diff options
Diffstat (limited to 'miasm2')
| -rw-r--r-- | miasm2/analysis/machine.py | 16 | ||||
| -rw-r--r-- | miasm2/arch/mep/__init__.py | 0 | ||||
| -rw-r--r-- | miasm2/arch/mep/arch.py | 2049 | ||||
| -rw-r--r-- | miasm2/arch/mep/disasm.py | 23 | ||||
| -rw-r--r-- | miasm2/arch/mep/ira.py | 45 | ||||
| -rw-r--r-- | miasm2/arch/mep/jit.py | 115 | ||||
| -rw-r--r-- | miasm2/arch/mep/regs.py | 90 | ||||
| -rw-r--r-- | miasm2/arch/mep/sem.py | 1172 | ||||
| -rw-r--r-- | miasm2/jitter/arch/JitCore_mep.c | 618 | ||||
| -rw-r--r-- | miasm2/jitter/arch/JitCore_mep.h | 77 | ||||
| -rw-r--r-- | miasm2/jitter/codegen.py | 3 | ||||
| -rw-r--r-- | miasm2/jitter/jitload.py | 2 |
12 files changed, 4208 insertions, 2 deletions
diff --git a/miasm2/analysis/machine.py b/miasm2/analysis/machine.py index 73b90aef..03d19503 100644 --- a/miasm2/analysis/machine.py +++ b/miasm2/analysis/machine.py @@ -12,7 +12,7 @@ class Machine(object): __available = ["arml", "armb", "armtl", "armtb", "sh4", "x86_16", "x86_32", "x86_64", "msp430", "mips32b", "mips32l", - "aarch64l", "aarch64b", "ppc32b"] + "aarch64l", "aarch64b", "ppc32b", "mepl", "mepb"] def __init__(self, machine_name): @@ -178,6 +178,20 @@ class Machine(object): mn = arch.mn_ppc from miasm2.arch.ppc.ira import ir_a_ppc32b as ira from miasm2.arch.ppc.sem import ir_ppc32b as ir + elif machine_name == "mepb": + from miasm2.arch.mep.disasm import dis_mepb as dis_engine + from miasm2.arch.mep import arch, jit + mn = arch.mn_mep + jitter = jit.jitter_mepb + from miasm2.arch.mep.ira import ir_a_mepb as ira + from miasm2.arch.mep.sem import ir_mepb as ir + elif machine_name == "mepl": + from miasm2.arch.mep.disasm import dis_mepl as dis_engine + from miasm2.arch.mep import arch, jit + mn = arch.mn_mep + jitter = jit.jitter_mepl + from miasm2.arch.mep.ira import ir_a_mepl as ira + from miasm2.arch.mep.sem import ir_mepl as ir else: raise ValueError('Unknown machine: %s' % machine_name) diff --git a/miasm2/arch/mep/__init__.py b/miasm2/arch/mep/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/miasm2/arch/mep/__init__.py diff --git a/miasm2/arch/mep/arch.py b/miasm2/arch/mep/arch.py new file mode 100644 index 00000000..3f844c06 --- /dev/null +++ b/miasm2/arch/mep/arch.py @@ -0,0 +1,2049 @@ +# Toshiba MeP-c4 - miasm architecture definition +# Guillaume Valadon <guillaume@valadon.net> + +from miasm2.core.cpu import * +from miasm2.core.utils import Disasm_Exception +from miasm2.expression.expression import * +from miasm2.core.asm_ast import AstId, AstMem + +from miasm2.arch.mep.regs import * +import miasm2.arch.mep.regs as mep_regs_module # will be used to set mn_mep.regs + + +# Note: pyparsing is used to alter the way special operands are parsed +from pyparsing import Literal, Group, Word, hexnums + + +# These definitions will help parsing dereferencing instructions (i.e. that uses +# parenthesis) with pyparsing +LPARENTHESIS = Literal("(") +RPARENTHESIS = Literal(")") +PLUSSIGN = Literal("+") +HEX_INTEGER = str_int_pos | str_int_neg + + +def ExprInt2SignedString(expr, pos_fmt="%d", neg_fmt="%d", size=None, offset=0): + """Return the signed string corresponding to an ExprInt + + Note: this function is only useful to mimic objdump output""" + + # Apply a mask to the integer + if size is None: + mask_length = expr.size + else: + mask_length = size + mask = (1 << mask_length) - 1 + value = int(expr.arg) & mask + + # Return a signed integer if necessary + if (value >> mask_length - 1) == 1: + value = offset - ((value ^ mask) + 1) + if value < 0: + return "-" + neg_fmt % -value + else: + value += offset + + return pos_fmt % value + + +class instruction_mep(instruction): + """Generic MeP-c4 instruction + + Notes: + - this object is used to build internal miasm instructions based + on mnemonics + - it must be implemented ! + """ + + # Default delay slot + # Note: + # - mandatory for the miasm2 Machine + delayslot = 0 + + @staticmethod + def arg2str(expr, pos=None, loc_db=None): + """Convert mnemonics arguments into readable strings according to the + MeP-c4 architecture manual and their internal types + + Notes: + - it must be implemented ! However, a simple 'return str(expr)' + could do the trick. + - it is used to mimic objdump output + + Args: + expr: argument as a miasm2 expression + pos: position index in the arguments list + """ + + if isinstance(expr, ExprId) or isinstance(expr, ExprInt): + return str(expr) + + elif isinstance(expr, ExprLoc): + if loc_db is not None: + return loc_db.pretty_str(expr.loc_key) + else: + return str(expr) + + elif isinstance(expr, ExprMem) and (isinstance(expr.arg, ExprId) or isinstance(expr.arg, ExprInt)): + return "(%s)" % expr.arg + + elif isinstance(expr, ExprMem) and isinstance(expr.arg, ExprOp): + return "0x%X(%s)" % (expr.arg.args[1].arg, expr.arg.args[0]) + + # Raise an exception if the expression type was not processed + message = "instruction_mep.arg2str(): don't know what \ + to do with a '%s' instance." % type(expr) + raise Disasm_Exception(message) + + def __str__(self): + """Return the mnemonic as a string. + + Note: + - it is not mandatory as the instruction class already implement + it. It used to get rid of the padding between the opcode and the + arguments. + - most of this code is copied from miasm2/core/cpu.py + """ + + o = "%s" % self.name + + if self.name == "SSARB": + # The first operand is displayed in decimal, not in hex + o += " %d" % self.args[0].arg + o += self.arg2str(self.args[1]) + + elif self.name in ["MOV", "ADD"] and isinstance(self.args[1], ExprInt): + # The second operand is displayed in decimal, not in hex + o += " " + self.arg2str(self.args[0]) + o += ", %s" % ExprInt2SignedString(self.args[1].arg) + + elif "CPI" in self.name: + # The second operand ends with the '+' sign + o += " " + self.arg2str(self.args[0]) + deref_reg_str = self.arg2str(self.args[1]) + o += ", %s+)" % deref_reg_str[:-1] # GV: looks ugly + + elif self.name[0] in ["S", "L"] and self.name[-3:] in ["CPA", "PM0", "PM1"]: + # The second operand ends with the '+' sign + o += " " + self.arg2str(self.args[0]) + deref_reg_str = self.arg2str(self.args[1]) + o += ", %s+)" % deref_reg_str[:-1] # GV: looks ugly + # The third operand is displayed in decimal, not in hex + o += ", %s" % ExprInt2SignedString(self.args[2].arg) + + elif len(self.args) == 2 and self.name in ["SB", "SH", "LBU", "LB", "LH", "LW"] and \ + isinstance(self.args[1], ExprMem) and isinstance(self.args[1].arg, ExprOp): # Major Opcodes #12 + # The second operand is an offset to a register + o += " " + self.arg2str(self.args[0]) + o += ", %s" % ExprInt2SignedString(self.args[1].arg.args[1], "0x%X") + o += "(%s)" % self.arg2str(self.args[1].arg.args[0]) + + elif len(self.args) == 2 and self.name in ["SWCP", "LWCP", "SMCP", "LMCP"] \ + and isinstance(self.args[1], ExprMem) and isinstance(self.args[1].arg, ExprOp): # Major Opcodes #12 + # The second operand is an offset to a register + o += " " + self.arg2str(self.args[0]) + o += ", %s" % ExprInt2SignedString(self.args[1].arg.args[1]) + o += "(%s)" % self.arg2str(self.args[1].arg.args[0]) + + elif self.name == "SLL" and isinstance(self.args[1], ExprInt): # Major Opcodes #6 + # The second operand is displayed in hex, not in decimal + o += " " + self.arg2str(self.args[0]) + o += ", 0x%X" % self.args[1].arg + + elif self.name in ["ADD3", "SLT3"] and isinstance(self.args[2], ExprInt): + o += " %s" % self.arg2str(self.args[0]) + o += ", %s" % self.arg2str(self.args[1]) + # The third operand is displayed in decimal, not in hex + o += ", %s" % ExprInt2SignedString(self.args[2].arg, pos_fmt="0x%X") + + elif self.name == "(RI)": + return o + + else: + args = [] + if self.args: + o += " " + for i, arg in enumerate(self.args): + if not isinstance(arg, Expr): + raise ValueError('zarb arg type') + x = self.arg2str(arg, pos=i) + args.append(x) + o += self.gen_args(args) + + return o + + def breakflow(self): + """Instructions that stop a basic bloc.""" + + if self.name in ["BRA", "BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]: + return True + + if self.name in ["JMP", "JSR", "RET"]: + return True + + if self.name in ["RETI", "HALT", "SLEEP"]: + return True + + return False + + def splitflow(self): + """Instructions that splits a basic bloc, i.e. the CPU can go somewhere else.""" + + if self.name in ["BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]: + return True + + return False + + def dstflow(self): + """Instructions that explicitly provide the destination.""" + + if self.name in ["BRA", "BEQZ", "BNEZ", "BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE", "BSR"]: + return True + + if self.name in ["JMP"]: + return True + + return False + + def dstflow2label(self, loc_db): + """Set the label for the current destination. + + Note: it is used at disassembly""" + + if self.name == "JMP" and isinstance(self.args[0], ExprId): + # 'JMP RM' does not provide the destination + return + + # Compute the correct address + num = self.get_dst_num() + addr = self.args[num].arg + if not self.name == "JMP": + addr += self.offset + + # Get a new label at the address + label = loc_db.get_or_create_offset_location(addr) + + # Assign the label to the correct instruction argument + self.args[num] = ExprLoc(label, self.args[num].size) + + def get_dst_num(self): + """Get the index of the argument that points to the instruction destination.""" + + if self.name[-1] == "Z": + num = 1 + elif self.name in ["BEQI", "BNEI", "BLTI", "BGEI", "BEQ", "BNE"]: + num = 2 + else: + num = 0 + + return num + + def getdstflow(self, loc_db): + """Get the argument that points to the instruction destination.""" + + num = self.get_dst_num() + return [self.args[num]] + + def is_subcall(self): + """Instructions used to call sub functions.""" + + return self.name in ["JSR", "BSR"] + + def fixDstOffset(self): + """Fix/correct the instruction immediate according to the current offset + + Note: - it is used at assembly + - code inspired by miasm2/arch/mips32/arch.py""" + + if self.name == "JMP" and isinstance(self.args[0], ExprInt): + # 'JMP IMMEDIATE' does not need to be fixed + return + + # Get the argument that needs to be fixed + if not len(self.args): + return + num = self.get_dst_num() + expr = self.args[num] + + # Check that the argument can be fixed + if self.offset is None: + raise ValueError("Symbol not resolved %s" % self.l) + if not isinstance(expr, ExprInt): + return + + # Adjust the immediate according to the current instruction offset + off = expr.arg - self.offset + if int(off % 2): + raise ValueError("Strange offset! %r" % off) + self.args[num] = ExprInt(off, 32) + + +class mep_additional_info: + """Additional MeP instructions information + """ + + def __init__(self): + self.except_on_instr = False + + +class mn_mep(cls_mn): + """Toshiba MeP-c4 disassembler & assembler + """ + + # Define variables that stores information used to disassemble & assemble + # Notes: - theses variables are mandatory + # - they could be moved to the cls_mn class + + num = 0 # holds the number of mnemonics + + all_mn = list() # list of mnenomnics, converted to metamn objects + + all_mn_mode = defaultdict(list) # mneomnics, converted to metamn objects + # Note: + # - the key is the mode # GV: what is it ? + # - the data is a list of mnemonics + + all_mn_name = defaultdict(list) # mnenomnics strings + # Note: + # - the key is the mnemonic string + # - the data is the corresponding + # metamn object + + all_mn_inst = defaultdict(list) # mnemonics objects + # Note: + # - the key is the mnemonic Python class + # - the data is an instanciated object + + bintree = dict() # Variable storing internal values used to guess a + # mnemonic during disassembly + + # Defines the instruction set that will be used + instruction = instruction_mep + + # Python module that stores registers informations + regs = mep_regs_module + + # Default delay slot + # Note: + # - mandatory for the miasm2 Machine + delayslot = 0 + + # Architecture name + name = "mep" + + # PC name depending on architecture attributes (here, l or b) + pc = {'l': PC, 'b': PC} + + def additional_info(self): + """Define instruction side effects # GV: not fully understood yet + + When used, it must return an object that implements specific + variables, such as except_on_instr. + + Notes: + - it must be implemented ! + - it could be moved to the cls_mn class + """ + + return mep_additional_info() + + @classmethod + def gen_modes(cls, subcls, name, bases, dct, fields): + """Ease populating internal variables used to disassemble & assemble, such + as self.all_mn_mode, self.all_mn_name and self.all_mn_inst + + Notes: + - it must be implemented ! + - it could be moved to the cls_mn class. All miasm architectures + use the same code + + Args: + cls: ? + sublcs: + name: mnemonic name + bases: ? + dct: ? + fields: ? + + Returns: + a list of ? + + """ + + dct["mode"] = None + return [(subcls, name, bases, dct, fields)] + + @classmethod + def getmn(cls, name): + """Get the mnemonic name + + Notes: + - it must be implemented ! + - it could be moved to the cls_mn class. Most miasm architectures + use the same code + + Args: + cls: the mnemonic class + name: the mnemonic string + """ + + return name.upper() + + @classmethod + def getpc(cls, attrib=None): + """"Return the ExprId that represents the Program Counter. + + Notes: + - mandatory for the symbolic execution + - PC is defined in regs.py + + Args: + attrib: architecture dependent attributes (here, l or b) + """ + + return PC + + @classmethod + def getsp(cls, attrib=None): + """"Return the ExprId that represents the Stack Pointer. + + Notes: + - mandatory for the symbolic execution + - SP is defined in regs.py + + Args: + attrib: architecture dependent attributes (here, l or b) + """ + + return SP + + @classmethod + def getbits(cls, bitstream, attrib, start, n): + """Return an integer of n bits at the 'start' offset + + Note: code from miasm2/arch/mips32/arch.py + """ + + # Return zero if zero bits are requested + if not n: + return 0 + + o = 0 # the returned value + while n: + # Get a byte, the offset is adjusted according to the endianness + offset = start / 8 # the offset in bytes + n_offset = cls.endian_offset(attrib, offset) # the adjusted offset + c = cls.getbytes(bitstream, n_offset, 1) + if not c: + raise IOError + + # Extract the bits value + c = ord(c) + r = 8 - start % 8 + c &= (1 << r) - 1 + l = min(r, n) + c >>= (r - l) + o <<= l + o |= c + n -= l + start += l + + return o + + @classmethod + def endian_offset(cls, attrib, offset): + """Adjust the byte offset according to the endianness""" + + if attrib == "l": # Little Endian + if offset % 2: + return offset - 1 + else: + return offset + 1 + + elif attrib == "b": # Big Endian + return offset + + else: + raise NotImplementedError("Bad MeP endianness") + + def value(self, mode): + """Adjust the assembled instruction based on the endianness + + Note: code inspired by miasm2/arch/mips32/arch.py + """ + + # Get the candidated + candidates = super(mn_mep, self).value(mode) + + if mode == "l": + # Invert bytes per 16-bits + for i in range(len(candidates)): + tmp = candidates[i][1] + candidates[i][0] + if len(candidates[i]) == 4: + tmp += candidates[i][3] + candidates[i][2] + candidates[i] = tmp + return candidates + + elif mode == "b": + return candidates + + else: + raise NotImplementedError("Bad MeP endianness (%s)" % mode) + + +def addop(name, fields, args=None, alias=False): + """Dynamically create the "name" object + + Notes: + - it could be moved to a generic function such as: + addop(name, fields, cls_mn, args=None, alias=False). + - most architectures use the same code + + Args: + name: the mnemonic name + fields: used to fill the object.__dict__'fields' attribute # GV: not understood yet + args: used to fill the object.__dict__'fields' attribute # GV: not understood yet + alias: used to fill the object.__dict__'fields' attribute # GV: not understood yet + """ + + namespace = {"fields": fields, "alias": alias} + + if args is not None: + namespace["args"] = args + + # Dynamically create the "name" object + type(name, (mn_mep,), namespace) + + +# Define specific operand parsers & converters + +def deref2expr(s, l, parse_results): + """Convert a parsed dereferenced register to an ExprMem""" + + # Only use the first results + parse_results = parse_results[0] + + if type(parse_results[0]) == AstInt and isinstance(parse_results[2], AstId): + return AstMem(parse_results[2] + parse_results[0], 32) # 1 == "(" and 3 == ")" + + elif type(parse_results[0]) == int and isinstance(parse_results[2], AstId): + return AstMem(parse_results[2] + AstOp('-', AstInt(-parse_results[0])), 32) # 1 == "(" and 3 == ")" + + else: + return AstMem(parse_results[1], 32) # 0 == "(" and 2 == ")" + + +deref_reg_parser = Group(LPARENTHESIS + gpr_infos.parser + RPARENTHESIS).setParseAction(deref2expr) +deref_inc_reg_parser = Group(LPARENTHESIS + gpr_infos.parser + PLUSSIGN + RPARENTHESIS).setParseAction(deref2expr) +abs24_deref_parser = Group(LPARENTHESIS + HEX_INTEGER + RPARENTHESIS).setParseAction(deref2expr) +offset_deref_reg_parser = Group(HEX_INTEGER + LPARENTHESIS + gpr_infos.parser + RPARENTHESIS).setParseAction(deref2expr) + +# Define registers decoders and encoders + +class mep_arg(m_arg): + def asm_ast_to_expr(self, arg, loc_db): + """Convert AST to expressions + + Note: - code inspired by miasm2/arch/mips32/arch.py""" + + if isinstance(arg, AstId): + if isinstance(arg.name, ExprId): + return arg.name + if isinstance(arg.name, str) and arg.name in gpr_names: + return None # GV: why? + loc_key = loc_db.get_or_create_name_location(arg.name) + return ExprLoc(loc_key, 32) + + elif isinstance(arg, AstMem): + addr = self.asm_ast_to_expr(arg.ptr, loc_db) + if addr is None: + return None + return ExprMem(addr, 32) + + elif isinstance(arg, AstInt): + return ExprInt(arg.value, 32) + + elif isinstance(arg, AstOp): + args = [self.asm_ast_to_expr(tmp, loc_db) for tmp in arg.args] + if None in args: + return None + return ExprOp(arg.op, *args) + + # Raise an exception if the argument was not processed + message = "mep_arg.asm_ast_to_expr(): don't know what \ + to do with a '%s' instance." % type(arg) + raise Exception(message) + +class mep_reg(reg_noarg, mep_arg): + """Generic Toshiba MeP-c4 register + + Note: + - the register size will be set using bs() + """ + reg_info = gpr_infos # the list of MeP-c4 registers defined in regs.py + parser = reg_info.parser # GV: not understood yet + + +class mep_deref_reg(mep_arg): + """Generic Toshiba MeP-c4 dereferenced register + + Note: + - the arg2str() method could be defined to change the output string + """ + parser = deref_reg_parser + + def decode(self, v): + """Transform the decoded value to a ExprMem(ExprId()) expression""" + r = gpr_infos.expr[v] # get the ExprId, i.e. the register expression + self.expr = ExprMem(r, 32) + return True + + def encode(self): + """Ensure that we have a ExprMem(ExprId()) expression, and return the + register value.""" + + if not isinstance(self.expr, ExprMem): + return False + if not isinstance(self.expr.arg, ExprId): + return False + + # Get the ExprId index, i.e. its value + self.value = gpr_exprs.index(self.expr.arg) + return True + + +class mep_reg_sp(mep_reg): + """Dummy Toshiba MeP-c4 register that represents SP. It is used in + instructions that implicitly use SP, such as ADD3. + """ + implicit_reg = SP + + def decode(self, v): + """Always return 'implicit_reg.""" + self.expr = self.implicit_reg + return True + + def encode(self): + """Do nothing""" + return True + + +class mep_reg_tp(mep_reg_sp): + """Dummy Toshiba MeP-c4 register that represents TP. + """ + implicit_reg = TP + + +class mep_deref_reg_offset(mep_arg): + """Toshiba MeP-c4 dereferenced register that represents SP, plus an + offset. + """ + parser = offset_deref_reg_parser + + def decode(self, v): + """Modify the decoded value using the previously decoded + register id. + """ + + # Apply the immediate mask + se = sign_ext(v & 0xFFFF, 16, 32) # GV: might not belong here + int_id = ExprInt(se, 32) + + # Get the register expression + reg_id = gpr_infos.expr[self.parent.reg04_deref.value] + + # Build the internal expression + self.expr = ExprMem(reg_id + int_id, 32) + + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in reg04_deref. + """ + + # Verify the expression + if not isinstance(self.expr, ExprMem): + return False + if not isinstance(self.expr.arg, ExprOp): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg.args[1].arg & 0xFFFF) + + # Encode the values + self.parent.reg04_deref.value = gpr_exprs.index(self.expr.arg.args[0]) + self.value = v & 0xFFFF + return True + + +class mep_deref_sp_offset(mep_deref_reg): + """Dummy Toshiba MeP-c4 dereferenced register that represents SP, plus an + offset. + Note: it is as generic as possible to ease its use in different instructions + """ + implicit_reg = SP + parser = offset_deref_reg_parser + + def decode(self, v): + """Modify the decoded value using the previously decoded + immediate. + """ + + immediate = None + if getattr(self.parent, "imm7_align4", False): + # Apply the immediate mask + v = self.parent.imm7_align4.value & 0x1F + + # Shift value such as: + # imm7=iii_ii||00 + immediate = v << 2 + + elif getattr(self.parent, "imm7", False): + # Apply the immediate mask + immediate = self.parent.imm7.value & 0x7F + + elif getattr(self.parent, "disp7_align2", False): + # Apply the immediate mask + disp7_align2 = self.parent.disp7_align2.value & 0x3F + + # Shift value such as: + # disp7 = ddd_ddd||0 + immediate = disp7_align2 << 1 + + if immediate is not None: + self.expr = ExprMem(self.implicit_reg + ExprInt(immediate, 32), 32) + return True + else: + return False + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in a parent immediate. + """ + + # Verify the expression + if not isinstance(self.expr, ExprMem): + return False + if not isinstance(self.expr.arg, ExprOp): + return False + if self.expr.arg.args[0] != self.implicit_reg: + return False + + if getattr(self.parent, "imm7_align4", False): + + # Get the integer and check the upper bound + v = int(self.expr.arg.args[1].arg) + if v > 0x80: + return False + + # Encode the value + self.parent.imm7_align4.value = v >> 2 + + return True + + elif getattr(self.parent, "imm7", False): + + # Get the integer and check the upper bound + v = int(self.expr.arg.args[1].arg) + if v > 0x80: + return False + + # Encode the value + self.parent.imm7.value = v + + return True + + elif getattr(self.parent, "disp7_align2", False): + + # Get the integer and check the upper bound + v = int(self.expr.arg.args[1].arg) + if v > 0x80: + return False + + # Encode the value + self.parent.disp7_align2.value = v >> 1 + + return True + + return False + + +class mep_deref_tp_offset(mep_deref_sp_offset): + """Dummy Toshiba MeP-c4 dereferenced register that represents TP, plus an + offset. + """ + implicit_reg = TP + + +class mep_copro_reg(reg_noarg, mep_arg): + """Generic Toshiba MeP-c4 coprocessor register + """ + reg_info = copro_gpr_infos # the list of MeP-c4 coprocessor registers defined in regs.py + parser = reg_info.parser # GV: not understood yet + + +class mep_copro_reg_split(mep_copro_reg): + """Generic Toshiba MeP-c4 coprocessor register encode into different fields + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm4_noarg. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # CRn=NNnnnn + crn = (v << 4) + (self.parent.imm4.value & 0xF) + + # Build the internal expression + self.expr = ExprId("C%d" % crn, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm4_noarg. + """ + + if not isinstance(self.expr, ExprId): + return False + + # Get the register and check the upper bound + reg_name = self.expr.name + if reg_name[0] != "C": + return False + reg_value = copro_gpr_names.index(reg_name) + if reg_value > 0x3f: + return False + + # Encode the value into two parts + self.parent.imm4.value = (reg_value & 0xF) + self.value = (reg_value >> 4) & 0x3 + return True + + +class mep_deref_inc_reg(mep_deref_reg): + """Generic Toshiba MeP-c4 coprocess dereferenced & incremented registe + """ + parser = deref_inc_reg_parser + + +# Immediate decoders and encoders + +class mep_int32_noarg(int32_noarg): + """Generic Toshiba MeP-c4 signed immediate + + Note: encode() is copied from int32_noarg.encode() and modified to allow + small (< 32 bits) signed immediate to be manipulated. + + """ + + def encode(self): + if not isinstance(self.expr, ExprInt): + return False + v = int(self.expr.arg) + # Note: the following lines were commented on purpose + #if sign_ext(v & self.lmask, self.l, self.intsize) != v: + # return False + v = self.encodeval(v & self.lmask) + self.value = v & self.lmask + return True + + +class mep_imm(imm_noarg, mep_arg): + """Generic Toshiba MeP-c4 immediate + + Note: + - the immediate size will be set using bs() + """ + parser = base_expr + + +class mep_imm6(mep_int32_noarg): + """Toshiba MeP-c4 signed 6 bits immediate.""" + parser = base_expr + intsize = 6 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32) + + +class mep_imm8(mep_int32_noarg): + """Toshiba MeP-c4 signed 8 bits immediate.""" + parser = base_expr + intsize = 8 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32) + + +class mep_imm16(mep_int32_noarg): + """Toshiba MeP-c4 16 bits immediate.""" + parser = base_expr + intsize = 16 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(x, 32) + + +class mep_imm16_signed(mep_int32_noarg): + """Toshiba MeP-c4 signed 16 bits immediate.""" + parser = base_expr + intsize = 16 + intmask = (1 << intsize) - 1 + int2expr = lambda self, x: ExprInt(sign_ext(x, self.l, 32), 32) + + +class mep_target24(mep_imm): + """Toshiba MeP-c4 target24 immediate, as used in JMP + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm7. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # target24=tttt_tttt_tttt_tttt||TTT_TTTT||0 + target24 = (v << 8) + ((self.parent.imm7.value & 0x7F) << 1) + + # Build the internal expression + self.expr = ExprInt(target24, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm7. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and apply a mask + v = int(self.expr.arg) & 0x00FFFFFF + + # Encode the value into two parts + self.parent.imm7.value = (v & 0xFF) >> 1 + self.value = v >> 8 + return True + + +class mep_target24_signed(mep_target24): + """Toshiba MeP-c4 target24 signed immediate, as used in BSR + """ + + def decode(self, v): + """Perform sign extension + """ + + mep_target24.decode(self, v) + v = int(self.expr.arg) + self.expr = ExprInt(v, 24).signExtend(32) + return True + + +class mep_code20(mep_imm): + """Toshiba MeP-c4 code20 immediate, as used in DSP1 + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm4_noarg. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # code20=mmmm_cccc_cccc_cccc_cccc + code20 = v + ((self.parent.imm4.value & 0xFF) << 16) + + # Build the internal expression + self.expr = ExprInt(code20, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm4_noarg. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg) + if v > 0xffffff: + return False + + # Encode the value into two parts + self.parent.imm4 = ((v >> 16) & 0xFF) + self.value = v + return True + + +class mep_code24(mep_imm): + """Toshiba MeP-c4 code24 immediate, as used in CP + """ + + def decode(self, v): + """Modify the decoded value using the previously decoded imm8_CCCC_CCCC. + """ + + # Shift values such as: + # code24=CCCC_CCCC||cccc_cccc_cccc_cccc + code24 = v + ((self.parent.imm8_CCCC_CCCC.value & 0xFF) << 16) + + # Build the internal expression + self.expr = ExprInt(code24, 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm8_CCCC_CCCC. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg) + if v > 0xFFFFFF: + return False + + # Encode the value into two parts + self.parent.imm8_CCCC_CCCC.value = ((v >> 16) & 0xFF) + self.value = v & 0xFFFF + return True + + +class mep_imm7_align4(mep_imm): + """Toshiba MeP-c4 imm7.align4 immediate, as used in Major #4 opcodes + """ + + def decode(self, v): + """Modify the decoded value. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift value such as: + # imm7=iii_ii||00 + imm7_align4 = v << 2 + + # Build the internal expression + self.expr = ExprInt(imm7_align4, 32) + return True + + def encode(self): + """Modify the encoded value. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg) + if v > 0x80: + return False + + # Encode the value + self.value = v >> 2 + return True + + +class mep_imm5_Iiiii (mep_imm): + """Toshiba MeP-c4 imm5 immediate, as used in STC & LDC. It encodes a + control/special register. + """ + + reg_info = csr_infos # the list of MeP-c4 control/special registers defined in regs.py + parser = reg_info.parser # GV: not understood yet + + def decode(self, v): + """Modify the decoded value using the previously decoded imm4_iiii + """ + + # Apply the immediate mask + I = v & self.lmask + + # Shift values such as: + # imm5=I||iiii + imm5 = (I << 4) + (self.parent.imm4_iiii.value & 0xF) + + # Build the internal register expression + self.expr = ExprId(csr_names[imm5], 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm4_iiii. + """ + + if not isinstance(self.expr, ExprId): + return False + + # Get the register number and check the upper bound + v = csr_names.index(self.expr.name) + if v > 0x1F: + return False + + # Encode the value into two parts + self.parent.imm4_iiii.value = v & 0xF # iiii + self.value = (v >> 4) & 0b1 # I + return True + + +class mep_disp7_align2(mep_imm): + """Toshiba MeP-c4 disp7.align2 immediate, as used in Major #8 opcodes + """ + upper_bound = 0x7F + bits_shift = 1 + + def decode(self, v): + """Modify the decoded value. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift value such as: + # disp7 = ddd_ddd||0 + disp7_align2 = (v << self.bits_shift) + + # Sign extension + disp7_align2 = sign_ext(disp7_align2, self.l + self.bits_shift, 32) + + # Build the internal expression + self.expr = ExprInt(disp7_align2, 32) + return True + + def encode(self): + """Modify the encoded value. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer + v = int(self.expr.arg) & self.upper_bound + + # Encode the value + self.value = (v >> self.bits_shift) & self.upper_bound + self.value = (v & self.upper_bound) >> self.bits_shift + return True + + +class mep_disp8_align2(mep_disp7_align2): + upper_bound = 0xFF + + +class mep_disp8_align4(mep_disp7_align2): + upper_bound = 0xFF + bits_shift = 2 + + +class mep_imm8_align8(mep_disp7_align2): + upper_bound = 0xFF + bits_shift = 3 + + +class mep_disp12_align2(mep_disp7_align2): + upper_bound = 0xFFF + + +class mep_disp12_align2_signed(mep_disp12_align2): + + def decode(self, v): + """Perform sign extension. + """ + mep_disp12_align2.decode(self, v) + v = int(self.expr.arg) + + self.expr = ExprInt(v, 12).signExtend(32) + return True + + +class mep_disp17(mep_disp7_align2): + upper_bound = 0x1FFFF + + +class mep_imm24(mep_imm): + """Toshiba MeP-c4 imm24 immediate, as used in MOVU + """ + + def decode(self, v): + """Modify the decoded value. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # imm24=iiii_iiii_iiii_iiii||IIII_IIIII + imm24 = ((v & 0xFFFF) << 8) + ((v & 0xFF0000) >> 16) + + # Build the internal expression + self.expr = ExprInt(imm24, 32) + return True + + def encode(self): + """Modify the encoded value. + """ + + if not isinstance(self.expr, ExprInt): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg) + if v > 0xFFFFFF: + return False + + # Encode the value + self.value = ((v & 0xFFFF00) >> 8) + ((v & 0xFF) << 16) + return True + + +class mep_abs24(mep_imm): + """Toshiba MeP-c4 abs24 immediate + """ + parser = abs24_deref_parser + + def decode(self, v): + """Modify the decoded value using the previously decoded imm6. + """ + + # Apply the immediate mask + v = v & self.lmask + + # Shift values such as: + # abs24=dddd_dddd_dddd_dddd||DDDD_DD||00 + abs24 = (v << 8) + ((self.parent.imm6.value & 0x3F) << 2) + + # Build the internal expression + self.expr = ExprMem(ExprInt(abs24, 32), 32) + return True + + def encode(self): + """Modify the encoded value. One part is stored in this object, and + the other one in imm6. + """ + + if not (isinstance(self.expr, ExprMem) and isinstance(self.expr.arg, ExprInt)): + return False + + # Get the integer and check the upper bound + v = int(self.expr.arg.arg) + if v > 0xffffff: + return False + + # Encode the value into two parts + self.parent.imm6.value = (v & 0xFF) >> 2 + self.value = v >> 8 + return True + + +# Define MeP-c4 assembly operands + +reg04 = bs(l=4, # length in bits + cls=(mep_reg, )) # class implementing decoding & encoding + +reg04_l = bs(l=4, cls=(mep_reg, )) + +reg04_m = bs(l=4, cls=(mep_reg, )) + +reg04_n = bs(l=4, cls=(mep_reg, )) + +reg00 = bs(l=0, cls=(mep_reg, )) + +reg00_sp = bs(l=0, cls=(mep_reg_sp, )) + +reg00_tp = bs(l=0, cls=(mep_reg_tp, )) + +reg00_deref_sp = bs(l=0, cls=(mep_deref_sp_offset, )) + +reg00_deref_tp = bs(l=0, cls=(mep_deref_tp_offset, )) + +reg03 = bs(l=3, cls=(mep_reg, )) + +reg04_deref = bs(l=4, cls=(mep_deref_reg,)) + +reg04_deref_noarg = bs(l=4, fname="reg04_deref") + +reg04_inc_deref = bs(l=4, cls=(mep_deref_inc_reg,)) + +copro_reg04 = bs(l=4, cls=(mep_copro_reg,)) + +copro_reg05 = bs(l=1, cls=(mep_copro_reg_split,)) + +copro_reg06 = bs(l=2, cls=(mep_copro_reg_split,)) + +disp2 = bs(l=2, cls=(mep_imm, )) + +imm2 = disp2 + +imm3 = bs(l=3, cls=(mep_imm, )) + +imm4 = bs(l=4, cls=(mep_imm, )) + +imm4_noarg = bs(l=4, fname="imm4") + +imm4_iiii_noarg = bs(l=4, fname="imm4_iiii") + +imm5 = bs(l=5, cls=(mep_imm, )) + +imm5_Iiiii = bs(l=1, cls=(mep_imm5_Iiiii, )) # it is not an immediate, but a + # control/special register. + +imm6 = bs(l=6, cls=(mep_imm6, mep_arg)) + +imm6_noarg = bs(l=6, fname="imm6") + +imm7 = bs(l=7, cls=(mep_imm, )) + +imm7_noarg = bs(l=7, fname="imm7") # Note: + # - will be decoded as a 7 bits immediate + # - fname is used to set the operand name + # used in mep_target24 to merge operands + # values. By default, the bs class fills + # fname with an hex string compute from + # arguments passed to __init__ + +imm7_align4 = bs(l=5, cls=(mep_imm7_align4,)) + +imm7_align4_noarg = bs(l=5, fname="imm7_align4") + +disp7_align2 = bs(l=6, cls=(mep_disp7_align2,)) + +disp7_align2_noarg = bs(l=6, fname="disp7_align2") + +imm8 = bs(l=8, cls=(mep_imm8, mep_arg)) + +imm8_noarg = bs(l=8, fname="imm8_CCCC_CCCC") + +disp8 = bs(l=7, cls=(mep_disp8_align2, )) + +imm8_align2 = bs(l=7, cls=(mep_disp8_align2, )) + +imm8_align4 = bs(l=6, cls=(mep_disp8_align4, )) + +imm8_align8 = bs(l=5, cls=(mep_imm8_align8, )) + +imm12 = bs(l=12, cls=(mep_imm, )) + +disp12_signed = bs(l=11, cls=(mep_disp12_align2_signed, )) + +imm16 = bs(l=16, cls=(mep_imm16, mep_arg)) +imm16_signed = bs(l=16, cls=(mep_imm16_signed, mep_arg)) + +disp16_reg_deref = bs(l=16, cls=(mep_deref_reg_offset,)) + +disp17 = bs(l=16, cls=(mep_disp17, )) + +imm18 = bs(l=19, cls=(mep_imm, )) + +imm_code20 = bs(l=16, cls=(mep_code20, )) + +imm24 = bs(l=24, cls=(mep_imm24, )) + +imm_target24 = bs(l=16, cls=(mep_target24, )) +imm_target24_signed = bs(l=16, cls=(mep_target24_signed, )) + +imm_code24 = bs(l=16, cls=(mep_code24, )) + +abs24 = bs(l=16, cls=(mep_abs24, )) + + +# MeP-c4 mnemonics objects + +### <Major Opcode #0> + +# MOV Rn,Rm - 0000_nnnn_mmmm_0000 +addop("MOV", [bs("0000"), reg04, reg04, bs("0000")]) + +# NEG Rn,Rm - 0000_nnnn_mmmm_0001 +addop("NEG", [bs("0000"), reg04, reg04, bs("0001")]) + +# SLT3 R0,Rn,Rm - 0000_nnnn_mmmm_0010 +addop("SLT3", [bs("0000"), reg00, reg04, reg04, bs("0010")]) + +# SLTU3 R0,Rn,Rm - 0000_nnnn_mmmm_0011 +addop("SLTU3", [bs("0000"), reg00, reg04, reg04, bs("0011")]) + +# SUB Rn,Rm - 0000_nnnn_mmmm_0100 +addop("SUB", [bs("0000"), reg04, reg04, bs("0100")]) + +# SBVCK3 R0,Rn,Rm - 0000_nnnn_mmmm_0101 +addop("SBVCK3", [bs("0000"), reg00, reg04, reg04, bs("0101")]) + +# (RI) - 0000_xxxx_xxxx_0110 +addop("(RI)", [bs("0000"), reg04, reg04, bs("0110")]) + +# ADVCK3 R0,Rn,Rm - 0000_nnnn_mmmm_0111 +addop("ADVCK3", [bs("0000"), reg00, reg04, reg04, bs("0111")]) + +# SB Rn,(Rm) - 0000_nnnn_mmmm_1000 +addop("SB", [bs("0000"), reg04, reg04_deref, bs("1000")]) + +# SH Rn,(Rm) - 0000_nnnn_mmmm_1001 +addop("SH", [bs("0000"), reg04, reg04_deref, bs("1001")]) + +# SW Rn,(Rm) - 0000_nnnn_mmmm_1010 +addop("SW", [bs("0000"), reg04, reg04_deref, bs("1010")]) + +# LBU Rn,(Rm) - 0000_nnnn_mmmm_1011 +addop("LBU", [bs("0000"), reg04, reg04_deref, bs("1011")]) + +# LB Rn,(Rm) - 0000_nnnn_mmmm_1100 +addop("LB", [bs("0000"), reg04, reg04_deref, bs("1100")]) + +# LH Rn,(Rm) - 0000_nnnn_mmmm_1101 +addop("LH", [bs("0000"), reg04, reg04_deref, bs("1101")]) + +# LW Rn,(Rm) - 0000_nnnn_mmmm_1110 +addop("LW", [bs("0000"), reg04, reg04_deref, bs("1110")]) + +# LHU Rn,(Rm) - 0000_nnnn_mmmm_1111 +addop("LHU", [bs("0000"), reg04, reg04_deref, bs("1111")]) + + +### <Major Opcode #1> + +# OR Rn,Rm - 0001_nnnn_mmmm_0000 +addop("OR", [bs("0001"), reg04, reg04, bs("0000")]) + +# AND Rn,Rm - 0001_nnnn_mmmm_0001 +addop("AND", [bs("0001"), reg04, reg04, bs("0001")]) + +# XOR Rn,Rm - 0001_nnnn_mmmm_0010 +addop("XOR", [bs("0001"), reg04, reg04, bs("0010")]) + +# NOR Rn,Rm - 0001_nnnn_mmmm_0011 +addop("NOR", [bs("0001"), reg04, reg04, bs("0011")]) + +# MUL Rn,Rm - 0001_nnnn_mmmm_0100 +addop("MUL", [bs("0001"), reg04, reg04, bs("0100")]) + +# MULU Rn,Rm - 0001_nnnn_mmmm_0101 +addop("MULU", [bs("0001"), reg04, reg04, bs("0101")]) + +# MULR Rn,Rm - 0001_nnnn_mmmm_0110 +addop("MULR", [bs("0001"), reg04, reg04, bs("0110")]) + +# MULRU Rn,Rm - 0001_nnnn_mmmm_0111 +addop("MULRU", [bs("0001"), reg04, reg04, bs("0111")]) + +# DIV Rn,Rm - 0001_nnnn_mmmm_1000 +addop("DIV", [bs("0001"), reg04, reg04, bs("1000")]) + +# DIVU Rn,Rm - 0001_nnnn_mmmm_1001 +addop("DIVU", [bs("0001"), reg04, reg04, bs("1001")]) + +# (RI) - 0001_xxxx_xxxx_1010 +addop("(RI)", [bs("0001"), reg04, reg04, bs("1010")]) + +# (RI) - 0001_xxxx_xxxx_1011 +addop("(RI)", [bs("0001"), reg04, reg04, bs("1011")]) + +# SSARB disp2(Rm) - 0001_00dd_mmmm_1100 +addop("SSARB", [bs("000100"), disp2, reg04_deref, bs("1100")]) + +# EXTB Rn - 0001_nnnn_0000_1101 +addop("EXTB", [bs("0001"), reg04, bs("00001101")]) + +# EXTH Rn - 0001_nnnn_0010_1101 +addop("EXTH", [bs("0001"), reg04, bs("00101101")]) + +# EXTUB Rn - 0001_nnnn_1000_1101 +addop("EXTUB", [bs("0001"), reg04, bs("10001101")]) + +# EXTUH Rn - 0001_nnnn_1010_1101 +addop("EXTUH", [bs("0001"), reg04, bs("10101101")]) + +# JMP Rm - 0001_0000_mmmm_1110 +addop("JMP", [bs("00010000"), reg04, bs("1110")]) + +# JSR Rm - 0001_0000_mmmm_1111 +addop("JSR", [bs("00010000"), reg04, bs("1111")]) + +# JSRV Rm - 0001_1000_mmmm_1111 +addop("JSRV", [bs("00011000"), reg04, bs("1111")]) + + +### <Major Opcode #2> + +# BSETM (Rm),imm3 - 0010_0iii_mmmm_0000 +addop("BSETM", [bs("00100"), imm3, reg04_deref, bs("0000")], [reg04_deref, imm3]) + +# BCLRM (Rn),imm3 - 0010_0iii_mmmm_0001 +addop("BCLRM", [bs("00100"), imm3, reg04_deref, bs("0001")], [reg04_deref, imm3]) + +# BNOTM (Rm),imm3 - 0010_0iii_mmmm_0010 +addop("BNOTM", [bs("00100"), imm3, reg04_deref, bs("0010")], [reg04_deref, imm3]) + +# BTSTM R0,(Rm),imm3 - 0010_0iii_mmmm_0011 +addop("BTSTM", [bs("00100"), reg00, imm3, reg04_deref, bs("0011")], [reg00, reg04_deref, imm3]) + +# TAS Rn,(Rm) - 0010_nnnn_mmmm_0100 +addop("TAS", [bs("0010"), reg04, reg04_deref, bs("0100")]) + +# (RI) - 0010_xxxx_xxxx_0101 +addop("(RI)", [bs("0010"), reg04, reg04, bs("0101")]) + +# SL1AD3 R0,Rn,Rm - 0010_nnnn_mmmm_0110 +addop("SL1AD3", [bs("0010"), reg00, reg04, reg04, bs("0110")]) + +# SL2AD3 R0,Rn,Rm - 0010_nnnn_mmmm_0111 +addop("SL2AD3", [bs("0010"), reg00, reg04, reg04, bs("0111")]) + +# (RI) - 0010_xxxx_xxxx_1000 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1000")]) + +# (RI) - 0010_xxxx_xxxx_1001 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1001")]) + +# (RI) - 0010_xxxx_xxxx_1010 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1010")]) + +# (RI) - 0010_xxxx_xxxx_1011 +addop("(RI)", [bs("0010"), reg04, reg04, bs("1011")]) + +# SRL Rn,Rm - 0010_nnnn_mmmm_1100 +addop("SRL", [bs("0010"), reg04, reg04, bs("1100")]) + +# SRA Rn,Rm - 0010_nnnn_mmmm_1101 +addop("SRA", [bs("0010"), reg04, reg04, bs("1101")]) + +# SLL Rn,Rm - 0010_nnnn_mmmm_1110 +addop("SLL", [bs("0010"), reg04, reg04, bs("1110")]) + +# FSFT Rn,Rm - 0010_nnnn_mmmm_1111 +addop("FSFT", [bs("0010"), reg04, reg04, bs("1111")]) + + +### <Major Opcode #3> + +# SWCPI CRn,(Rm+) - 0011_nnnn_mmmm_0000 +addop("SWCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0000")]) + +# LWCPI CRn,(Rm+) - 0011_nnnn_mmmm_0001 +addop("LWCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0001")]) + +# SMCPI CRn,(Rm+) - 0011_nnnn_mmmm_0010 +addop("SMCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0010")]) + +# LMCPI CRn,(Rm+) - 0011_nnnn_mmmm_0011 +addop("LMCPI", [bs("0011"), copro_reg04, reg04_inc_deref, bs("0011")]) + +# SWCP CRn,(Rm) - 0011_nnnn_mmmm_1000 +addop("SWCP", [bs("0011"), copro_reg04, reg04_deref, bs("1000")]) + +# LWCP CRn,(Rm) - 0011_nnnn_mmmm_1001 +addop("LWCP", [bs("0011"), copro_reg04, reg04_deref, bs("1001")]) + +# SMCP CRn,(Rm) - 0011_nnnn_mmmm_1010 +addop("SMCP", [bs("0011"), copro_reg04, reg04_deref, bs("1010")]) + +# LMCP CRn,(Rm) - 0011_nnnn_mmmm_1011 +addop("LMCP", [bs("0011"), copro_reg04, reg04_deref, bs("1011")]) + + +### <Major Opcode #4> + +# ADD3 Rn,SP,imm7.align4 - 0100_nnnn_0iii_ii00 +addop("ADD3", [bs("0100"), reg04, reg00_sp, bs("0"), imm7_align4, bs("00")]) + +# SW Rn,disp7.align4(SP) - 0100_nnnn_0ddd_dd10 +# Note: disp7.align4 is the same as imm7.align4 +addop("SW", [bs("0100"), reg04, bs("0"), imm7_align4_noarg, reg00_deref_sp, bs("10")]) + +# LW Rn,disp7.align4(SP) - 0100_nnnn_0ddd_dd11 +addop("LW", [bs("0100"), reg04, bs("0"), imm7_align4_noarg, reg00_deref_sp, bs("11")]) + +# SW Rn[0-7],disp7.align4(TP) - 0100_0nnn_1ddd_dd10 +addop("SW", [bs("01000"), reg03, bs("1"), imm7_align4_noarg, reg00_deref_tp, bs("10")]) + +# LW Rn[0-7],disp7.align4(TP) - 0100_0nnn_1ddd_dd11 +addop("LW", [bs("01000"), reg03, bs("1"), imm7_align4_noarg, reg00_deref_tp, bs("11")]) + +# LBU Rn[0-7],disp7(TP) - 0100_1nnn_1ddd_dddd +addop("LBU", [bs("01001"), reg03, bs("1"), imm7_noarg, reg00_deref_tp], [reg03, reg00_deref_tp]) + +### <Major Opcode #5> + +# MOV Rn,imm8 - 0101_nnnn_iiii_iiii +addop("MOV", [bs("0101"), reg04, imm8]) + + +### <Major Opcode #6> + +# ADD Rn,imm6 - 0110_nnnn_iiii_ii00 +addop("ADD", # mnemonic name + [bs("0110"), reg04, imm6, bs("00")]) # mnemonic description + +# SLT3 R0,Rn,imm5 - 0110_nnnn_iiii_i001 +addop("SLT3", [bs("0110"), reg00, reg04, imm5, bs("001")]) + +# SRL Rn,imm5 - 0110_nnnn_iiii_i010 +addop("SRL", [bs("0110"), reg04, imm5, bs("010")]) + +# SRA Rn,imm5 - 0110_nnnn_iiii_i011 +addop("SRA", [bs("0110"), reg04, imm5, bs("011")]) + +# SLTU3 R0,Rn,imm5 - 0110_nnnn_iiii_i101 +addop("SLTU3", [bs("0110"), reg00, reg04, imm5, bs("101")]) + +# SLL Rn,imm5 - 0110_nnnn_iiii_i110 +addop("SLL", [bs("0110"), reg04, imm5, bs("110")]) + +# SLL3 R0,Rn,imm5 - 0110_nnnn_iiii_i111 +addop("SLL3", [bs("0110"), reg00, reg04, imm5, bs("111")]) + + +### <Major Opcode #7> + +# DI - 0111_0000_0000_0000 +addop("DI", [bs("0111000000000000")]) + +# EI - 0111_0000_0001_0000 +addop("EI", [bs("0111000000010000")]) + +# SYNCM - 0111_0000_0001_0001 +addop("SYNCM", [bs("0111000000010001")]) + +# SYNCCP - 0111_0000_0010_0001 +addop("SYNCCP", [bs("0111000000100001")]) + +# RET - 0111_0000_0000_0010 +addop("RET", [bs("0111000000000010")]) + +# RETI - 0111_0000_0001_0010 +addop("RETI", [bs("0111000000010010")]) + +# HALT - 0111_0000_0010_0010 +addop("HALT", [bs("0111000000100010")]) + +# BREAK - 0111_0000_0011_0010 +addop("BREAK", [bs("0111000000110010")]) + +# SLEEP - 0111_0000_0110_0010 +addop("SLEEP", [bs("0111000001100010")]) + +# DRET - 0111_0000_0001_0011 +addop("DRET", [bs("0111000000010011")]) + +# DBREAK - 0111_0000_0011_0011 +addop("DBREAK", [bs("0111000000110011")]) + +# CACHE imm4,(Rm) - 0111_iiii_mmmm_0100 +addop("CACHE", [bs("0111"), imm4, reg04_deref, bs("0100")]) + +# (RI) - 0111_xxxx_xxxx_0101 +addop("(RI)", [bs("0111"), reg04, reg04, bs("0101")]) + +# SWI imm2 - 0111_0000_00ii_0110 +addop("SWI", [bs("0111000000"), imm2, bs("0110")]) + +# (RI) - 0111_xxxx_xxxx_0111 +addop("(RI)", [bs("0111"), reg04, reg04, bs("0111")]) + +# STC Rn,imm5 - 0111_nnnn_iiii_100I +addop("STC", [bs("0111"), reg04, imm4_iiii_noarg, bs("100"), imm5_Iiiii]) + +# LDC Rn,imm5 - 0111_nnnn_iiii_101I +addop("LDC", [bs("0111"), reg04, imm4_iiii_noarg, bs("101"), imm5_Iiiii]) + +# (RI) - 0111_xxxx_xxxx_1100 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1100")]) + +# (RI) - 0111_xxxx_xxxx_1101 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1101")]) + +# (RI) - 0111_xxxx_xxxx_1110 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1110")]) + +# (RI) - 0111_xxxx_xxxx_1111 +addop("(RI)", [bs("0111"), reg04, reg04, bs("1111")]) + + +### <Major Opcode #8> + +# SB Rn[0-7],disp7(TP) - 1000_0nnn_0ddd_dddd +addop("SB", [bs("10000"), reg03, bs("0"), imm7_noarg, reg00_deref_tp]) + +# SH Rn[0-7],disp7.align2(TP) - 1000_0nnn_1ddd_ddd0 +# (disp7.align2 = ddd_ddd||0) +addop("SH", [bs("10000"), reg03, bs("1"), disp7_align2_noarg, bs("0"), reg00_deref_tp]) + +# LB Rn[0-7],disp7(TP) - 1000_1nnn_0ddd_dddd +addop("LB", [bs("10001"), reg03, bs("0"), imm7_noarg, reg00_deref_tp]) + +# LH Rn[0-7],disp7.align2(TP) - 1000_1nnn_1ddd_ddd0 +addop("LH", [bs("10001"), reg03, bs("1"), disp7_align2_noarg, bs("0"), reg00_deref_tp]) + +# LHU Rn[0-7],disp7.align2(TP) - 1000_1nnn_1ddd_ddd1 +addop("LHU", [bs("10001"), reg03, bs("1"), disp7_align2_noarg, bs("1"), reg00_deref_tp]) + + +### <Major Opcode #9> + +# ADD3 Rl,Rn,Rm - 1001_nnnn_mmmm_llll +addop("ADD3", [bs("1001"), reg04_n, reg04_m, reg04_l], [reg04_l, reg04_n, reg04_m]) + + +### <Major Opcode #10> + +# BEQZ Rn,disp8.align2 - 1010_nnnn_dddd_ddd0 +# (disp8=dddd_ddd||0) +addop("BEQZ", [bs("1010"), reg04, disp8, bs("0")]) + +# BNEZ Rn,disp8.align2 - 1010_nnnn_dddd_ddd1 +addop("BNEZ", [bs("1010"), reg04, disp8, bs("1")]) + + +### <Major Opcode #11> + +# BRA disp12.align2 - 1011_dddd_dddd_ddd0 +# (disp12=dddd_dddd_ddd||0) +addop("BRA", [bs("1011"), disp12_signed, bs("0")]) + +# BSR disp12.align2 - 1011_dddd_dddd_ddd1 +addop("BSR", [bs("1011"), disp12_signed, bs("1")]) + + +### <Major Opcode #12> + +# ADD3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0000 iiii_iiii_iiii_iiii +addop("ADD3", [bs("1100"), reg04, reg04, bs("0000"), imm16_signed]) + +# MOV Rn,imm16 - 1100_nnnn_0000_0001 iiii_iiii_iiii_iiii +addop("MOV", [bs("1100"), reg04, bs("00000001"), imm16]) + +# MOVU Rn,imm16 - 1100_nnnn_0001_0001 iiii_iiii_iiii_iiii +addop("MOVU", [bs("1100"), reg04, bs("00010001"), imm16]) + +# MOVH Rn,imm16 - 1100_nnnn_0010_0001 iiii_iiii_iiii_iiii +addop("MOVH", [bs("1100"), reg04, bs("00100001"), imm16]) + +# SLT3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0010 iiii_iiii_iiii_iiii +addop("SLT3", [bs("1100"), reg04, reg04, bs("0010"), imm16_signed]) + +# SLTU3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0011 iiii_iiii_iiii_iiii +addop("SLTU3", [bs("1100"), reg04, reg04, bs("0011"), imm16]) + +# OR3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0100 iiii_iiii_iiii_iiii +addop("OR3", [bs("1100"), reg04, reg04, bs("0100"), imm16]) + +# AND3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0101 iiii_iiii_iiii_iiii +addop("AND3", [bs("1100"), reg04, reg04, bs("0101"), imm16]) + +# XOR3 Rn,Rm,imm16 - 1100_nnnn_mmmm_0110 iiii_iiii_iiii_iiii +addop("XOR3", [bs("1100"), reg04, reg04, bs("0110"), imm16]) + +# (RI) - 1100_xxxx_xxxx_0111 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1100"), imm8, bs("0111"), imm16]) + +# SB Rn,disp16(Rm) - 1100_nnnn_mmmm_1000 dddd_dddd_dddd_dddd +addop("SB", [bs("1100"), reg04, reg04_deref_noarg, bs("1000"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# SH Rn,disp16(Rm) - 1100_nnnn_mmmm_1001 dddd_dddd_dddd_dddd +addop("SH", [bs("1100"), reg04, reg04_deref_noarg, bs("1001"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# SW Rn,disp16(Rm) - 1100_nnnn_mmmm_1010 dddd_dddd_dddd_dddd +addop("SW", [bs("1100"), reg04, reg04_deref_noarg, bs("1010"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LBU Rn,disp16(Rm) - 1100_nnnn_mmmm_1011 dddd_dddd_dddd_dddd +addop("LBU", [bs("1100"), reg04, reg04_deref_noarg, bs("1011"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LB Rn,disp16(Rm) - 1100_nnnn_mmmm_1100 dddd_dddd_dddd_dddd +addop("LB", [bs("1100"), reg04, reg04_deref_noarg, bs("1100"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LH Rn,disp16(Rm) - 1100_nnnn_mmmm_1101 dddd_dddd_dddd_dddd +addop("LH", [bs("1100"), reg04, reg04_deref_noarg, bs("1101"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LW Rn,disp16(Rm) - 1100_nnnn_mmmm_1110 dddd_dddd_dddd_dddd +addop("LW", [bs("1100"), reg04, reg04_deref_noarg, bs("1110"), disp16_reg_deref], [reg04, disp16_reg_deref]) + +# LHU Rn,disp16(Rm) - 1100_nnnn_mmmm_1111 dddd_dddd_dddd_dddd +addop("LHU", [bs("1100"), reg04, reg04_deref_noarg, bs("1111"), disp16_reg_deref], [reg04, disp16_reg_deref]) + + +### <Major Opcode #13> + +# MOVU Rn[0-7],imm24 - 1101_0nnn_IIII_IIII iiii_iiii_iiii_iiii +addop("MOVU", [bs("11010"), reg03, imm24]) + +# BCPEQ cccc,disp17 - 1101_1000_cccc_0100 dddd_dddd_dddd_dddd +addop("BCPEQ", [bs("11011000"), imm4, bs("0100"), disp17]) + +# BCPNE cccc,disp17 - 1101_1000_cccc_0101 dddd_dddd_dddd_dddd +addop("BCPNE", [bs("11011000"), imm4, bs("0101"), disp17]) + +# BCPAT cccc,disp17 - 1101_1000_cccc_0110 dddd_dddd_dddd_dddd +addop("BCPAT", [bs("11011000"), imm4, bs("0110"), disp17]) + +# BCPAF cccc,disp17 - 1101_1000_cccc_0111 dddd_dddd_dddd_dddd +addop("BCPAF", [bs("11011000"), imm4, bs("0111"), disp17]) + +# JMP target24 - 1101_1TTT_TTTT_1000 tttt_tttt_tttt_tttt +addop("JMP", [bs("11011"), imm7_noarg, bs("1000"), imm_target24], + [imm_target24]) # the only interesting operand is imm_target24 + +# BSR disp24 - 1101_1DDD_DDDD_1001 dddd_dddd_dddd_dddd +addop("BSR", [bs("11011"), imm7_noarg, bs("1001"), imm_target24_signed], [imm_target24_signed]) + +# BSRV disp24 1101_1DDD_DDDD_1011 dddd_dddd_dddd_dddd +addop("BSRV", [bs("11011"), imm7_noarg, bs("1011"), imm_target24], [imm_target24]) + + +### <Major Opcode #14> + +# BEQI Rn,imm4,disp17 - 1110_nnnn_iiii_0000 dddd_dddd_dddd_dddd +addop("BEQI", [bs("1110"), reg04, imm4, bs("0000"), disp17]) + +# BEQ Rn,Rm,disp17 - 1110_nnnn_mmmm_0001 dddd_dddd_dddd_dddd +addop("BEQ", [bs("1110"), reg04, reg04, bs("0001"), disp17]) + +# BNEI Rn,imm4,disp17 - 1110_nnnn_iiii_0100 dddd_dddd_dddd_dddd +addop("BNEI", [bs("1110"), reg04, imm4, bs("0100"), disp17]) + +# BNE Rn,Rm,disp17 - 1110_nnnn_mmmm_0101 dddd_dddd_dddd_dddd +addop("BNE", [bs("1110"), reg04, reg04, bs("0101"), disp17]) + +# BGEI Rn,imm4,disp17 - 1110_nnnn_iiii_1000 dddd_dddd_dddd_dddd +addop("BGEI", [bs("1110"), reg04, imm4, bs("1000"), disp17]) + +# REPEAT Rn,disp17 - 1110_nnnn_0000_1001 dddd_dddd_dddd_dddd +addop("REPEAT", [bs("1110"), reg04, bs("00001001"), disp17]) + +# EREPEAT disp17 - 1110_0000_0001_1001 dddd_dddd_dddd_dddd +addop("EREPEAT", [bs("1110000000011001"), disp17]) + +# BLTI Rn,imm4,disp17 - 1110_nnnn_iiii_1100 dddd_dddd_dddd_dddd +addop("BLTI", [bs("1110"), reg04, imm4, bs("1100"), disp17]) + +# (RI) - 1110_xxxx_xxxx_1101 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1110"), imm8, bs("1101"), imm16]) + +# SW Rn,(abs24) - 1110_nnnn_DDDD_DD10 dddd_dddd_dddd_dddd +addop("SW", [bs("1110"), reg04, imm6_noarg, bs("10"), abs24]) + +# LW Rn,(abs24) - 1110_nnnn_DDDD_DD11 dddd_dddd_dddd_dddd +addop("LW", [bs("1110"), reg04, imm6_noarg, bs("11"), abs24]) + + +### <Major Opcode #15> + +# DSP Rn,Rm,code16 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc +addop("DSP", [bs("1111"), reg04, reg04, bs("0000"), imm16]) + +# Note: DSP, DSP0 & DSP1 look exactly the same. This is ambiguous, and prevent +# them for being correctly disassembled. DSP0 & DSP1 are arbitrarily +# disabled. + +# DSP0 code24 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc +#addop("DSP0", [bs("1111"), imm8_noarg, bs("0000"), imm_code24], [imm_code24]) + +# DSP1 Rn,code20 - 1111_nnnn_mmmm_0000 cccc_cccc_cccc_cccc +#addop("DSP1", [bs("1111"), reg04, imm4_noarg, bs("0000"), imm_code20]) + +# LDZ Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0000 +addop("LDZ", [bs("1111"), reg04, reg04, bs("00010000000000000000")]) + +# AVE Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0010 +addop("AVE", [bs("1111"), reg04, reg04, bs("00010000000000000010")]) + +# ABS Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0011 +addop("ABS", [bs("1111"), reg04, reg04, bs("00010000000000000011")]) + +# MIN Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0100 +addop("MIN", [bs("1111"), reg04, reg04, bs("00010000000000000100")]) + +# MAX Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0101 +addop("MAX", [bs("1111"), reg04, reg04, bs("00010000000000000101")]) + +# MINU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0110 +addop("MINU", [bs("1111"), reg04, reg04, bs("00010000000000000110")]) + +# MAXU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_0111 +addop("MAXU", [bs("1111"), reg04, reg04, bs("00010000000000000111")]) + +# SADD Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1000 +addop("SADD", [bs("1111"), reg04, reg04, bs("00010000000000001000")]) + +# SADDU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1001 +addop("SADDU", [bs("1111"), reg04, reg04, bs("00010000000000001001")]) + +# SSUB Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1010 +addop("SSUB", [bs("1111"), reg04, reg04, bs("00010000000000001010")]) + +# SSUBU Rn,Rm - 1111_nnnn_mmmm_0001 0000_0000_0000_1011 +addop("SSUBU", [bs("1111"), reg04, reg04, bs("00010000000000001011")]) + +# CLIP Rn,imm5 - 1111_nnnn_0000_0001 0001_0000_iiii_i000 +addop("CLIP", [bs("1111"), reg04, bs("0000000100010000"), imm5, bs("000")]) + +# CLIPU Rn,imm5 - 1111_nnnn_0000_0001 0001_0000_iiii_i001 +addop("CLIPU", [bs("1111"), reg04, bs("0000000100010000"), imm5, bs("001")]) + +# (RI) - 1111_xxxx_xxxx_0001 0010_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("00010010"), imm12]) + +# MADD Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0100 +addop("MADD", [bs("1111"), reg04, reg04, bs("00010011000000000100")]) + +# MADDU Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0101 +addop("MADDU", [bs("1111"), reg04, reg04, bs("00010011000000000101")]) + +# MADDR Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0110 +addop("MADDR", [bs("1111"), reg04, reg04, bs("00010011000000000110")]) + +# MADDRU Rn,Rm - 1111_nnnn_mmmm_0001 0011_0000_0000_0111 +addop("MADDRU", [bs("1111"), reg04, reg04, bs("00010011000000000111")]) + +# UCI Rn,Rm,code16 - 1111_nnnn_mmmm_0010 cccc_cccc_cccc_cccc +addop("UCI", [bs("1111"), reg04, reg04, bs("0010"), imm16]) + +# (RI) - 1111_xxxx_xxxx_0011 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("0011"), imm16]) + +# STCB Rn,abs16 - 1111_nnnn_0000_0100 aaaa_aaaa_aaaa_aaaa +addop("STCB", [bs("1111"), reg04, bs("00000100"), imm16]) + +# LDCB Rn,abs16 - 1111_nnnn_0001_0100 aaaa_aaaa_aaaa_aaaa +addop("LDCB", [bs("1111"), reg04, bs("00010100"), imm16]) + +# SBCPA CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_0000_iiii_iiii +addop("SBCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100000000"), imm8]) + +# SHCPA CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_0000_iiii_iii0 +addop("SHCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100010000"), imm8_align2, bs("0")]) + +# SWCPA CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_0000_iiii_ii00 +addop("SWCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100100000"), imm8_align4, bs("00")]) + +# SMCPA CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_0000_iiii_i000 +addop("SMCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100110000"), imm8_align8, bs("000")]) + +# LBCPA CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_0000_iiii_iiii +addop("LBCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101000000"), imm8]) + +# LHCPA CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_0000_iiii_iii0 +addop("LHCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101010000"), imm8_align2, bs("0")]) + +# LWCPA CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_0000_iiii_ii00 +addop("LWCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101100000"), imm8_align4, bs("00")]) + +# LMCPA CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_0000_iiii_i000 +addop("LMCPA", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101110000"), imm8_align8, bs("000")]) + +# SBCPM0 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_1000_iiii_iiii +addop("SBCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100001000"), imm8]) + +# SHCPM0 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_1000_iiii_iii0 +addop("SHCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100011000"), imm8_align2, bs("0")]) + +# SWCPM0 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_1000_iiii_ii00 +addop("SWCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100101000"), imm8_align4, bs("00")]) + +# SMCPM0 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_1000_iiii_i000 +addop("SMCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100111000"), imm8_align8, bs("000")]) + +# LBCPM0 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_1000_iiii_iiii +addop("LBCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101001000"), imm8]) + +# LHCPM0 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_1000_iiii_iii0 +addop("LHCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101011000"), imm8_align2, bs("0")]) + +# LWCPM0 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_1000_iiii_ii00 +addop("LWCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101101000"), imm8_align4, bs("00")]) + +# LMCPM0 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_1000_iiii_i000 +addop("LMCPM0", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101111000"), imm8_align8, bs("000")]) + +# SBCPM1 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0000_1100_iiii_iiii +addop("SBCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100001100"), imm8]) + +# SHCPM1 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0001_1100_iiii_iii0 +addop("SHCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100011100"), imm8_align2, bs("0")]) + +# SWCPM1 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0010_1100_iiii_ii00 +addop("SWCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100101100"), imm8_align4, bs("00")]) + +# SMCPM1 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0011_1100_iiii_i000 +addop("SMCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010100111100"), imm8_align8, bs("000")]) + +# LBCPM1 CRn,(Rm+),imm8 - 1111_nnnn_mmmm_0101 0100_1100_iiii_iiii +addop("LBCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101001100"), imm8]) + +# LHCPM1 CRn,(Rm+),imm8.align2 - 1111_nnnn_mmmm_0101 0101_1100_iiii_iii0 +addop("LHCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101011100"), imm8_align2, bs("0")]) + +# LWCPM1 CRn,(Rm+),imm8.align4 - 1111_nnnn_mmmm_0101 0110_1100_iiii_ii00 +addop("LWCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101101100"), imm8_align4, bs("00")]) + +# LMCPM1 CRn,(Rm+),imm8.align8 - 1111_nnnn_mmmm_0101 0111_1100_iiii_i000 +addop("LMCPM1", [bs("1111"), copro_reg04, reg04_inc_deref, bs("010101111100"), imm8_align8, bs("000")]) + +# (RI) - 1111_xxxx_xxxx_0110 xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("0110"), imm16]) + +# CP code24 - 1111_CCCC_CCCC_0111 cccc_cccc_cccc_cccc +#addop("CP", [bs("1111"), imm8_noarg, bs("0111"), imm_code24], [imm_code24]) +# Note: CP & CMOV* look exactly the same. This is ambiguous, and prevent +# them for being correctly disassembled. CP was arbitrarily disabled. + +# CP code56 - 1111_CCCC_CCCC_0111 cccc_cccc_cccc_cccc cccc_cccc_cccc_cccc +# 64-bit VLIW operation mode - not implemented + +# CMOV CRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_0000 +#addop("CMOV", [bs("1111"), copro_reg04, reg04, bs("01111111000000000000")]) + +# CMOV Rm,CRn - 1111_nnnn_mmmm_0111 1111_0000_0000_0001 +#addop("CMOV", [bs("1111"), copro_reg04, reg04, bs("01111111000000000001")], [reg04, copro_reg04]) + +# CMOVC CCRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_NN10 +# CRn=NNnnnn +addop("CMOVC", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg06, bs("10")], [copro_reg06, reg04]) + +# CMOVC Rm,CCRn - 1111_nnnn_mmmm_0111 1111_0000_0000_NN11 +# CRn=NNnnnn +addop("CMOVC", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg06, bs("11")], [reg04, copro_reg06]) + +# CMOVH CRn,Rm - 1111_nnnn_mmmm_0111 1111_0001_0000_0000 +#addop("CMOVH", [bs("1111"), copro_reg04, reg04, bs("01111111000100000000")]) + +# CMOVH Rm,CRn - 1111_nnnn_mmmm_0111 1111_0001_0000_0001 +#addop("CMOVH", [bs("1111"), copro_reg04, reg04, bs("01111111000100000001")], [reg04, copro_reg04]) + +# Note: the following CMOV* instructions are extensions used when the processor +# has more than 16 coprocessor general-purpose registers. They can be +# used to assemble and disassemble both CMOV* instructuons sets. + +# CMOV CRn,Rm - 1111_nnnn_mmmm_0111 1111_0000_0000_N000 +# CRn=Nnnnn +addop("CMOV", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg05, bs("000")], [copro_reg05, reg04]) + +# CMOV Rm,CRn - 1111_nnnn_mmmm_0111 1111_0000_0000_N001 +addop("CMOV", [bs("1111"), imm4_noarg, reg04, bs("0111111100000000"), copro_reg05, bs("001")], [reg04, copro_reg05]) + +# CMOVH CRn,Rm - 1111_nnnn_mmmm_0111 1111_0001_0000_N000 +addop("CMOVH", [bs("1111"), imm4_noarg, reg04, bs("0111111100010000"), copro_reg05, bs("000")], [copro_reg05, reg04]) + +# CMOVH Rm,CRn - 1111_nnnn_mmmm_0111 1111_0001_0000_N001 +addop("CMOVH", [bs("1111"), imm4_noarg, reg04, bs("0111111100010000"), copro_reg05, bs("001")], [reg04, copro_reg05]) + +# (RI) - 1111_xxxx_xxxx_10xx xxxx_xxxx_xxxx_xxxx +addop("(RI)", [bs("1111"), imm8, bs("10"), imm18]) + +# SWCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1100 dddd_dddd_dddd_dddd +addop("SWCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1100"), disp16_reg_deref], [copro_reg04, disp16_reg_deref]) + +# LWCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1101 dddd_dddd_dddd_dddd +addop("LWCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1101"), disp16_reg_deref], [copro_reg04, disp16_reg_deref, reg04_deref]) + +# SMCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1110 dddd_dddd_dddd_dddd +addop("SMCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1110"), disp16_reg_deref], [copro_reg04, disp16_reg_deref, reg04_deref]) + +# LMCP CRn,disp16(Rm) - 1111_nnnn_mmmm_1111 dddd_dddd_dddd_dddd +addop("LMCP", [bs("1111"), copro_reg04, reg04_deref_noarg, bs("1111"), disp16_reg_deref], [copro_reg04, disp16_reg_deref]) diff --git a/miasm2/arch/mep/disasm.py b/miasm2/arch/mep/disasm.py new file mode 100644 index 00000000..2ad73036 --- /dev/null +++ b/miasm2/arch/mep/disasm.py @@ -0,0 +1,23 @@ +# Toshiba MeP-c4 - miasm disassembly engine +# Guillaume Valadon <guillaume@valadon.net> + +from miasm2.core.asmblock import disasmEngine +from miasm2.arch.mep.arch import mn_mep + + +class dis_mepb(disasmEngine): + """MeP miasm disassembly engine - Big Endian + + Notes: + - its is mandatory to call the miasm Machine + """ + + attrib = "b" + + def __init__(self, bs=None, **kwargs): + super(dis_mepb, self).__init__(mn_mep, self.attrib, bs, **kwargs) + + +class dis_mepl(dis_mepb): + """MeP miasm disassembly engine - Little Endian""" + attrib = "l" diff --git a/miasm2/arch/mep/ira.py b/miasm2/arch/mep/ira.py new file mode 100644 index 00000000..34808656 --- /dev/null +++ b/miasm2/arch/mep/ira.py @@ -0,0 +1,45 @@ +# Toshiba MeP-c4 - miasm IR analysis +# Guillaume Valadon <guillaume@valadon.net> + +from miasm2.arch.mep.sem import ir_mepb, ir_mepl +from miasm2.ir.analysis import ira + + +class ir_a_mepb(ir_mepb, ira): + """MeP high level IR manipulations - Big Endian + + Notes: + - it is mandatory for symbolic execution. + """ + + def __init__(self, loc_db=None): + ir_mepb.__init__(self, loc_db) + self.ret_reg = self.arch.regs.R0 + + # Note: the following are abstract method and must be implemented + def sizeof_char(self): + "Return the size of a char in bits" + return 8 + + def sizeof_short(self): + "Return the size of a short in bits" + return 16 + + def sizeof_int(self): + "Return the size of an int in bits" + return 32 + + def sizeof_long(self): + "Return the size of a long in bits" + return 32 + + def sizeof_pointer(self): + "Return the size of a void* in bits" + return 32 + + +class ir_a_mepl(ir_mepl, ir_a_mepb): + """MeP high level IR manipulations - Little Endian""" + + def __init__(self, loc_db=None): + ir_a_mepb.__init__(self, loc_db) diff --git a/miasm2/arch/mep/jit.py b/miasm2/arch/mep/jit.py new file mode 100644 index 00000000..33eb5c3c --- /dev/null +++ b/miasm2/arch/mep/jit.py @@ -0,0 +1,115 @@ +# Toshiba MeP-c4 - miasm jitter +# Guillaume Valadon <guillaume@valadon.net> +# Note: inspiration from msp430/jit.py + +from miasm2.jitter.jitload import Jitter +from miasm2.core.locationdb import LocationDB +from miasm2.core.utils import * +from miasm2.jitter.codegen import CGen +from miasm2.ir.translators.C import TranslatorC +from miasm2.arch.mep.sem import ir_mepl, ir_mepb + +import logging + +log = logging.getLogger("jit_mep") +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + + +class mep_CGen(CGen): + """ + Translate a bloc containing MeP instructions to C + + Note: it is used to emulate the *REPEAT instructions + """ + + def __init__(self, ir_arch): + self.ir_arch = ir_arch + self.PC = self.ir_arch.arch.regs.PC + self.translator = TranslatorC(self.ir_arch.loc_db) + self.init_arch_C() + + def gen_pre_code(self, attrib): + """Generate C code inserted before the current bloc""" + + # Call the base class method + out = super(mep_CGen, self).gen_pre_code(attrib) + + # Set the PC register value explicitly + out.append("mycpu->PC = 0x%X;" % attrib.instr.offset) + out.append("mycpu->last_addr = mycpu->PC;"); + + return out + + def gen_post_code(self, attrib): + """Generate C code inserted after the current bloc""" + + # Call the base class method + out = super(mep_CGen, self).gen_post_code(attrib) + + # Implement the *REPEAT instructions logics + tmp = r""" + /* *REPEAT instructions logic */ + { + uint32_t is_repeat_end = mycpu->is_repeat_end; + mycpu->is_repeat_end = !!(mycpu->last_addr == (mycpu->RPE&~0x1)); + + if (is_repeat_end && !mycpu->take_jmp && + (mycpu->in_erepeat || mycpu->RPC)) { + if (mycpu->RPC) + mycpu->RPC --; + + //printf("Go repeat %X\n", mycpu->RPB); + DST_value = mycpu->RPB; + BlockDst->address = mycpu->RPB; + return JIT_RET_NO_EXCEPTION; + } + } + """ + + out += tmp.split('`\n') + return out + + +class jitter_mepl(Jitter): + + C_Gen = mep_CGen + + def __init__(self, *args, **kwargs): + sp = LocationDB() + Jitter.__init__(self, ir_mepl(sp), *args, **kwargs) + self.vm.set_little_endian() + self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC + + def push_uint16_t(self, v): + regs = self.cpu.get_gpreg() + regs["SP"] -= 2 + self.cpu.set_gpreg(regs) + self.vm.set_mem(regs["SP"], pck16(v)) + + def pop_uint16_t(self): + regs = self.cpu.get_gpreg() + x = upck16(self.vm.get_mem(regs["SP"], 2)) + regs["SP"] += 2 + self.cpu.set_gpreg(regs) + return x + + def get_stack_arg(self, n): + regs = self.cpu.get_gpreg() + x = upck16(self.vm.get_mem(regs["SP"] + 2 * n, 2)) + return x + + def init_run(self, *args, **kwargs): + Jitter.init_run(self, *args, **kwargs) + self.cpu.PC = self.pc + + +class jitter_mepb(jitter_mepl): + + def __init__(self, *args, **kwargs): + sp = LocationDB() + Jitter.__init__(self, ir_mepb(sp), *args, **kwargs) + self.vm.set_big_endian() + self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC diff --git a/miasm2/arch/mep/regs.py b/miasm2/arch/mep/regs.py new file mode 100644 index 00000000..9564d026 --- /dev/null +++ b/miasm2/arch/mep/regs.py @@ -0,0 +1,90 @@ +# Toshiba MeP-c4 - miasm registers definition +# Guillaume Valadon <guillaume@valadon.net> + +from miasm2.expression.expression import * +from miasm2.core.cpu import reg_info, gen_reg, gen_regs + +# Used by internal miasm exceptions +exception_flags = ExprId("exception_flags", 32) +exception_flags_init = ExprId("exception_flags_init", 32) + +is_repeat_end = ExprId("is_repeat_end", 32) +is_repeat_end_init = ExprId("is_repeat_end_init", 32) +last_addr = ExprId("last_addr", 32) +last_addr_init = ExprId("last_addr_init", 32) +take_jmp = ExprId("take_jmp", 32) +take_jmp_init = ExprId("take_jmp_init", 32) +in_erepeat = ExprId("in_erepeat", 32) +in_erepeat_init = ExprId("take_jmp_init", 32) + + +# General-purpose registers (R0 to R15) names +gpr_names = ["R%d" % r for r in xrange(13)] # register names +gpr_names += ["TP", "GP", "SP"] # according to the manual GP does not exist +gpr_exprs, gpr_inits, gpr_infos = gen_regs(gpr_names, globals()) # sz=32 bits (default) + +# Notes: +# - gpr_exprs: register ExprIds on 32 bits. The size is important for +# symbolic execution. +# - gpr_inits: register initial values. +# - gpr_infos: object that binds names & ExprIds + +# Define aliases to general-purpose registers +TP = gpr_exprs[13] # Tiny data area Pointer +GP = gpr_exprs[14] # Global Pointer +SP = gpr_exprs[15] # Stack Pointer + + +# Control/special registers name +csr_names = ["PC", "LP", "SAR", "S3", "RPB", "RPE", "RPC", "HI", "LO", + "S9", "S10", "S11", "MB0", "ME0", "MB1", "ME1", "PSW", + "ID", "TMP", "EPC", "EXC", "CFG", "S22", "NPC", "DBG", + "DEPC", "OPT", "RCFG", "CCFG", "S29", "S30", "S31", "S32"] +csr_exprs, csr_inits, csr_infos = gen_regs(csr_names, globals()) + +# Define aliases to control/special registers +PC = csr_exprs[0] # Program Conter. On MeP, it is the special register R0 +LP = csr_exprs[1] # Link Pointer. On MeP, it is the special register R1 +SAR = csr_exprs[2] # Shift Amount Register. On MeP, it is the special register R2 +RPB = csr_exprs[4] # Repeat Begin. On MeP, it is the special register R4 +RPE = csr_exprs[5] # Repeat End. On MeP, it is the special register R5 +RPC = csr_exprs[6] # Repeat Counter. On MeP, it is the special register R6 + + +# Coprocesssor general-purpose registers (C0 to C15) names +# Note: a processor extension allows up to 32 coprocessor general-purpose registers +copro_gpr_names = ["C%d" % r for r in xrange(32)] # register names +copro_gpr_exprs, copro_gpr_inits, copro_gpr_infos = gen_regs(copro_gpr_names, globals()) + + +# Set registers initial values +all_regs_ids = gpr_exprs + csr_exprs + copro_gpr_exprs + [ + exception_flags, take_jmp, last_addr, is_repeat_end, + in_erepeat +] + +all_regs_ids_init = gpr_inits + csr_inits + copro_gpr_inits + [ + exception_flags_init, take_jmp_init, last_addr_init, is_repeat_end_init, + in_erepeat_init +] + +all_regs_ids_no_alias = all_regs_ids[:] # GV: not understood yet ! +all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) + + +float_st0 = ExprId("float_st0", 64) +float_st1 = ExprId("float_st1", 64) +float_st2 = ExprId("float_st2", 64) +float_st3 = ExprId("float_st3", 64) +float_st4 = ExprId("float_st4", 64) +float_st5 = ExprId("float_st5", 64) +float_st6 = ExprId("float_st6", 64) +float_st7 = ExprId("float_st7", 64) + +regs_flt_expr = [float_st0, float_st1, float_st2, float_st3, + float_st4, float_st5, float_st6, float_st7] + + +regs_init = dict() # mandatory name +for i, r in enumerate(all_regs_ids): + regs_init[r] = all_regs_ids_init[i] diff --git a/miasm2/arch/mep/sem.py b/miasm2/arch/mep/sem.py new file mode 100644 index 00000000..32a3270d --- /dev/null +++ b/miasm2/arch/mep/sem.py @@ -0,0 +1,1172 @@ +# Toshiba MeP-c4 - miasm instructions side effects +# Guillaume Valadon <guillaume@valadon.net> + +from miasm2.core.sembuilder import SemBuilder +from miasm2.ir.ir import IntermediateRepresentation +from miasm2.arch.mep.arch import mn_mep +from miasm2.arch.mep.regs import PC, SP, LP, SAR, TP, RPB, RPE, RPC, EPC, NPC, \ + take_jmp, in_erepeat +from miasm2.arch.mep.regs import EXC, HI, LO, PSW, DEPC, DBG +from miasm2.expression.expression import ExprId, ExprInt, ExprOp +from miasm2.expression.expression import ExprAff, ExprCond, ExprMem +from miasm2.core.cpu import sign_ext +from miasm2.jitter.csts import EXCEPT_DIV_BY_ZERO + +from miasm2.arch.mep.regs import exception_flags + + +def compute_s_inf(arg1, arg2): + """Signed comparison operator""" + return ((arg1 - arg2) ^ ((arg1 ^ arg2) & ((arg1 - arg2) ^ arg1))).msb() + +def compute_u_inf(x, y): + """Unsigned comparison operator""" + result = (((x - y) ^ ((x ^ y) & ((x - y) ^ x))) ^ x ^ y).msb() + return result + + +# SemBuilder context +ctx = {"PC": PC, "SP": SP, "LP": LP, "SAR": SAR, "TP": TP, + "RPB": RPB, "RPE": RPE, "RPC": RPC, "EPC": EPC, "NPC": NPC, + "EXC": EXC, "HI": HI, "LO": LO, "PSW": PSW, "DEPC": DEPC, "DBG": DBG, + "exception_flags": exception_flags, "compute_s_inf": compute_s_inf, + "compute_u_inf": compute_u_inf, "take_jmp": take_jmp, + "in_erepeat": in_erepeat, "EXCEPT_DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO} +sbuild = SemBuilder(ctx) + + +# Functions used to get an instruction IR +manual_functions = dict() + + +@sbuild.parse +def mep_nop(): + """Dummy instruction""" + + +@sbuild.parse +def mep_nop_2_args(arg1, arg2): + """Dummy instruction with two arguments""" + + +### Load/Store instructions + +# Register indirect addressing mode + +@sbuild.parse +def sb(reg_src, deref_dst): + """SB - Store Byte into memory""" + + # MemByte(Rm31..0) <- Rn7..0 + # MemByte((ZeroExt(disp7)+TP)31..0)) <- Rn7..0 + # MemByte((SignExt(disp16)+Rm)31..0) <- Rn7..0 + mem8[deref_dst.arg] = reg_src[:8] + + +@sbuild.parse +def sh(reg_src, deref_dst): + """SH - Store Halfword into memory""" + + # MemHword(Rm31..1||0) <- Rn15..0 + # MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0)) <- Rn15..0 + # MemHword((SignExt(disp16)+Rm)31..1||0) <- Rn15..0 + mem16[deref_dst.arg & i32(0xFFFFFFFE)] = reg_src[:16] + + +@sbuild.parse +def sw(reg_src, deref_dst): + """SW - Store Word into memory""" + + # MemWord(Rm31..2||00) <- Rn31..0 + # MemWord((ZeroExt((disp7)6..2||00)+SP)31..2||00)) <- Rn31..0 + # MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00)) <- Rn31..0 + # MemWord((SignExt(disp16)+Rm)31..2||00) <- Rn31..0 + # MemWord(ZeroExt((abs24)23..2||00)) - Rn31..0 + + mem32[deref_dst.arg & i32(0xFFFFFFFC)] = reg_src + +# Without the sembuilder +#def sw(ir, instr, reg_src, deref_reg_or_imm, deref_reg=None): +# """SW - store Word into memory. +# +# Note: there are three variants to get the memory address: +# - from a register +# - relatively to SP +# - relatively to TP""" +# +# if isinstance(deref_reg_or_imm, ExprMem): +# # MemWord(Rm31..2||00) <- Rn31..0 +# dst = deref_reg_or_imm +# +# elif isinstance(deref_reg_or_imm, ExprInt) and deref_reg: +# # MemWord((ZeroExt((disp7)6..2||00)+SP)31..2||00)) <- Rn31..0 +# # MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00)) <- Rn31..0 +# +# imm = deref_reg_or_imm.zeroExtend(32) +# dst = ExprMem(ExprOp("+", imm, deref_reg.arg)) +# +# return [ExprAff(dst, reg_src)], [] + + +@sbuild.parse +def lb(reg_dst, deref_dst): + """LB - Load Byte from memory""" + + # Rn <- SignExt(MemByte(Rm31..0)) + # Rn <- SignExt(MemByte((ZeroExt(disp7)+TP)31..0)) + # Rn <- SignExt(MemByte((SignExt(disp16)+Rm)31..0) + reg_dst = mem8[deref_dst.arg].signExtend(32) + + +@sbuild.parse +def lh(reg_dst, deref_dst): + """LH - Load Halfword from memory""" + + # Rn <- SignExt(MemHword(Rm31..1||0)) + # Rn <- SignExt(MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0) + # Rn <- SignExt(MemHword((SignExt(disp16)+Rm)31..1||0)) + reg_dst = mem16[deref_dst.arg & i32(0xFFFFFFFE)].signExtend(32) + + +@sbuild.parse +def lw(reg_dst, deref_dst): + """LW - Load Word from memory""" + + # Rn <- MemWord(Rm31..2||00) + # Rn <- MemWord((ZeroExt((disp7)6..2||00)+TP)31..2||00) + # Rn <- MemWord((SignExt(disp16)+Rm)31..2||00) + # Rn <- MemWord(ZeroExt((abs24)23..2||00)) + reg_dst = mem32[deref_dst.arg & i32(0xFFFFFFFC)] + + +@sbuild.parse +def lbu(reg_dst, deref_dst): + """LBU - Load an unsigned Byte from memory""" + + # Rn <- ZeroExt(MemByte(Rm31..0)) + # Rn <- ZeroExt(MemByte((ZeroExt(disp7)+TP)31..0)) + # Rn <- ZeroExt(MemByte((SignExt(disp16)+Rm)31..0)) + reg_dst = mem8[deref_dst.arg].zeroExtend(32) + + +@sbuild.parse +def lhu(reg_dst, deref_dst): + """LHU - Load an unsigned Halfword from memory""" + + # Rn <- ZeroExt(MemHword(Rm31..1||0)) + # Rn <- ZeroExt(MemHword((SignExt(disp16)+Rm)31..1||0)) + # Rn <- ZeroExt(MemHword((ZeroExt((disp7)6..1||0)+TP)31..1||0)) + reg_dst = mem16[deref_dst.arg & i32(0xFFFFFFFE)].zeroExtend(32) + + +### Byte/Halfword extension instructions + +@sbuild.parse +def extb(reg): + """EXTB - Sign extend a byte""" + + # Rn <- SignExt(Rn7..0) + reg = reg[:8].signExtend(32) + + +@sbuild.parse +def exth(reg): + """EXTH - Sign extend a word""" + + # Rn <- ZeroExt(Rn15..0) + reg = reg[:16].signExtend(32) + + +@sbuild.parse +def extub(reg): + """EXUTB - Zero extend a byte""" + + # Rn <- SignExt(Rn7..0) + reg = reg[:8].zeroExtend(32) + + +@sbuild.parse +def extuh(reg): + """EXTUH - Zero extend a word""" + + # Rn <- ZeroExt(Rn15..0) + reg = reg[:16].zeroExtend(32) + + +### Shift amount manipulation instructions + +#@sbuild.parse +#def ssarb(deref_reg): + + +### Move instructions + +@sbuild.parse +def mov(reg, value): + """MOV - Copy 'value' to a register. The three alternatives are handled.""" + + # Rn <- Rm + # Rn <- SignExt(imm8) + # Rn <- SignExt(imm16) + reg = value.signExtend(32) + + +@sbuild.parse +def movu(reg, value): + """MOV - Copy 'value' to a register. The two alternatives are handled.""" + + # Rn[0-7] <- ZeroExt(imm24) + # Rn <- ZeroExt(imm16) + reg = value.zeroExtend(32) + + +@sbuild.parse +def movh(reg, imm16): + """MOVH - Copy a shifted imm16 to a register.""" + + # Rn <- imm16 <<16 + reg = imm16.zeroExtend(32) << i32(16) + + +### Arithmetic instructions + +def add3(ir, instr, reg_dst, reg_src, reg_or_imm): + """ADD3 - Add two register and store the result to a register, or + add a register and an immediate and store the result to a register""" + + if isinstance(reg_or_imm, ExprId): + # Rl <- Rn + Rm + result = ExprOp("+", reg_src, reg_or_imm) + else: + # Rn <- Rm + SignExt(imm16) + value = int(reg_or_imm.arg) + result = ExprOp("+", reg_src, ExprInt(value, 32)) + + return [ExprAff(reg_dst, result)], [] + +manual_functions["add3"] = add3 + + +@sbuild.parse +def add(arg1, arg2): + """ADD - Add a register and an immediate.""" + + # Rn <- Rn + SignExt(imm6) + arg1 = arg1 + arg2.signExtend(32) + + +@sbuild.parse +def advck3(r0, rn, rm): + """ADVCK3 - Check addition overflow.""" + + # if(Overflow(Rn+Rm)) R0<-1 else R0<-0 (Signed) + r0 = i32(1) if compute_u_inf(i64(0xFFFFFFFF), rn.zeroExtend(64) + rm.zeroExtend(64)) else i32(0) + + +@sbuild.parse +def sub(reg1, reg2): + """SUB - Substract one register to another.""" + + # Rn <- Rn - Rm + reg1 = reg1 - reg2 + + +def sbvck3(ir, instr, r0, rn, rm): + """SBVCK3 - Check substraction overflow""" + + # if(Overflow(Rn-Rm)) R0<-1 else R0<-0 (Signed) + + # Substract registers + reg_sub = ExprOp("+", rn, rm) + + # Get the register storing the highest value + max_rn_rm = ExprCond(ExprOp(">", rn, rm), rn, rm) + + # Check for an overflow + overflow_test = ExprOp(">", reg_sub, max_rn_rm) + + # Return the result + condition = ExprCond(overflow_test, ExprInt(1, 32), ExprInt(0, 32)) + return [ExprAff(r0, condition)], [] + +manual_functions["sbvck3"] = sbvck3 + + +@sbuild.parse +def neg(reg1, reg2): + """NEG - Negate one register.""" + + # Rn <- - Rm + reg1 = - reg2 + + +@sbuild.parse +def slt3(r0, rn, rm_or_imm5): + """SLT3 - Set on less than (signed).""" + + # if (Rn<Rm) R0<-1 else R0<-0 (Signed) + # if (Rn<ZeroExt(imm5)) R0<-1 else R0<-0(Signed) + r0 = i32(1) if compute_s_inf(rn, rm_or_imm5.signExtend(32)) else i32(0) + +if False: + rm_ext = rm_or_imm5 + + # Mask sign bits + sign_mask = i32(0x80000000) + sign_rn = rn & sign_mask + sign_rm = rm_ext & sign_mask + + # Check if both numbers are positive or negative + are_both_neg = sign_rn & sign_rm + are_both_pos = ~(sign_rn & sign_rm) >> i32(31) + + # rn is positive and rm negative, return 1 + r0_mixed = i32(1) if sign_rn else i32(0) + + # rn & rm are both positives, test and return 1 or 0 + r0_pos = (i32(1) if "<"(rn, rm_ext) else i32(0)) if are_both_pos else r0_mixed + + # rn & rm are both negatives, test and return 0 or 1 + r0 = (i32(0) if "<"(rn, rm_ext) else i32(1)) if are_both_neg else r0_pos + + +@sbuild.parse +def sltu3(r0, rn, rm_or_imm5): + """SLTU3 - Set on less than (unsigned).""" + + # if (Rn<Rm) R0<-1 else R0<-0 (Unigned) + # if (Rn<ZeroExt(imm5)) R0<-1 else R0<-0(Unsigned) + r0 = i32(1) if compute_u_inf(rn, rm_or_imm5) else i32(0) + + +@sbuild.parse +def sl1ad3(r0, rn, rm): + """SL1AD3 - Shift a register one bit left, then add another one.""" + + # R0 <- (Rn<<1) + Rm + r0 = (rn << i32(1)) + rm + + +@sbuild.parse +def sl2ad3(r0, rn, rm): + """SL2AD3 - Shift a register two bits left, then add another one.""" + + # R0 <- (Rn<<2) + Rm + r0 = (rn << i32(2)) + rm + + +### Logical instructions + +@sbuild.parse +def logical_or(rn, rm): + """OR - Logical OR between two registers.""" + + # Rn <- Rn or Rm + rn = rn | rm + +manual_functions["or"] = logical_or + + +@sbuild.parse +def logical_and(rn, rm): + """AND - Logical AND between two registers.""" + + # Rn <- Rn and Rm + rn = rn & rm + +manual_functions["and"] = logical_and + + +@sbuild.parse +def xor(rn, rm): + """XOR - Logical XOR between two registers.""" + + # Rn <- Rn xor Rm + rn = rn ^ rm + + +@sbuild.parse +def nor(rn, rm): + """NOR - Logical NOR between two registers.""" + + # Rn <- Rn nor Rm + rn = ~ (rn | rm) + + +@sbuild.parse +def or3(rn, rm, imm16): + """OR3 - Logical OR between a register and an immediate""" + + # Rn <- Rm or ZeroExt(imm16) + rn = rm | imm16 + + +@sbuild.parse +def and3(rn, rm, imm16): + """AND3 - Logical AND between a register and an immediate""" + + # Rn <- Rm and ZeroExt(imm16) + rn = rm & imm16 + + +@sbuild.parse +def xor3(rn, rm, imm16): + """XOR3 - Logical XOR between a register and an immediate""" + + # Rn <- Rm xor ZeroExt(imm16) + rn = rm ^ imm16 + + +### Shift instruction + +@sbuild.parse +def sra(rn, rm_or_imm5): + """SRA - Shift Right signed""" + + # Rn <- (Signed) Rn >> Rm4..0 + # Rn <- (Signed) Rn >> imm5 + + # Unsigned result + shift_u = rn >> rm_or_imm5 + + # Signed result + shift_mask = i32(32) - rm_or_imm5 + mask = (i32(0xFFFFFFFF) >> shift_mask) << shift_mask + shift_s = shift_u | mask + + rn = shift_s if rn.msb() else shift_u + + +@sbuild.parse +def srl(rn, rm_or_imm5): + """SRL - Shift Right unsigned.""" + + # Rn <- (Unsigned) Rn >> Rm4..0 + # Rn <- (Unsigned) Rn >> imm5 + rn = rn >> rm_or_imm5 + + +@sbuild.parse +def sll(rn, rm_or_imm5): + """SLL - Shift Left unsigned.""" + + # Rn <- (Unsigned) Rn >> Rm4..0 + # Rn <- (Unsigned) Rn << imm5 + rn = rn << rm_or_imm5 + + +@sbuild.parse +def sll3(r0, rn, imm5): + """SLL3 - Shift Left unsigned, with 3 arguments.""" + + # R0 <- (Unsigned) Rn << imm5 + r0 = rn << imm5 + + +@sbuild.parse +def fsft(rn, rm): + "FSFT - Funnel shift.""" + + # Rn <- ((Rn||Rm)<<SAR5..0)63..32 + # Note: lowest Rm bits are discarded + + sar = SAR[:5].zeroExtend(32) + tmp_rn = rn << sar # Shift Rn + tmp_rm = rm >> (i32(32) - sar) # Shift Rm in the reverse order + rn = tmp_rn | tmp_rm # Concatenate registers + + +## Branch/Jump instructions + +@sbuild.parse +def bra(disp12): + """BRA - Branch to an address.""" + + # PC <- PC + SignExt((disp12)11..1||0) + dst = disp12 + PC = dst + take_jmp = ExprInt(1, 32) + ir.IRDst = dst + + +@sbuild.parse +def beqz(reg_test, disp8): + """BEQZ - Branch if the register stores zero.""" + + # if(Rn==0) PC <- PC +SignExt((disp8)7..1||0) + dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if reg_test else disp8 + take_jmp = ExprInt(0, 32) if reg_test else ExprInt(1, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bnez(reg_test, disp8): + """BNEZ - Branch if the register does not store zero.""" + + # if(Rn!=0) PC <- PC + SignExt((disp8)7..1||0) + dst = disp8 if "-"(reg_test, i32(0)) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if "-"(reg_test, i32(0)) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def beqi(reg_test, imm4, disp16): + """BEQI - Branch if the register stores imm4.""" + + # if(Rn==ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) + dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if "-"(reg_test, imm4) else disp16 + take_jmp = ExprInt(0, 32) if "-"(reg_test, imm4) else ExprInt(1, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bnei(reg_test, imm4, disp16): + """BNEI - Branch if the register does not store imm4.""" + + # if(Rn!=ZeroExt(imm4)) PC <- PC+SignExt((disp17)16..1||0) + dst = disp16 if "-"(reg_test, imm4) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if "-"(reg_test, imm4) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def blti(reg_test, imm4, disp16): + """BLTI - Branch if the register is lower than imm4.""" + + # if(Rn< ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) - (Signed comparison) + dst = disp16 if compute_s_inf(reg_test, imm4) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if compute_s_inf(reg_test, imm4) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bgei(reg_test, imm4, disp16): + """BGEI - Branch if the register is greater or equal to imm4.""" + + # if(Rn>=ZeroExt(imm4)) PC <- PC +SignExt((disp17)16..1||0) - (Signed comparison) + dst = disp16 if ">="(reg_test, imm4) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if ">="(reg_test, imm4) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def beq(rn, rm, disp16): + """BEQ - Branch if the two registers are equal.""" + + # if(Rn==Rm) PC <- PC +SignExt((disp17)16..1||0) + dst = ExprLoc(ir.get_next_break_loc_key(instr), 32) if "-"(rn, rm) else disp16 + take_jmp = ExprInt(0, 32) if "-"(rn, rm) else ExprInt(1, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bne(rn, rm, disp16): + """BNE - Branch if the two registers are not equal.""" + + # if(Rn!=Rm) PC <- PC +SignExt((disp17)16..1||0) + dst = disp16 if "-"(rn, rm) else ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) if "-"(rn, rm) else ExprInt(0, 32) + PC = dst + ir.IRDst = dst + + +@sbuild.parse +def bsr(disp): + """BSR - Branch to an address, and store the return address.""" + + # 16-bit variant: LP <- PC + 2; PC <- PC +SignExt((disp12)11..1||0) + # 32-bit variant: LP <- PC + 4; PC <- PC +SignExt((disp24)23..1||0) + + # Set LP + LP = ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) + + # Set PC according to the immediate size + dst = disp + PC = dst + ir.IRDst = dst + + +def jmp(ir, instr, reg_or_imm): + """JMP - Change PC to a register content or an immediate. + Note: the behavior in VLIW mode is not implemented""" + + take_jmp = ExprInt(1, 32) + + if isinstance(reg_or_imm, ExprId): + # PC <- Rm31..1||0 + new_PC = ExprAff(PC, reg_or_imm) + else: + # PC <- PC31..28||0000||(target24)23..1||0 + new_PC = ExprAff(PC, ExprOp("+", ExprOp("&", PC, ExprInt(0xF0000000, 32)), reg_or_imm)) + + return [new_PC, ExprAff(ir.IRDst, new_PC)], [] + +manual_functions["jmp"] = jmp + + +@sbuild.parse +def jsr(reg): + """JSR - Jump to the register, and store the return address.""" + + # LP <- PC + 2; PC <- Rm31..1||0 + LP = ExprLoc(ir.get_next_break_loc_key(instr), 32) + take_jmp = ExprInt(1, 32) + PC = reg + ir.IRDst = reg + + +@sbuild.parse +def ret(): + """RET - Return from a function call. + Note: the behavior in VLIW mode is not implemented""" + + # PC <- LP31..1||0 + dst = LP + PC = dst + ir.IRDst = dst + + +# Repeat instructions + +@sbuild.parse +def repeat(rn, disp17): + """REPEAT - This instruction repeats an instruction block. It sets the RPB, + RPE and RPC control registers.""" + + # RPB <- pc+4 // Repeat Begin + RPB = PC + i32(4) + # RPE <- pc+SignExt((disp17)16..1||0)) // Repeat End + RPE = PC + i32(disp17.arg & 0xFFFFFFFE) + # RPC <- Rn + RPC = rn + in_erepeat = ExprInt(0, 32) + + +@sbuild.parse +def erepeat(disp17): + """EREPEAT - This instruction repeats an instruction block. It sets the RPB + and RPE control registers. To distinguish from the repeat instruction, + the least significant bit in the RPE register (ELR) is set to 1.""" + + # RPB <- pc+4 // Repeat Begin + RPB = PC + i32(4) + # RPE <- pc+SignExt((disp17)16..1||1)) (EREPEAT) + RPE = PC + i32(disp17.arg + 1) + # RPC <- undefined + in_erepeat = ExprInt(1, 32) + + +## Control Instructions + +@sbuild.parse +def stc(reg, control_reg): + """STC - Copy a general-purpose register into a control register.""" + + # ControlReg(imm5) <- Rn + control_reg = reg + + +@sbuild.parse +def ldc(reg, control_reg): + """LDC - Copy a control register into a general-purpose register.""" + + # Rn <- ControlReg(imm5) + reg = control_reg + + +@sbuild.parse +def di(): + """DI - Disable Interrupt""" + + # PSW.IEC<-0 + PSW = PSW & i32(0xFFFFFFFE) # PSW.IEC: bit 0 + + +@sbuild.parse +def ei(): + """EI - Enable Interrupt""" + + # PSW.IEC<-1 + PSW = PSW ^ i32(0b1) # PSW.IEC: bit 0 + + +@sbuild.parse +def reti(): + """RETI - Return from the exception/interrupt handler. + Note: the behavior in VLIW mode is not implemented""" + + #if (PSW.NMI==1) { + # PC <- NPC31..1 || 0; PSW.NMI<-0; + #} else { + # PC <- EPC31..1 || 0; + # PSW.UMC <- PSW.UMP; PSW.IEC <- PSW.IEP + #} + + # PSW.NMI == bit 9 + NMI_mask = i32(1 << 9) + + # PSW.UMP == bit 3 + # PSW.IEP == bit 1 + UMP_IEP_mask = i32((1 << 3) ^ (1 << 1)) + + # PSW.UMC == bit 2 + # PSW.IEC == bit 0 + UMC_IEC_mask = (PSW & UMP_IEP_mask) >> i32(1) + + # Get PSW.NMI + PSW_NMI = (PSW & NMI_mask) >> i32(9) + + # Set PC + dst = NPC & i32(0xFFFFFFFE) if PSW_NMI else EPC & i32(0xFFFFFFFE) + PC = dst + + # Set flags + PSW = PSW ^ NMI_mask if PSW_NMI else PSW ^ UMC_IEC_mask + + ir.IRDst = dst + + +@sbuild.parse +def swi(imm2): + """SWI - Software Interrupt""" + + # if(imm2==0) EXC.SIP0 <- 1 + # else if (imm2==1) EXC.SIP1 <- 1 + # else if (imm2==2) EXC.SIP2 <- 1 + # else if (imm2==3) EXC.SIP3 <- 1 + + # EXC.SIP0 == bit 4 + # EXC.SIP1 == bit 5 + # EXC.SIP2 == bit 6 + # EXC.SIP3 == bit 7 + + EXC = EXC ^ (i32(1) << (i32(4) + imm2)) + + +# Note: the following instructions can't be implemented +manual_functions["halt"] = mep_nop +manual_functions["sleep"] = mep_nop +manual_functions["break"] = mep_nop +manual_functions["syncm"] = mep_nop +manual_functions["stcb"] = mep_nop_2_args +manual_functions["ldcb"] = mep_nop_2_args + + +### Bit manipulation instruction option + +@sbuild.parse +def bsetm(rm_deref, imm3): + """BSETM - Bit Set Memory""" + + # MemByte(Rm) <- MemByte(Rm) or (1<<imm3) + mem8[rm_deref.arg] = ExprOp("|", mem8[rm_deref.arg], (i8(1) << imm3[:8])) + + +@sbuild.parse +def bclrm(rm_deref, imm3): + """BCLRM - Bit Clear Memory""" + + # MemByte(Rm) <- MemByte(Rm) and ~(1<<imm3) + shift = ExprOp("<<", i8(1), imm3[:8]) + mem8[rm_deref.arg] = ExprOp("&", mem8[rm_deref.arg], shift.__invert__()) + + +@sbuild.parse +def bnotm(rm_deref, imm3): + """BNOTM - Bit Not Memory""" + + # MemByte(Rm) <- MemByte(Rm) xor (1<<imm3) + mem8[rm_deref.arg] = ExprOp("^", mem8[rm_deref.arg], (i8(1) << imm3[:8])) + + +@sbuild.parse +def btstm(r0, rm_deref, imm3): + """BTSTM - Bit Test Memory""" + + # R0 <- ZeroExt( MemByte(Rm) and (1<<imm3) ) + r0 = ExprOp("&", mem8[rm_deref.arg], i8(1) << imm3[:8]).zeroExtend(32) + + +@sbuild.parse +def tas(rn, rm_deref): + """TAS - Load And Set""" + + # temp <- Rm; Rn <- ZeroExt(MemByte(temp)); MemByte(temp) <- 1 + temp = rm_deref + rn = mem8[temp.arg].zeroExtend(32) + mem8[temp.arg] = i8(1) + + +### Data cache option + +# Note: the following instruction can't be implemented +manual_functions["cache"] = mep_nop_2_args + + +### 32-bit multiply instruction option + +@sbuild.parse +def mul(rn, rm): + """MUL - Signed 32-bit multiplication""" + + # HI||LO <- Rn * Rm (Signed) + result = rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + + +@sbuild.parse +def mulu(rn, rm): + """MUL - Unsigned 32-bit multiplication""" + + # HI||LO <- Rn * Rm (Unsigned) + result = rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[0:32] + + +@sbuild.parse +def mulr(rn, rm): + """MULR - Signed 32-bit multiplication & store LO in Rn""" + + # HI||LO <- Rn * Rm; Rn <- LO (Signed) + result = rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +@sbuild.parse +def mulru(rn, rm): + """MULRU - Unsigned 32-bit multiplication & store LO in Rn""" + + # HI||LO <- Rn * Rm; Rn <- LO (Unsigned) + result = rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +@sbuild.parse +def madd(rn, rm): + """MADD - Signed 32-bit multiplication, adding results to HI & LO registers""" + + # HI||LO <- HI||LO + Rn*Rm (Signed) + result = (HI << i32(32)).signExtend(64) + LO.signExtend(64) + rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + + +@sbuild.parse +def maddu(rn, rm): + """MADDU - Unsigned 32-bit multiplication, adding results to HI & LO registers""" + + # HI||LO <- HI||LO + Rn*Rm (Unsigned) + result = (HI << i32(32)).zeroExtend(64) + LO.zeroExtend(64) + rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + + +@sbuild.parse +def maddr(rn, rm): + """MADDR - Signed 32-bit multiplication, adding results to HI & LO registers & storing LO in Rn""" + + # HI||LO <- HI||LO + Rn*Rm; Rn <- LO (Signed) + result = (HI << i32(32)).signExtend(64) + LO.signExtend(64) + rn.signExtend(64) * rm.signExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +@sbuild.parse +def maddru(rn, rm): + """MADDRU - Unsigned 32-bit multiplication, adding results to HI & LO registers & storing LO in Rn""" + + # HI||LO <- HI||LO + Rn*Rm; Rn <- LO (Unsigned) + result = (HI << i32(32)).zeroExtend(64) + LO.zeroExtend(64) + rn.zeroExtend(64) * rm.zeroExtend(64) # expand registers size + HI = result[32:64] + LO = result[:32] + rn = result[:32] + + +### 32-bit divide instruction option + +@sbuild.parse +def div(rn, rm): + """DIV - Signed division""" + + # LO <- Rn / Rm, HI <- Rn % Rm (Signed) + + # Mask sign bits + sign_mask = i32(0x80000000) + sign_rn = rn & sign_mask + sign_rm = rm & sign_mask + + # Check if both numbers are positive or negative + are_both_neg = sign_rn & sign_rm + are_both_pos = "=="(are_both_neg, sign_mask) + + # Invert both numbers + rn_inv = ~rn + i32(1) + rm_inv = ~rm + i32(1) + + # Used to delay the arithmetic computations + tmp_rm = rm if rm else i32(1) + tmp_rm_inv = rm_inv if rm_inv else i32(1) + + # Results if only rn, or rm is negative + LO_rn_neg = (~(rn_inv / tmp_rm) + i32(1)) if sign_rn else (~(rn / tmp_rm_inv) + i32(1)) + HI_rn_neg = (~(rn_inv % tmp_rm) + i32(1)) if sign_rn else (~(rn % tmp_rm_inv) + i32(1)) + + # Results if both numbers are positive + LO_pos = rn / tmp_rm if are_both_pos else LO_rn_neg + HI_pos = rn % tmp_rm if are_both_pos else HI_rn_neg + + # Results if both numbers are negative + LO_neg = rn_inv / tmp_rm_inv if are_both_neg else LO_pos + HI_neg = rn_inv % tmp_rm_inv if are_both_neg else HI_pos + + # Results if rm is equal to zero + LO = LO_neg if rm else LO + HI = HI_neg if rm else HI + + exception_flags = i32(0) if rm else i32(EXCEPT_DIV_BY_ZERO) + + +@sbuild.parse +def divu(rn, rm): + """DIVU - Unsigned division""" + + # LO <- Rn / Rm, HI <- Rn % Rm (Unsigned) + + tmp_rm = rm if rm else i32(1) # used to delay the arithmetic computations + LO = rn / tmp_rm if rm else LO + HI = rn % tmp_rm if rm else HI + + exception_flags = i32(0) if rm else i32(EXCEPT_DIV_BY_ZERO) + + +### Debug function option + +@sbuild.parse +def dret(): + """DRET - Debug Exception Return""" + + # PC <- DEPC; DBG.DM <- 0 + PC = DEPC + DBG = DBG & i32(0xFFFFBFFF) # DBG.DM: bit 15 + + +@sbuild.parse +def dbreak(): + """DBREAK - Debug break""" + + # The DBG.DBP bit becomes 1 + DBG = DBG ^ i32(0b10) # DBG.DBP: bit 2 + + +### Leading zero instruction option + +@sbuild.parse +def ldz(rn, rm): + """LDZ - Count Leading Zeroes + + Note: this implementation is readable, yet slow. Each bit are tested + individually, and the results are propagated to other bits. + + Here is the commented implementation for 4-bit integers: + rm = 0b0001 + + # Invert the value + reversed_rm = ~rm + -> reversed_rm = 0b1110 + + # Test bits individually + b3 = (reversed_rm & i32(2**3)) >> i32(3) if reversed_rm else i32(0) + -> b3 = (0b1110 & 0b1000 >> 3) = 1 + + b2 = (reversed_rm & i32(2**2)) >> i32(2) if b3 else i32(0) + -> b2 = (0b1110 & 0b0100 >> 2) = 1 + + b1 = (reversed_rm & i32(2**1)) >> i32(1) if b2 else i32(0) + -> b1 = (0b1110 & 0b0010 >> 1) = 1 + + b0 = (reversed_rm & i32(2**0)) >> i32(0) if b1 else i32(0) + -> b0 = (0b1110 & 0b0001 >> 0) = 0 + + # Sum all partial results + rn = b3 + b2 + b1 + b0 + -> rn = 1 + 1 + 1 + 0 = 3 + """ + + # Rn <- LeadingZeroDetect(Rm) + + # Invert the value + reversed_rm = ~rm + + # Test bits individually + b31 = (reversed_rm & i32(2**31)) >> i32(31) if reversed_rm else i32(0) + b30 = (reversed_rm & i32(2**30)) >> i32(30) if b31 else i32(0) + b29 = (reversed_rm & i32(2**29)) >> i32(29) if b30 else i32(0) + b28 = (reversed_rm & i32(2**28)) >> i32(28) if b29 else i32(0) + b27 = (reversed_rm & i32(2**27)) >> i32(27) if b28 else i32(0) + b26 = (reversed_rm & i32(2**26)) >> i32(26) if b27 else i32(0) + b25 = (reversed_rm & i32(2**25)) >> i32(25) if b26 else i32(0) + b24 = (reversed_rm & i32(2**24)) >> i32(24) if b25 else i32(0) + b23 = (reversed_rm & i32(2**23)) >> i32(23) if b24 else i32(0) + b22 = (reversed_rm & i32(2**22)) >> i32(22) if b23 else i32(0) + b21 = (reversed_rm & i32(2**21)) >> i32(21) if b22 else i32(0) + b20 = (reversed_rm & i32(2**20)) >> i32(20) if b21 else i32(0) + b19 = (reversed_rm & i32(2**19)) >> i32(19) if b20 else i32(0) + b18 = (reversed_rm & i32(2**18)) >> i32(18) if b19 else i32(0) + b17 = (reversed_rm & i32(2**17)) >> i32(17) if b18 else i32(0) + b16 = (reversed_rm & i32(2**16)) >> i32(16) if b17 else i32(0) + b15 = (reversed_rm & i32(2**15)) >> i32(15) if b16 else i32(0) + b14 = (reversed_rm & i32(2**14)) >> i32(14) if b15 else i32(0) + b13 = (reversed_rm & i32(2**13)) >> i32(13) if b14 else i32(0) + b12 = (reversed_rm & i32(2**12)) >> i32(12) if b13 else i32(0) + b11 = (reversed_rm & i32(2**11)) >> i32(11) if b12 else i32(0) + b10 = (reversed_rm & i32(2**10)) >> i32(10) if b11 else i32(0) + b09 = (reversed_rm & i32(2 ** 9)) >> i32(9) if b10 else i32(0) + b08 = (reversed_rm & i32(2 ** 8)) >> i32(8) if b09 else i32(0) + b07 = (reversed_rm & i32(2 ** 7)) >> i32(7) if b08 else i32(0) + b06 = (reversed_rm & i32(2 ** 6)) >> i32(6) if b07 else i32(0) + b05 = (reversed_rm & i32(2 ** 5)) >> i32(5) if b06 else i32(0) + b04 = (reversed_rm & i32(2 ** 4)) >> i32(4) if b05 else i32(0) + b03 = (reversed_rm & i32(2 ** 3)) >> i32(3) if b04 else i32(0) + b02 = (reversed_rm & i32(2 ** 2)) >> i32(2) if b03 else i32(0) + b01 = (reversed_rm & i32(2 ** 1)) >> i32(1) if b02 else i32(0) + b00 = (reversed_rm & i32(2 ** 0)) >> i32(0) if b01 else i32(0) + + # Sum all partial results + rn = b31 + b30 + b29 + b28 + b27 + b26 + b25 + b24 + b23 + b22 + b21 + b20 \ + + b19 + b18 + b17 + b16 + b15 + b14 + b13 + b12 + b11 + b10 + b09 + b08 \ + + b07 + b06 + b05 + b04 + b03 + b02 + b01 + b00 + + +### Coprocessor option + +# Note: these instructions are implemented when needed + +# SWCP - Store Word to memory from a coprocessor register +# MemWord(Rm31..2||00) <- CRn 31..0 +manual_functions["swcp"] = sw + + +# LWCP - Load Word from memory to a coprocessor register +# CRn <- MemWord(Rm31..2||00) +manual_functions["lwcp"] = lw + + +@sbuild.parse +def smcp(reg_src, deref_dst): + """SMCP - Store Word to memory from a coprocessor register""" + + # MemDword(Rm31..3||000) <- CRn + mem32[deref_dst.arg & i32(0xFFFFFFF8)] = reg_src + + +@sbuild.parse +def lmcp(reg_dst, deref_src): + """LMCP - Load Word from memory to a coprocessor register""" + + # CRn <- MemDword(Rm31..3||000) + reg_dst = mem32[deref_src.arg & i32(0xFFFFFFF8)] + + +@sbuild.parse +def swcpi(reg_src, deref_dst): + """SWCPI - Store Word to memory, and increment the address""" + + # MemWord(Rm31..2||00) <- CRn 31..0; Rm<-Rm+4 + mem32[deref_dst.arg & i32(0xFFFFFFFC)] = reg_src + deref_dst.arg = deref_dst.arg + i32(4) + + +@sbuild.parse +def lwcpi(reg_dst, deref_src): + """LWCPI - Load Word from memory, and increment the address""" + + # CRn <- MemWord(Rm31..2||00); Rm<-Rm+4 + reg_dst = mem32[deref_src.arg & i32(0xFFFFFFFC)] + deref_src.arg = deref_src.arg + i32(4) + + +@sbuild.parse +def smcpi(reg_src, deref_dst): + """SMCPI - Store Word to memory, and increment the address""" + + # MemDword(Rm31..3||000) <- CRn; Rm<-Rm+8 + mem32[deref_dst.arg & i32(0xFFFFFFF8)] = reg_src + deref_dst.arg = deref_dst.arg + i32(8) + + +@sbuild.parse +def lmcpi(reg_dst, deref_src): + """LMCPI - Load Word from memory, and increment the address""" + + # CRn <- MemDword(Rm31..3||000); Rm<-Rm+8 + reg_dst = mem32[deref_src.arg & i32(0xFFFFFFFC)] + deref_src.arg = deref_src.arg + i32(8) + + +### IR MeP definitions + +def get_mnemo_expr(ir, instr, *args): + """Simplify getting the IR from a miasm instruction.""" + + if instr.name.lower() in sbuild.functions: + mnemo_func = sbuild.functions[instr.name.lower()] + else: + mnemo_func = manual_functions[instr.name.lower()] + + ir, extra_ir = mnemo_func(ir, instr, *args) + return ir, extra_ir + + +class ir_mepb(IntermediateRepresentation): + """Toshiba MeP miasm IR - Big Endian + + It transforms an instructon into an IR. + """ + + def __init__(self, loc_db=None): + IntermediateRepresentation.__init__(self, mn_mep, "b", loc_db) + self.pc = mn_mep.getpc() + self.sp = mn_mep.getsp() + self.IRDst = ExprId("IRDst", 32) + self.addrsize = 32 + + def get_ir(self, instr): + """Get the IR from a miasm instruction.""" + + instr_ir, extra_ir = get_mnemo_expr(self, instr, *instr.args) + + return instr_ir, extra_ir + + def get_next_break_loc_key(self, instr): + """Returns a new label that identifies where the instuction is going. + + Note: it eases linking IR blocs + """ + + l = self.loc_db.get_or_create_offset_location(instr.offset + instr.l) + return l + + +class ir_mepl(ir_mepb): + """Toshiba MeP miasm IR - Little Endian""" + + def __init__(self, loc_db=None): + IntermediateRepresentation.__init__(self, mn_mep, "l", loc_db) + self.pc = mn_mep.getpc() + self.sp = mn_mep.getsp() + self.IRDst = ExprId("IRDst", 32) diff --git a/miasm2/jitter/arch/JitCore_mep.c b/miasm2/jitter/arch/JitCore_mep.c new file mode 100644 index 00000000..e63fa97b --- /dev/null +++ b/miasm2/jitter/arch/JitCore_mep.c @@ -0,0 +1,618 @@ +// Inspired from JitCore_mep.c + +#include <Python.h> +#include "structmember.h" +#include <stdint.h> + +#include <inttypes.h> +#include "../queue.h" +#include "../vm_mngr.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "JitCore_mep.h" + + +reg_dict gpreg_dict[] = { + {.name = "R0", .offset = offsetof(vm_cpu_t, R0)}, + {.name = "R1", .offset = offsetof(vm_cpu_t, R1)}, + {.name = "R2", .offset = offsetof(vm_cpu_t, R2)}, + {.name = "R3", .offset = offsetof(vm_cpu_t, R3)}, + {.name = "R4", .offset = offsetof(vm_cpu_t, R4)}, + {.name = "R5", .offset = offsetof(vm_cpu_t, R5)}, + {.name = "R6", .offset = offsetof(vm_cpu_t, R6)}, + {.name = "R7", .offset = offsetof(vm_cpu_t, R7)}, + {.name = "R8", .offset = offsetof(vm_cpu_t, R8)}, + {.name = "R9", .offset = offsetof(vm_cpu_t, R9)}, + {.name = "R10", .offset = offsetof(vm_cpu_t, R10)}, + {.name = "R11", .offset = offsetof(vm_cpu_t, R11)}, + {.name = "R12", .offset = offsetof(vm_cpu_t, R12)}, + {.name = "TP", .offset = offsetof(vm_cpu_t, TP)}, + {.name = "GP", .offset = offsetof(vm_cpu_t, GP)}, + {.name = "SP", .offset = offsetof(vm_cpu_t, SP)}, + + {.name = "PC", .offset = offsetof(vm_cpu_t, PC)}, + {.name = "LP", .offset = offsetof(vm_cpu_t, LP)}, + {.name = "SAR", .offset = offsetof(vm_cpu_t, SAR)}, + {.name = "S3", .offset = offsetof(vm_cpu_t, S3)}, + {.name = "RPB", .offset = offsetof(vm_cpu_t, RPB)}, + {.name = "RPE", .offset = offsetof(vm_cpu_t, RPE)}, + {.name = "RPC", .offset = offsetof(vm_cpu_t, RPC)}, + {.name = "HI", .offset = offsetof(vm_cpu_t, HI)}, + {.name = "LO", .offset = offsetof(vm_cpu_t, LO)}, + {.name = "S9", .offset = offsetof(vm_cpu_t, S9)}, + {.name = "S10", .offset = offsetof(vm_cpu_t, S10)}, + {.name = "S11", .offset = offsetof(vm_cpu_t, S11)}, + {.name = "MB0", .offset = offsetof(vm_cpu_t, MB0)}, + {.name = "ME0", .offset = offsetof(vm_cpu_t, ME0)}, + {.name = "MB1", .offset = offsetof(vm_cpu_t, MB1)}, + {.name = "ME1", .offset = offsetof(vm_cpu_t, ME1)}, + {.name = "PSW", .offset = offsetof(vm_cpu_t, PSW)}, + {.name = "ID", .offset = offsetof(vm_cpu_t, ID)}, + {.name = "TMP", .offset = offsetof(vm_cpu_t, TMP)}, + {.name = "EPC", .offset = offsetof(vm_cpu_t, EPC)}, + {.name = "EXC", .offset = offsetof(vm_cpu_t, EXC)}, + {.name = "CFG", .offset = offsetof(vm_cpu_t, CFG)}, + {.name = "S22", .offset = offsetof(vm_cpu_t, S22)}, + {.name = "NPC", .offset = offsetof(vm_cpu_t, NPC)}, + {.name = "DBG", .offset = offsetof(vm_cpu_t, DBG)}, + {.name = "DEPC", .offset = offsetof(vm_cpu_t, DEPC)}, + {.name = "OPT", .offset = offsetof(vm_cpu_t, OPT)}, + {.name = "RCFG", .offset = offsetof(vm_cpu_t, RCFG)}, + {.name = "CCFG", .offset = offsetof(vm_cpu_t, CCFG)}, + {.name = "S29", .offset = offsetof(vm_cpu_t, S29)}, + {.name = "S30", .offset = offsetof(vm_cpu_t, S30)}, + {.name = "S31", .offset = offsetof(vm_cpu_t, S31)}, + {.name = "S32", .offset = offsetof(vm_cpu_t, S32)}, + {.name = "take_jmp", .offset = offsetof(vm_cpu_t, take_jmp)}, + {.name = "last_addr", .offset = offsetof(vm_cpu_t, last_addr)}, + {.name = "is_repeat_end", .offset = offsetof(vm_cpu_t, is_repeat_end)}, + + {.name = "PC_end", .offset = offsetof(vm_cpu_t, PC_end)}, + {.name = "RPE_instr_count", .offset = offsetof(vm_cpu_t, RPE_instr_count)}, + {.name = "RPC_current", .offset = offsetof(vm_cpu_t, RPC_current)}, + +}; + +/************************** JitCpu object **************************/ + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(R0); + get_reg(R1); + get_reg(R2); + get_reg(R3); + get_reg(R4); + get_reg(R5); + get_reg(R6); + get_reg(R7); + get_reg(R8); + get_reg(R9); + get_reg(R10); + get_reg(R11); + get_reg(R12); + get_reg(TP); + get_reg(GP); + get_reg(SP); + + get_reg(PC); + get_reg(LP); + get_reg(SAR); + get_reg(S3); + get_reg(RPB); + get_reg(RPE); + get_reg(RPC); + get_reg(HI); + get_reg(LO); + get_reg(S9); + get_reg(S10); + get_reg(S11); + get_reg(MB0); + get_reg(ME0); + get_reg(MB1); + get_reg(ME1); + get_reg(PSW); + get_reg(ID); + get_reg(TMP); + get_reg(EPC); + get_reg(EXC); + get_reg(CFG); + get_reg(S22); + get_reg(NPC); + get_reg(DBG); + get_reg(DEPC); + get_reg(OPT); + get_reg(RCFG); + get_reg(CCFG); + get_reg(S29); + get_reg(S30); + get_reg(S31); + get_reg(S32); + + get_reg(PC_end); + get_reg(RPE_instr_count); + get_reg(RPC_current); + + + return dict; +} + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + uint64_t val; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + return NULL; + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + if(!PyString_Check(d_key)) + RAISE(PyExc_TypeError, "key must be str"); + + PyGetInt(d_value, val); + + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(PyString_AsString(d_key), gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unkown key: %s\n", PyString_AsString(d_key)); + RAISE(PyExc_ValueError, "unkown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(vm_cpu_t)); + + Py_INCREF(Py_None); + return Py_None; + +} + +void dump_gpregs(vm_cpu_t* vmcpu) +{ + printf("R0 %.4"PRIX32" ", vmcpu->R0); + printf("R1 %.4"PRIX32" ", vmcpu->R1); + printf("R2 %.4"PRIX32" ", vmcpu->R2); + printf("R3 %.4"PRIX32" ", vmcpu->R3); + printf("R4 %.4"PRIX32" ", vmcpu->R4); + printf("R5 %.4"PRIX32" ", vmcpu->R5); + printf("R6 %.4"PRIX32" ", vmcpu->R6); + printf("R7 %.4"PRIX32" ", vmcpu->R7); + printf("R8 %.4"PRIX32" ", vmcpu->R8); + printf("R9 %.4"PRIX32" ", vmcpu->R9); + printf("R10 %.4"PRIX32" ", vmcpu->R10); + printf("R11 %.4"PRIX32" ", vmcpu->R11); + printf("R12 %.4"PRIX32" ", vmcpu->R12); + printf("TP %.4"PRIX32" ", vmcpu->TP); + printf("GP %.4"PRIX32" ", vmcpu->GP); + printf("SP %.4"PRIX32" ", vmcpu->SP); + printf("\n"); +} + + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + vm_cpu_t* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint64_t i; + + if (!PyArg_ParseTuple(args, "O", &item1)) + return NULL; + + PyGetInt(item1, i); + + ((vm_cpu_t*)self->cpu)->exception_flags = i; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((vm_cpu_t*)self->cpu)->exception_flags)); +} + + + + + +void check_automod(JitCpu* jitcpu, uint64_t addr, uint64_t size) +{ + PyObject *result; + + if (!(((VmMngr*)jitcpu->pyvm)->vm_mngr.exception_flags & EXCEPT_CODE_AUTOMOD)) + return; + result = PyObject_CallMethod(jitcpu->jitter, "automod_cb", "LL", addr, size); + Py_DECREF(result); + +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); + check_automod(jitcpu, addr, 8); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); + check_automod(jitcpu, addr, 16); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); + check_automod(jitcpu, addr, 32); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); + check_automod(jitcpu, addr, 64); +} + + +PyObject* vm_set_mem(JitCpu *self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_buffer; + Py_ssize_t py_length; + + char * buffer; + uint64_t size; + uint64_t addr; + int ret = 0x1337; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_buffer)) + return NULL; + + PyGetInt(py_addr, addr); + + if(!PyString_Check(py_buffer)) + RAISE(PyExc_TypeError,"arg must be str"); + + size = PyString_Size(py_buffer); + PyString_AsStringAndSize(py_buffer, &buffer, &py_length); + + ret = vm_write_mem(&(((VmMngr*)self->pyvm)->vm_mngr), addr, buffer, size); + if (ret < 0) + RAISE(PyExc_TypeError,"arg must be str"); + check_automod(self, addr, size*8); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, "X"}, + {"set_mem", (PyCFunction)vm_set_mem, METH_VARARGS, "X"}, + {"get_mem", (PyCFunction)vm_get_mem, METH_VARARGS, "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(vm_cpu_t)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc vm_cpu_t\n"); + exit(0); + } + return 0; +} + +getset_reg_u32(R0); +getset_reg_u32(R1); +getset_reg_u32(R2); +getset_reg_u32(R3); +getset_reg_u32(R4); +getset_reg_u32(R5); +getset_reg_u32(R6); +getset_reg_u32(R7); +getset_reg_u32(R8); +getset_reg_u32(R9); +getset_reg_u32(R10); +getset_reg_u32(R11); +getset_reg_u32(R12); +getset_reg_u32(TP); +getset_reg_u32(GP); +getset_reg_u32(SP); + +getset_reg_u32(PC); +getset_reg_u32(LP); +getset_reg_u32(SAR); +getset_reg_u32(S3); +getset_reg_u32(RPB); +getset_reg_u32(RPE); +getset_reg_u32(RPC); +getset_reg_u32(HI); +getset_reg_u32(LO); +getset_reg_u32(S9); +getset_reg_u32(S10); +getset_reg_u32(S11); +getset_reg_u32(MB0); +getset_reg_u32(ME0); +getset_reg_u32(MB1); +getset_reg_u32(ME1); +getset_reg_u32(PSW); +getset_reg_u32(ID); +getset_reg_u32(TMP); +getset_reg_u32(EPC); +getset_reg_u32(EXC); +getset_reg_u32(CFG); +getset_reg_u32(S22); +getset_reg_u32(NPC); +getset_reg_u32(DBG); +getset_reg_u32(DEPC); +getset_reg_u32(OPT); +getset_reg_u32(RCFG); +getset_reg_u32(CCFG); +getset_reg_u32(S29); +getset_reg_u32(S30); +getset_reg_u32(S31); +getset_reg_u32(S32); + +getset_reg_u32(PC_end); +getset_reg_u32(RPE_instr_count); +getset_reg_u32(RPC_current); + + + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + get_reg_off(exception_flags); + + get_reg_off(R0); + get_reg_off(R1); + get_reg_off(R2); + get_reg_off(R3); + get_reg_off(R4); + get_reg_off(R5); + get_reg_off(R6); + get_reg_off(R7); + get_reg_off(R8); + get_reg_off(R9); + get_reg_off(R10); + get_reg_off(R11); + get_reg_off(R12); + get_reg_off(TP); + get_reg_off(GP); + get_reg_off(SP); + + get_reg_off(PC); + get_reg_off(LP); + get_reg_off(SAR); + get_reg_off(S3); + get_reg_off(RPB); + get_reg_off(RPE); + get_reg_off(RPC); + get_reg_off(HI); + get_reg_off(LO); + get_reg_off(S9); + get_reg_off(S10); + get_reg_off(S11); + get_reg_off(MB0); + get_reg_off(ME0); + get_reg_off(MB1); + get_reg_off(ME1); + get_reg_off(PSW); + get_reg_off(ID); + get_reg_off(TMP); + get_reg_off(EPC); + get_reg_off(EXC); + get_reg_off(CFG); + get_reg_off(S22); + get_reg_off(NPC); + get_reg_off(DBG); + get_reg_off(DEPC); + get_reg_off(OPT); + get_reg_off(RCFG); + get_reg_off(CCFG); + get_reg_off(S29); + get_reg_off(S30); + get_reg_off(S31); + get_reg_off(S32); + + get_reg_off(PC_end); + get_reg_off(RPE_instr_count); + get_reg_off(RPC_current); + + + return dict; +} + + + + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + {"R0" , (getter)JitCpu_get_R0 , (setter)JitCpu_set_R0 , "R0" , NULL}, + {"R1" , (getter)JitCpu_get_R1 , (setter)JitCpu_set_R1 , "R1" , NULL}, + {"R2" , (getter)JitCpu_get_R2 , (setter)JitCpu_set_R2 , "R2" , NULL}, + {"R3" , (getter)JitCpu_get_R3 , (setter)JitCpu_set_R3 , "R3" , NULL}, + {"R4" , (getter)JitCpu_get_R4 , (setter)JitCpu_set_R4 , "R4" , NULL}, + {"R5" , (getter)JitCpu_get_R5 , (setter)JitCpu_set_R5 , "R5" , NULL}, + {"R6" , (getter)JitCpu_get_R6 , (setter)JitCpu_set_R6 , "R6" , NULL}, + {"R7" , (getter)JitCpu_get_R7 , (setter)JitCpu_set_R7 , "R7" , NULL}, + {"R8" , (getter)JitCpu_get_R8 , (setter)JitCpu_set_R8 , "R8" , NULL}, + {"R9" , (getter)JitCpu_get_R9 , (setter)JitCpu_set_R9 , "R9" , NULL}, + {"R10" , (getter)JitCpu_get_R10 , (setter)JitCpu_set_R10 , "R10" , NULL}, + {"R11" , (getter)JitCpu_get_R11 , (setter)JitCpu_set_R11 , "R11" , NULL}, + {"R12" , (getter)JitCpu_get_R12 , (setter)JitCpu_set_R12 , "R12" , NULL}, + {"TP" , (getter)JitCpu_get_TP , (setter)JitCpu_set_TP , "TP" , NULL}, + {"GP" , (getter)JitCpu_get_GP , (setter)JitCpu_set_GP , "GP" , NULL}, + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + {"LP" , (getter)JitCpu_get_LP , (setter)JitCpu_set_LP , "LP" , NULL}, + {"SAR" , (getter)JitCpu_get_SAR , (setter)JitCpu_set_SAR , "SAR" , NULL}, + {"S3" , (getter)JitCpu_get_S3 , (setter)JitCpu_set_S3 , "S3" , NULL}, + {"RPB" , (getter)JitCpu_get_RPB , (setter)JitCpu_set_RPB , "RPB" , NULL}, + {"RPE" , (getter)JitCpu_get_RPE , (setter)JitCpu_set_RPE , "RPE" , NULL}, + {"RPC" , (getter)JitCpu_get_RPC , (setter)JitCpu_set_RPC , "RPC" , NULL}, + {"HI" , (getter)JitCpu_get_HI , (setter)JitCpu_set_HI , "HI" , NULL}, + {"LO" , (getter)JitCpu_get_LO , (setter)JitCpu_set_LO , "LO" , NULL}, + {"S9" , (getter)JitCpu_get_S9 , (setter)JitCpu_set_S9 , "S9" , NULL}, + {"S10" , (getter)JitCpu_get_S10 , (setter)JitCpu_set_S10 , "S10" , NULL}, + {"S11" , (getter)JitCpu_get_S11 , (setter)JitCpu_set_S11 , "S11" , NULL}, + {"MB0" , (getter)JitCpu_get_MB0 , (setter)JitCpu_set_MB0 , "MB0" , NULL}, + {"ME0" , (getter)JitCpu_get_ME0 , (setter)JitCpu_set_ME0 , "ME0" , NULL}, + {"MB1" , (getter)JitCpu_get_MB1 , (setter)JitCpu_set_MB1 , "MB1" , NULL}, + {"ME1" , (getter)JitCpu_get_ME1 , (setter)JitCpu_set_ME1 , "ME1" , NULL}, + {"PSW" , (getter)JitCpu_get_PSW , (setter)JitCpu_set_PSW , "PSW" , NULL}, + {"ID" , (getter)JitCpu_get_ID , (setter)JitCpu_set_ID , "ID" , NULL}, + {"TMP" , (getter)JitCpu_get_TMP , (setter)JitCpu_set_TMP , "TMP" , NULL}, + {"EPC" , (getter)JitCpu_get_EPC , (setter)JitCpu_set_EPC , "EPC" , NULL}, + {"EXC" , (getter)JitCpu_get_EXC , (setter)JitCpu_set_EXC , "EXC" , NULL}, + {"CFG" , (getter)JitCpu_get_CFG , (setter)JitCpu_set_CFG , "CFG" , NULL}, + {"S22" , (getter)JitCpu_get_S22 , (setter)JitCpu_set_S22 , "S22" , NULL}, + {"NPC" , (getter)JitCpu_get_NPC , (setter)JitCpu_set_NPC , "NPC" , NULL}, + {"DBG" , (getter)JitCpu_get_DBG , (setter)JitCpu_set_DBG , "DBG" , NULL}, + {"DEPC" , (getter)JitCpu_get_DEPC , (setter)JitCpu_set_DEPC , "DEPC" , NULL}, + {"OPT" , (getter)JitCpu_get_OPT , (setter)JitCpu_set_OPT , "OPT" , NULL}, + {"RCFG" , (getter)JitCpu_get_RCFG , (setter)JitCpu_set_RCFG , "RCFG" , NULL}, + {"CCFG" , (getter)JitCpu_get_CCFG , (setter)JitCpu_set_CCFG , "CCFG" , NULL}, + {"S29" , (getter)JitCpu_get_S29 , (setter)JitCpu_set_S29 , "S29" , NULL}, + {"S30" , (getter)JitCpu_get_S30 , (setter)JitCpu_set_S30 , "S30" , NULL}, + {"S31" , (getter)JitCpu_get_S31 , (setter)JitCpu_set_S31 , "S31" , NULL}, + {"S32" , (getter)JitCpu_get_S32 , (setter)JitCpu_set_S32 , "S32" , NULL}, + + {"PC_end" , (getter)JitCpu_get_PC_end , (setter)JitCpu_set_PC_end , "PC_end" , NULL}, + {"RPE_instr_count" , (getter)JitCpu_get_RPE_instr_count , (setter)JitCpu_set_RPE_instr_count , "RPE_instr_count" , NULL}, + {"RPC_current" , (getter)JitCpu_get_RPC_current , (setter)JitCpu_set_RPC_current , "RPC_current" , NULL}, + + + + {NULL} /* Sentinel */ +}; + + + +static PyTypeObject JitCpuType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "JitCore_mep.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_mep_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + +static PyObject *JitCore_mep_Error; + +PyMODINIT_FUNC +initJitCore_mep(void) +{ + PyObject *m; + + if (PyType_Ready(&JitCpuType) < 0) + return; + + m = Py_InitModule("JitCore_mep", JitCore_mep_Methods); + if (m == NULL) + return; + + JitCore_mep_Error = PyErr_NewException("JitCore_mep.error", NULL, NULL); + Py_INCREF(JitCore_mep_Error); + PyModule_AddObject(m, "error", JitCore_mep_Error); + + Py_INCREF(&JitCpuType); + PyModule_AddObject(m, "JitCpu", (PyObject *)&JitCpuType); + +} diff --git a/miasm2/jitter/arch/JitCore_mep.h b/miasm2/jitter/arch/JitCore_mep.h new file mode 100644 index 00000000..47075ba5 --- /dev/null +++ b/miasm2/jitter/arch/JitCore_mep.h @@ -0,0 +1,77 @@ +// Inspired from JitCore_msp430.h + +typedef struct { + /* miasm2 flags */ + uint32_t exception_flags; + + /* gpregs */ + uint32_t R0; + uint32_t R1; + uint32_t R2; + uint32_t R3; + uint32_t R4; + uint32_t R5; + uint32_t R6; + uint32_t R7; + uint32_t R8; + uint32_t R9; + uint32_t R10; + uint32_t R11; + uint32_t R12; + uint32_t TP; + uint32_t GP; + uint32_t SP; + + /* csregs */ + uint32_t PC; + uint32_t LP; + uint32_t SAR; + uint32_t S3; + uint32_t RPB; + uint32_t RPE; + uint32_t RPC; + uint32_t HI; + uint32_t LO; + uint32_t S9; + uint32_t S10; + uint32_t S11; + uint32_t MB0; + uint32_t ME0; + uint32_t MB1; + uint32_t ME1; + uint32_t PSW; + uint32_t ID; + uint32_t TMP; + uint32_t EPC; + uint32_t EXC; + uint32_t CFG; + uint32_t S22; + uint32_t NPC; + uint32_t DBG; + uint32_t DEPC; + uint32_t OPT; + uint32_t RCFG; + uint32_t CCFG; + uint32_t S29; + uint32_t S30; + uint32_t S31; + uint32_t S32; + + /* miasm2 specific regs */ + uint32_t PC_end; + uint32_t RPE_instr_count; + uint32_t RPC_current; + + + uint32_t take_jmp; + uint32_t last_addr; + uint32_t is_repeat_end; + uint32_t in_erepeat; + + /* flags */ + +} vm_cpu_t; + +void dump_gpregs(vm_cpu_t* vmcpu); + +#define RETURN_PC return BlockDst; diff --git a/miasm2/jitter/codegen.py b/miasm2/jitter/codegen.py index 10140fd2..a709d5ec 100644 --- a/miasm2/jitter/codegen.py +++ b/miasm2/jitter/codegen.py @@ -132,7 +132,8 @@ class CGen(object): @dst2index: LocKey -> uniq value @loc_key: LocKey istance""" - dst2index[loc_key] = len(dst2index) + if loc_key not in dst2index: + dst2index[loc_key] = len(dst2index) def assignblk_to_irbloc(self, instr, assignblk): """ diff --git a/miasm2/jitter/jitload.py b/miasm2/jitter/jitload.py index 288e737a..39ca3d56 100644 --- a/miasm2/jitter/jitload.py +++ b/miasm2/jitter/jitload.py @@ -196,6 +196,8 @@ class Jitter(object): from miasm2.jitter.arch import JitCore_mips32 as jcore elif arch_name == "ppc32": from miasm2.jitter.arch import JitCore_ppc32 as jcore + elif arch_name == "mep": + from miasm2.jitter.arch import JitCore_mep as jcore else: raise ValueError("unknown jit arch: %s" % arch_name) except ImportError: |