def read_memory(self, address, memory_space=None, size=1, count=1, do_side_effects=False): """ :param address: Address to begin reading from. :param memory_space: Name of the memory space to read or None which will read the core's current memory space. :param size: Size of memory access unit in bytes. Must be one of 1, 2, 4 or 8. Note that not all values are supported by all models. Note that the data is always returned as bytes, so calling with size=4, count=1 will return a byte array of length 4. :param count: Number of units to read. :param do_side_effects: If True, the target must perform any side-effects normally triggered by the read, for example clear-on-read. Returns an integer if count is 1, otherwise returns a bytearray of length size*count """ space = self._get_address_space(memory_space) if address < space.minAddress: raise ValueError( "Address is below minimum address of memory space '%s'" % space.memSpaceName) if address > space.maxAddress: raise ValueError( "Address is above maximum address of memory space '%s'" % space.memSpaceName) if size not in [1, 2, 4, 8]: raise ValueError("'size' must be 1, 2, 4 or 8") if count is None: count = len(data) / size if len(data) % size != 0: raise ValueError("len(data) must be a multiple of size") cadi_address = CADI.CADIAddrComplete( CADI.CADI_NO_OVERLAY, CADI.CADIAddr(space.memSpaceId, address)) data = self.__cadi.CADIMemRead(cadi_address, count, size, do_side_effects) return data
def appliOutput(self, streamId, count, actualCountp, buf): """Semihosting output callback""" if streamId == CADI.CADI_STREAMID_STDOUT: stream = self.stdout elif streamId == CADI.CADI_STREAMID_STDERR: stream = self.stderr else: warn("attempted to write to stream: %s" % streamId) stream.write(buf) CADI.uint32p_assign(actualCountp, count)
def add_bpt_mem(self, address, memory_space=None, on_read=True, on_write=True, on_modify=True): """ Set a new breakpoint, which will be hit when a memory location is accessed :param address: The address to set the breakpoint on :param memory_space: The name of the memory space that ``address`` is in. If None, the current memory space of the core is used :param on_read: If True, the breakpoint will be triggered when the memory location is read from. :param on_write: If True, the breakpoint will be triggered when the memory location is written to. :param on_modify: If True, the breakpoint will be triggered when the memory location is modified. """ space = self._get_address_space(memory_space) cadi_address = CADI.CADIAddrComplete( CADI.CADI_NO_OVERLAY, CADI.CADIAddr(space.memSpaceId, address)) trigger_type = 0 if on_read: trigger_type |= CADI.CADI_BPT_TRIGGER_ON_READ if on_write: trigger_type |= CADI.CADI_BPT_TRIGGER_ON_WRITE if on_modify: trigger_type |= CADI.CADI_BPT_TRIGGER_ON_MODIFY if trigger_type == 0: raise ValueError( "At least one of on_read, on_write and on_modify must be True") request = CADI.CADIBptRequest(enabled_par=1, type_par=CADI.CADI_BPT_MEMORY, address_par=cadi_address, triggerType_par=trigger_type) bpt = Breakpoint(self, self.__cadi, request) self.breakpoints[bpt.number] = bpt return self.breakpoints[bpt.number]
def _get_cadi_value(self): # info.(min|max|default)Value is stored as int64_t, but sometimes contains 2**64-1 # The workaround is to add/subtract 2**64 if values seem wrong (max < min) # This does not fix the problem in all possible cases # This currently gets triggered by the AEM and v8 models # Is *seems* to fix the bug for all current cores using the default property values # Many properties use the range [-2**63, 2**63-1] so I don't think this can be solved properly # This is based on CadiRunner::CheckParameter in MaxCore/CadiRunner/CadiRunner.cpp if self.__info.maxValue >= self.__info.minValue: if self >= self.__info.minValue and self <= self.__info.maxValue: intValue = self else: raise ValueError("int parameter %s must satisfy: %i <= value <= %i (actual %i)" % (self.__info.name, self.__info.minValue, self.__info.maxValue, self)) else: # min and max wrong way round, must be unsigned range def unsigned_to_signed(n): if n < 0: return n + (2 ** 64) else: return n if ( unsigned_to_signed(self) >= unsigned_to_signed(self.__info.minValue) and unsigned_to_signed(self) <= unsigned_to_signed(self.__info.maxValue) ): intValue = self else: raise ValueError("int parameter %s must satisfy: %i <= value <= %i (actual %i)" % (self.__info.name, self.__info.minValue, self.__info.maxValue, self)) return CADI.CADIParameterValue(self.__info.id, CADI.CADI_PARAM_INT, intValue, "")
def write(self, value, sideEffects=False): """ Write a new value to the register. The value may be a bytearray or a value appropriate to the register type. """ reg = [ CADI.CADIReg(self._info.regNumber, 0, i, False, self._info.attribute) for i in xrange(self.__reg_count) ] full_array = bytearray(self.__reg_count * 16) if isinstance(value, bytearray): full_array[0:len(value)] = value elif self.__conversion_str != None: if self.__conversion_str != "": pack_into(self.__conversion_str, full_array, 0, value) elif self._info.display == CADI.CADI_REGTYPE_SYMBOL: if value not in self.__symbols: raise ValueError( "\"%s\" is not a valid symbol for register %s" % self._info.name) pack_into("<I", full_array, 0, self.__symbols.index(value)) elif self._info.display == CADI.CADI_REGTYPE_STRING: full_array[0:len(value)] = value else: raise TypeError("Expecting a bytearray or %s" % self.__type_str) offset = 0 for r in reg: r.bytes = full_array[offset:(offset + 16)] offset += 16 self.__cadi.CADIRegWrite(reg, sideEffects)
def read(self, sideEffects=False): """ Read the contents of the register and attempt to convert it to an appropriate format according to CADIRegInfo.display. If the value cannot be converted to an appropriate format the register contents will be returned as a bytearray. """ reg = [ CADI.CADIReg(self._info.regNumber, 0, i, False, self._info.attribute) for i in xrange(self.__reg_count) ] reg = self.__cadi.CADIRegRead(reg, sideEffects) bytes_to_read = self.__width_in_bytes if self._info.display == CADI.CADI_REGTYPE_SYMBOL: bytes_to_read = 4 full_array = b"".join([str(r.bytes) for r in reg])[0:bytes_to_read] if self.__conversion_str != None: if self.__conversion_str == "": # this happens with the vector-breakpoint fake registers on v8A return 0 else: return unpack(self.__conversion_str, full_array)[0] elif self._info.display == CADI.CADI_REGTYPE_SYMBOL: index = unpack("<I", full_array)[0] return self.__symbols[index] elif self._info.display == CADI.CADI_REGTYPE_STRING: return full_array else: return bytearray(full_array)
def __init__(self, filename, parameters={}, verbose=False): """ Loads a model from a DLL, and initialises it :param filename: The path of the file to load the model from :param parameters: Dictionary containing parameters of the model to set. The keys of this dictionary should be strings containing the names of the parameters, and the values should be strings, bools or ints containing the values of the parameters :param verbose: If True, extra debugging information is printed """ self.__filename = filename self._loader = CADI.CADIDll() self._loader.openDll(filename) self._broker = self._loader.CreateCADIBroker() factories = self._broker.GetSimulationFactories() factory = factories[0] callbacks_enable = '\001' * CADI.CADI_SIM_CB_Count errors = [] @CADIcallback def Error(severity, errorCode, erroneousParameterId, message): """ Error(severity, errorCode, erroneousParameterId, message) Recieves error information during instantiation """ errors.append("CADIErrorCallback::Error(severity=%s, error=%s, paramId=%d, message=%s)" % (CADIFACT_SEVERITY2str(severity), CADIFACT_ERROR2str(errorCode), erroneousParameterId, repr(message))) parameter_dict = ParameterDict(factory.GetParameterInfos()) for (key, value) in parameters.iteritems(): # This will raise an exception for unknown parameters parameter_dict[key] = value # This will raise an exception for parameters set to a value of # the wrong type or out of range parameter_array = parameter_dict._get_parameter_array() self._sim_callback = Model.SimulationCallback(self, verbose) self._sim_error_callback = PyCADIErrorCallback(Error) simulation = factory.Instantiate(parameter_array, self._sim_error_callback, self._sim_callback, callbacks_enable) if simulation is None: raise TargetError("Instantiation failed: " + ", ".join(errors)) factory.Release() Model.__init__(self, simulation, verbose)
def get_target(self, target): """ Obtain an interface to a target :param target: The instance name corresponding to the desired target """ interface_name = "eslapi.CADI2" target_id = next((t.id for t in self.__simulation.GetTargetInfos() if t.instanceName == target), None) if target_id == None: raise ValueError("Model has no target named \"%s\"" % target) if target_id not in self.__targets: target = self.__simulation.GetTarget(target_id) result = target.ObtainInterface(interface_name) if type(result) == int: raise Model.ObtainInterfaceFailed(interface_name) (interface, rev) = result cadi = CADI.CAInterface_CADI(interface) target_name = cadi.CADIGetTargetInfo().targetName try: # if this fails, this target object hangs around, breaking the # modechange callbacks target_object = _target_classes[target_name](cadi, self) except Exception as ex: target_object = Target(cadi, self) if self.__verbose: warn("Failed to load specialised target, falling back to general implementation.\n(Error: %s)" % ex) self.__targets[target_id] = target_object return self.__targets[target_id]
def get_model_parameters(cls, filename): """Get a dictionary containing the default parameters for the model :param filename: The path of the file to load the model parameters from """ loader = CADI.CADIDll() loader.openDll(filename) broker = loader.CreateCADIBroker() factory = broker.GetSimulationFactories()[0] return ParameterDict(factory.GetParameterInfos())
def add_bpt_prog(self, address, memory_space=None): """ Set a new breakpoint, which will be hit when program execution reaches a memory address :param address: The address to set the breakpoint on :param memory_space: The name of the memory space that ``address`` is in. If None, the current memory space of the core is used """ space = self._get_address_space(memory_space) cadi_address = CADI.CADIAddrComplete( CADI.CADI_NO_OVERLAY, CADI.CADIAddr(space.memSpaceId, address)) request = CADI.CADIBptRequest(enabled_par=1, type_par=CADI.CADI_BPT_PROGRAM, address_par=cadi_address) bpt = Breakpoint(self, self.__cadi, request) self.breakpoints[bpt.number] = bpt return self.breakpoints[bpt.number]
def add_bpt_reg(self, reg_name, on_read=True, on_write=True, on_modify=True): """ Set a new breakpoint, which will be hit when a register is accessed :param reg_name: The name of the register to set the breakpoint on. The name can be in one of the following formats: * ``<group>.<register>`` * ``<group>.<register>.<field>`` * ``<register>`` * ``<register>.<field>`` The last two forms can only be used if the register name is unambiguous :param on_read: If True, the breakpoint will be triggered when the register is read from. :param on_write: If True, the breakpoint will be triggered when the register is written to. :param on_modify: If True, the breakpoint will be triggered when the register is modified. """ # No ARM models support register breakpoints (as of Apr 2013), so this is untested register = self._get_register_by_name(reg_name) trigger_type = 0 if on_read: trigger_type |= CADI.CADI_BPT_TRIGGER_ON_READ if on_write: trigger_type |= CADI.CADI_BPT_TRIGGER_ON_WRITE if on_modify: trigger_type |= CADI.CADI_BPT_TRIGGER_ON_MODIFY if trigger_type == 0: raise ValueError( "At least one of on_read, on_write and on_modify must be True") request = CADI.CADIBptRequest(enabled_par=1, type_par=CADI.CADI_BPT_REGISTER, regNumber_par=register._info.regNumber, triggerType_par=trigger_type) bpt = Breakpoint(self, self.__cadi, request) self.breakpoints[bpt.number] = bpt return self.breakpoints[bpt.number]
def __init__(self, host, port, verbose=False): """ Connects to an already initalised model using CADIIPC :param host: Hostname or IP address of the computer running the model. :param port: Port number that the model is listening on. :param verbose: If True, extra debugging information is printed """ self.__host = host self.__port = port self._loader = CADI.CADIClient() self._broker = self._loader.CreateCADIBroker("cadiclient://" + host) callbacks_enable = '\001' * CADI.CADI_SIM_CB_Count errors = [] @CADIcallback def Error(severity, errorCode, erroneousParameterId, message): """ Error(severity, errorCode, erroneousParameterId, message) Recieves error information during instantiation """ errors.append("CADIErrorCallback::Error(severity=%s, error=%s, paramId=%d, message=%s)" % (CADIFACT_SEVERITY2str(severity), CADIFACT_ERROR2str(errorCode), erroneousParameterId, repr(message))) self._sim_callback = Model.SimulationCallback(self, verbose) self._sim_error_callback = PyCADIErrorCallback(Error) simulation = self._broker.SelectSimulation(port, self._sim_error_callback, self._sim_callback, callbacks_enable) if simulation is None: raise TargetError("Instantiation failed: " + ", ".join(errors)) Model.__init__(self, simulation, verbose)
def _get_cadi_value(self): return CADI.CADIParameterValue(self.__info.id, CADI.CADI_PARAM_STRING, 0, self)
def _get_cadi_value(self): intValue = 1 if self.__value == True else 0 return CADI.CADIParameterValue(self.__info.id, CADI.CADI_PARAM_BOOL, intValue, "")
def write_memory(self, address, data, memory_space=None, size=1, count=None, do_side_effects=False): """ :param address: Address to begin reading from :param data: The data to write. If count is 1, this must be an integer Otherwise it must be a bytearray with length >= size*count :param memory_space: memory space to read. Default is None which will read the core's current memory space. :param size: Size of memory access unit in bytes. Must be one of 1, 2, 4 or 8. Note that not all values are supported by all models. :param count: Number of units to write. If None, count is automatically calculated such that all data from the array is written to the target :param do_side_effects: If True, the target must perform any side-effects normally triggered by the write, for example triggering an interrupt. """ space = self._get_address_space(memory_space) if address < space.minAddress: raise ValueError( "Address is below minimum address of memory space '%s'" % space.memSpaceName) if address > space.maxAddress: raise ValueError( "Address is above maximum address of memory space '%s'" % space.memSpaceName) if size not in [1, 2, 4, 8]: raise ValueError("'size' must be 1, 2, 4 or 8") if isinstance(data, Integral): data = bytearray([data]) if count is None: count = len(data) / size if len(data) % size != 0: raise ValueError("len(data) must be a multiple of size") if isinstance(data, bytearray) and len(data) < size * count: raise ValueError( "'data' must be either an integer, or a bytearray with length >= size*count" ) cadi_address = CADI.CADIAddrComplete( CADI.CADI_NO_OVERLAY, CADI.CADIAddr(space.memSpaceId, address)) self.__cadi.CADIMemWrite(cadi_address, count, size, data, do_side_effects)
def appliInput(self, streamId, count, actualCountp, buf): """Semihosting input callback""" result = self.stdin.read(count) length = len(result) buf[0:length] = result CADI.uint32p_assign(actualCountp, length)