def cbuffers(self): """ Returns the status of cbuffers on the Kalimba. Considers only structures following the naming convention '*cbuffer_struc'. """ if not self._core.is_connected(): raise ka_exceptions.NotConnectedError() if not self._core.arch.is_bluecore(): raise ka_exceptions.UnsupportedArchitecture("cbuffers() is not supported on non-Bluecore chips") self._core.sym.assert_have_symbols() cbuffer_name_key = "cbuffer_struc$" cbuffer_name_key_len = len(cbuffer_name_key) cbuffers = self._core.sym.varfind(cbuffer_name_key) cbuffers.sort() print(" " * 30 + "C-Buffer Size Read Addr Write Addr Start Space Data") # The results from varfind are unfortunately tuples -- one simply has to know the correct indices. for (struct_name, size_in_addressable_units, struct_address) in cbuffers: # Order of fields in the structure: size, read pointer, write pointer. (sz, rd, wr) = self._read_var_with_size_check(struct_address, size_in_addressable_units) struct_name = struct_name[:-cbuffer_name_key_len] print("%38s" % struct_name, end=' ') if sz != 0: # Find start address of the buffer mask = int(2**math.ceil(math.log(sz, 2)) - 1) start_addr = rd - (rd & mask) if start_addr != (wr - (wr & mask)): print( '\n\n** Warning the start address calculated from the read and ' 'write pointers is different! **' ) amount_space = rd - wr if amount_space <= 0: amount_space += sz amount_space -= 1 amount_data = wr - rd if amount_data < 0: amount_data += sz print(' %4d 0x%06x 0x%06x 0x%06x %4d %4d' % (sz, rd, wr, start_addr, amount_space, amount_data)) else: print("size=0")
def profiler(self): """ Read the built-in profiler data. Requires the profiler library to be used. """ if not self._core.is_connected(): raise ka_exceptions.NotConnectedError() if not self._core.arch.is_bluecore(): raise ka_exceptions.UnsupportedArchitecture("profiler() is not supported on non-Bluecore chips") class Task(object): def __init__(self, block_, addr): self.block = block_ self.addr = addr self.name = None self.CPU_FRAC = 0 def tidy(self, sym): self.name = sym.varfind(self.addr).name self.CPU_FRAC = sym.constfind("$profiler.CPU_FRACTION_FIELD").value def __repr__(self): if self.name is None: raise Exception("Need to call the tidy method before using") return "%-50s - %2.1f %%" % (self.name, self.block[self.CPU_FRAC]/1000) # get the head of the list and a couple of constants head = self._core.sym.varfind("$profiler.last_addr").addr null = self._core.sym.constfind("$profiler.LAST_ENTRY").value size = self._core.sym.constfind("$profiler.STRUC_SIZE").value next_addr = self._core.sym.constfind("$profiler.NEXT_ADDR_FIELD").value # get the first address curr = self._core.dm[head] # read all the structures off the chip as fast as we can tasks = [] while curr != null: block = self._core.dm[curr:(curr + size)] tasks.append(Task(block, curr)) curr = block[next_addr] # now fill in the other bits for t in tasks: t.tidy(self._core.sym) # finally return return tasks
def timers(self): """Reports the status of timers registered with the Kalimba standard library.""" if not self._core.is_connected(): raise ka_exceptions.NotConnectedError() if not self._core.arch.is_bluecore(): raise ka_exceptions.UnsupportedArchitecture("timers() is not supported on non-Bluecore chips") # Strategy is to grab all the data in one go, then print it afterwards. def get_const_field(name): symbol = self._core.sym.constfind(name) if not symbol: raise MissingTimerSymbolError(name) return symbol.value # We need the offsets for various structure fields next_field_offset = get_const_field("$timer.NEXT_ADDR_FIELD") time_field_offset = get_const_field("$timer.TIME_FIELD") handler_field_offset = get_const_field("$timer.HANDLER_ADDR_FIELD") timer_structure_size = get_const_field("$timer.STRUC_SIZE") # Get the address of the timer at the head of the linked list. head_timer_symbol = self._core.sym.varfind("$timer.last_addr") if len(head_timer_symbol) == 0: raise MissingTimerSymbolError("$timer.last_addr") # If the processor is running, pause it while we collect data. was_running = self._core.is_running() if was_running: self._core.pause() # Read each timer structure in the linked list of timers current_timer_address = self._core.dm[head_timer_symbol.addr] timers = [] end_marker = 2**self._core.arch.get_data_width() - 1 while current_timer_address != end_marker: # noinspection PyProtectedMember timer_struct_memory = self._core._read_dm_block(current_timer_address, timer_structure_size) timers.append((current_timer_address, timer_struct_memory)) current_timer_address = timer_struct_memory[next_field_offset] if was_running: self._core.run() self._print_timer_results(timers, time_field_offset, handler_field_offset)
def ports(self): """ Displays information about each DSP port including format and amount of data/space. """ # check connected to chip if not self._core.is_connected(): raise ka_exceptions.NotConnectedError() if not self._core.arch.is_bluecore(): raise ka_exceptions.UnsupportedArchitecture("ports() is not supported on non-Bluecore chips") # check symbols are loaded self._core.sym.assert_have_symbols() # get the symbols we need READ_OFFSET_ADDR = self._core.sym.varfind('$cbuffer.read_port_offset_addr') WRITE_OFFSET_ADDR = self._core.sym.varfind('$cbuffer.write_port_offset_addr') READ_LIMIT_ADDR = self._core.sym.varfind('$cbuffer.read_port_limit_addr') WRITE_LIMIT_ADDR = self._core.sym.varfind('$cbuffer.write_port_limit_addr') READ_BUFFER_SIZE = self._core.sym.varfind('$cbuffer.read_port_buffer_size') WRITE_BUFFER_SIZE = self._core.sym.varfind('$cbuffer.write_port_buffer_size') def read_dm(addr): return self._core.dm[addr] # get the read and write offset read_offset_addr = self._read_var_with_size_check( READ_OFFSET_ADDR.addr, READ_OFFSET_ADDR.size_in_addressable_units ) write_offset_addr = self._read_var_with_size_check( WRITE_OFFSET_ADDR.addr, WRITE_OFFSET_ADDR.size_in_addressable_units ) read_offset = list(map(read_dm, read_offset_addr)) write_offset = list(map(read_dm, write_offset_addr)) # get the read and write limit read_limit_addr = self._read_var_with_size_check( READ_LIMIT_ADDR.addr, READ_LIMIT_ADDR.size_in_addressable_units ) write_limit_addr = self._read_var_with_size_check( WRITE_LIMIT_ADDR.addr, WRITE_LIMIT_ADDR.size_in_addressable_units ) read_limit = list(map(read_dm, read_limit_addr)) write_limit = list(map(read_dm, write_limit_addr)) # get the port size read_size = self._read_var_with_size_check( READ_BUFFER_SIZE.addr, READ_BUFFER_SIZE.size_in_addressable_units ) write_size = self._read_var_with_size_check( WRITE_BUFFER_SIZE.addr, WRITE_BUFFER_SIZE.size_in_addressable_units ) # calculate size mask (size-1) for non-zero sizes read_mask = list(map(lambda s: s - (s > 0), read_size)) write_mask = list(map(lambda s: s - (s > 0), write_size)) # calculate data/space in port read_data = list(map(lambda l,o,m: (l - o) & m, read_limit, read_offset, read_mask)) write_space = list(map(lambda l,o,m: (l - o) & m - 1, write_limit, write_offset, write_mask)) # read port configs read_conf_base = self._core.sym.constfind('$READ_PORT0_CONFIG').value write_conf_base = self._core.sym.constfind('$WRITE_PORT0_CONFIG').value read_conf = self._read_var_with_size_check(read_conf_base, READ_OFFSET_ADDR.size_in_addressable_units) write_conf = self._read_var_with_size_check(write_conf_base, WRITE_OFFSET_ADDR.size_in_addressable_units) # extract data size (in octets) from config read_data_size = list(map(lambda c: (c & 0x3) + 1, read_conf)) write_space_size = list(map(lambda c: (c & 0x3) + 1, write_conf)) # decode configs into strings read_conf_str = list( map( lambda c, s: ("8" if s == 1 else ("16" if s == 2 else ("24" if s == 3 else "??"))) + "-bit, " + ("Big Endian" if (c & 0x4) else "Little Endian") + ", " + ("No Sign Ext" if (c & 0x8) else "Sign Ext" ), read_conf, read_data_size ) ) write_conf_str = list( map( lambda c, s: ("8" if s == 1 else ("16" if s == 2 else ("24" if s == 3 else "??"))) + "-bit, " + ("Big Endian" if (c & 0x4) else "Little Endian") + ", " + ("Saturate" if (c & 0x8) else "No Saturate"), write_conf, write_space_size ) ) # print information print("Read ports:\n Port Status Offset Address Size(Bytes) Data Config") for i in range(len(read_offset_addr)): if read_offset_addr[i]: print( " %2i Enabled %6i (0x%04X) %5i (0x%04X) %5i %s" % ( i, read_offset_addr[i], read_offset_addr[i], read_size[i], read_size[i], read_data[i] // read_data_size[i], read_conf_str[i] ) ) else: print(" %2i Disabled" % i) print("Write ports:\n Port Status Offset Address Size(Bytes) Space Config") for i in range(len(write_offset_addr)): if write_offset_addr[i]: print( " %2i Enabled %6i (0x%04X) %5i (0x%04X) %5i %s" % ( i, write_offset_addr[i], write_offset_addr[i], write_size[i], write_size[i], write_space[i] // write_space_size[i], write_conf_str[i] ) ) else: print(" %2i Disabled" % i)
def writecbuffer(self, cbuffer_name, data, do_ud='update'): """ Writes data to the specified cbuffer. Returns the left over data after writing as much as it can. cbuffer_name can be a regular expression, but must end with 'cbuffer_struc'. data is a list that contains the data to be written. Set do_ud to 'noupdate' if the write address should not be updated (the default is 'update'). """ if not self._core.is_connected(): raise ka_exceptions.NotConnectedError() if not self._core.arch.is_bluecore(): raise ka_exceptions.UnsupportedArchitecture("writecbuffer() is not supported on non-Bluecore chips") if not cbuffer_name.endswith("cbuffer_struc"): print("cbuffer_name must end with 'cbuffer_struc'") return cbuff_list = self._core.sym.varfind(cbuffer_name) if len(cbuff_list) == 0: print("No such cbuffer found") return if len(cbuff_list) > 1: print("More than one cbuffer found with that name. Match must be unique.") print("Matching names were:") for i in cbuff_list: print(" ", i[0]) return cbuff_tuple = cbuff_list[0] cbuff_addr = cbuff_tuple[2] # Fields are name, size, addr (sz, rd, wr) = self._core._read_dm_block(cbuff_addr, 3) if sz != 0: # start and end addresses mask = int(2**math.ceil(math.log(sz, 2)) - 1) start_addr = rd - (rd & mask) end_addr = start_addr + sz - 1 # available data in buffer amount_data = wr - rd if amount_data < 0: amount_data += sz amount_space = sz - amount_data - 1 if amount_space == 0: return data else: n = min(len(data), amount_space) # end_addr is index of last item of buf if (wr + n - 1) >= end_addr: self._core._write_dm_block(wr, data[0:(end_addr - wr + 1)]) written_size = (end_addr - wr + 1) if written_size < n: self._core._write_dm_block(start_addr, data[written_size:n]) wr = start_addr + n - written_size else: self._core._write_dm_block(wr, data[0:n]) wr += n data = data[n:] if do_ud.lower() == 'update': self._core._write_dm_block(cbuff_addr+2, [wr]) return data else: print("The size of the cbuffer is 0.") return data
def readcbuffer(self, cbuffer_name, n=0, do_ud='noupdate'): """ Returns the contents of a cbuffer on the Kalimba. cbuffer_name can be a regular expression, but must end with 'cbuffer_struc'. n specifies the maximum number of words to read. Set do_ud to 'update' if the read address should be updated by this function (the default is 'noupdate'). """ if not self._core.is_connected(): raise ka_exceptions.NotConnectedError() if not self._core.arch.is_bluecore(): raise ka_exceptions.UnsupportedArchitecture("readcbuffer() is not supported on non-Bluecore chips") if not cbuffer_name.endswith("cbuffer_struc"): print("cbuffer_name must end with 'cbuffer_struc'") return cbuff_list = self._core.sym.varfind(cbuffer_name) if len(cbuff_list) == 0: print("No such cbuffer found") return if len(cbuff_list) > 1: print("More than one cbuffer found with that name. Match must be unique.") print("Matching names were:") for i in cbuff_list: print(" ", i[0]) return cbuff_tuple = cbuff_list[0] cbuff_addr = cbuff_tuple[2] # Fields are name, size, addr (sz, rd, wr) = self._core._read_dm_block(cbuff_addr, 3) if sz != 0: # start and end addresses mask = int(2**math.ceil(math.log(sz, 2)) - 1) start_addr = rd - (rd & mask) end_addr = start_addr + sz - 1 # available data in buffer amount_data = wr - rd if amount_data < 0: amount_data += sz if amount_data == 0: return [] else: if n > 0: if n > amount_data: n = amount_data print("Warning: Not enough data in the cbuffer") else: n = amount_data # end_addr is index of last item of buf if (rd + n - 1) > end_addr: data = self._core._read_dm_block(rd, end_addr - rd + 1) m = len(data) data.append(self._core._read_dm_block(start_addr, m)) rd = start_addr + m else: data = self._core._read_dm_block(rd, n) rd += n if do_ud.lower() == 'update': self._core._write_dm_block(cbuff_addr+1, [rd]) return data else: print("The size of the cbuffer is 0.") return []