diff options
Diffstat (limited to 'miasm2/arch/mep')
| -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 |
7 files changed, 3494 insertions, 0 deletions
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) |