def execute_hardware(plan): dma = [] hw_switch.reset() ret_dma_base = int( PL.ip_dict["SEG_{0}_Reg".format(metadata.DMA_names[0])][0], 16) ret_dma_mmio = MMIO(ret_dma_base, 256) ret_dma = DMA(ret_dma_base, 1) ret_dma.create_buf(8388607) prepare_execution(plan, dma, metadata.DMA[0][0][0]) hw_switch.commit() ## Timer Start start_time = time.process_time() ret_dma.transfer(8388607, 1) for d in dma: d.transfer() for d in dma: d.wait() ## Timer End end_time = time.process_time() print("Elapsed Test Time: ", end_time - start_time) ret_dma.wait() bytes_read = ret_dma_mmio.read(0x58) ffi = pynq.drivers.dma.ffi buf = ffi.buffer(ret_dma.buf, bytes_read) view = np.frombuffer(buf, plan.dtype, -1).copy() return view
def __init__(self,sample_size=128,overlay=None): self.lock = threading.Lock() self.dma = overlay.GPS_Receiver_IQ_Streamer.axi_dma_0 self.data_size = sample_size self.xlnk = Xlnk() self.input_buffer = self.xlnk.cma_array(shape=(self.data_size,), dtype=np.uint32) self._isFetching = True self.blk_count = 0 """GPIO based settings initialization""" GPIO_BASE_ADDRESS = 0x41200000 GPS_IP_BASE_ADDRESS = 0x41210000 DMA_IP_BASE_ADDRESS = 0x40400000 ADDRESS_RANGE = 0x4 ADDRESS_OFFSET = 0x00 self.FIFORESET_OFFSET = 16 self.IQSTREAM_EN_OFFSET = 20 self.RFSTREAM_EN_OFFSET = 24 self.SAMPLES_PER_BLK_OFFSET = 0 self.LEDs = MMIO(GPIO_BASE_ADDRESS, ADDRESS_RANGE) self.GpsSettings = MMIO(GPS_IP_BASE_ADDRESS, ADDRESS_RANGE) timestr = time.strftime("%Y%m%d-%H%M%S") self.filename = "/home/xilinx/jupyter_notebooks/iotSDR-GPS/rec5s_40960IF"#+timestr """update dma frame size""" self.GpsSettings.write(0x0, self.data_size)
def __init__(self, layer, fm, dim, xlnk, runFactor=1, batchsize=1): self.layer = layer self.fm = fm self.dim = dim self.xlnk = xlnk self.runFactor = runFactor self.batchsize = batchsize self.COMPUTE = 0 self.CONV_WEIGHT = 1 self.ol = Overlay( os.path.dirname(os.path.realpath(__file__)) + "/bitstream/" + layer + ".bit") self.dma = self.ol.axi_dma_0 self.ip = MMIO(self.ol.ip_dict[self.layer]['phys_addr'], self.ol.ip_dict[self.layer]['addr_range']) self.wBuff = [] self.initWeights() self.cmaOut = [] self.cmaTemp = [] for b in range(self.batchsize): self.cmaOut.append( self.xlnk.cma_array(shape=(self.fm * (self.dim**2), ), dtype=np.float32)) self.allocaCmaTemp()
def __init__(self): self.mmio_control = MMIO(CONTROL_BLOCK_OFFSET, ADDRESS_RANGE) self.mmio_capture = MMIO(CAPTURE_BLOCK_OFFSET, ADDRESS_RANGE) self.mmio_blocks = {'control_axi_block': hex(CONTROL_BLOCK_OFFSET), 'capture_axi_block': hex(CAPTURE_BLOCK_OFFSET)} self.motor_modes = ('reset_mode', 'torque_mode', 'rpm_mode') self.motor_capture_modes = ('ia_ib_angle_rpm', 'id_iq', 'vd_vq')
def load_ip_data(cls, ip_name, data): """This method writes data to the addressable IP. Note ---- The data is assumed to be in binary format (.bin). The data name will be stored as a state information in the IP dictionary. Parameters ---------- ip_name : str The name of the addressable IP. data : str The absolute path of the data to be loaded. Returns ------- None """ cls.client_request() with open(data, 'rb') as bin: size = (math.ceil(os.fstat(bin.fileno()).st_size / mmap.PAGESIZE)) * mmap.PAGESIZE mmio = MMIO(cls._ip_dict[ip_name][0], size) buf = bin.read(size) mmio.write(0, buf) cls._ip_dict[ip_name][2] = data cls.server_update()
def execute_hardware(plan): dma = [] hw_switch.reset() ret_dma_base = PL.ip_dict[metadata.DMA_names[0]]["phys_addr"] ret_dma_mmio = MMIO(ret_dma_base, 256) ret_dma = overlay.axi_dma_0 ret_buf = xlnk.cma_array((8388607, ), dtype=np.uint8) prepare_execution(plan, dma, metadata.DMA[0][0][0]) hw_switch.commit() ## Timer Start start_time = time.process_time() ret_dma.recvchannel.start() ret_dma.recvchannel.transfer(ret_buf) for d in dma: d.transfer() for d in dma: d.wait() ## Timer End end_time = time.process_time() print("Elapsed Test Time: ", end_time - start_time) ret_dma.recvchannel.wait() bytes_read = ret_dma_mmio.read(0x58) view = np.frombuffer(ret_buf, np.uint8, count=bytes_read).copy() view.dtype = plan.dtype print(view.shape) ret_buf.freebuffer() return view
def __init__(self): self.mcolv = Overlay("mcolor/design_1_wrapper.bit", 0) self.mcolv.download() self.axi_gpio_h = MMIO(axi_gpio_addr, axi_gpio_range) self.axi_gpio_h.write(0x4, 0x0) self.axi_gpio_h.write(0x0, 0x0) self.buffer = 0
def __init__(self, bitfile, **kwargs): """Initializes a new ioOverlay object. """ # The following lines do some path searching to enable a # PYNQ-Like API for Overlays. For example, without these # lines you cannot call ioOverlay('io.bit') because # io.bit is not on the bitstream search path. The # following lines fix this for any non-PYNQ Overlay # # You can safely reuse, and ignore the following lines # # Get file path of the current class (i.e. /opt/python3.6/<...>/stream.py) file_path = os.path.abspath(inspect.getfile(inspect.currentframe())) # Get directory path of the current class (i.e. /opt/python3.6/<...>/stream/) dir_path = os.path.dirname(file_path) # Update the bitfile path to search in dir_path bitfile = os.path.join(dir_path, bitfile) # Upload the bitfile (and parse the colocated .tcl script) super().__init__(bitfile, **kwargs) # Manually define the GPIO pin that drives reset self.__resetPin = GPIO(GPIO.get_gpio_pin(0), "out") # Define a Register object at address 0x0 of the IO address space # We will use this to set bits and start the core (see start()) # Do NOT write to __ap_ctrl unless __resetPin has been set to __NRESET_VALUE self.nreset() self.__ap_ctrl = Register(self.ioCore.mmio.base_addr, 32) self.__hls_reg = MMIO(self.ioCore.mmio.base_addr + self.__IO_REG_OFF, self.__IO_REG_LEN)
def __init__(self, intf_spec_name='BG_SPECIFICATION'): """Return a new Boolean generator object. The available input pins are data pins DIN0 - DIN15, The available output pins can be DOUT0-DOUT15. The input boolean expression can be of the following format: `DOUT4 = DIN0 & DIN1 | DIN2`. If no input boolean expression is specified, the default function implemented is `DIN0 & DIN1 & DIN2 & DIN3`. Parameters ---------- No parameters are required """ if type(intf_spec_name) is str: self.intf_spec = eval(intf_spec_name) elif type(intf_spec_name) is dict: self.intf_spec = intf_spec_name else: raise ValueError("Interface specification has to be str or dict.") self.bg_mmio = MMIO(0x43c00000, (4 * 64)) self.bg_sel_mmio = MMIO(0x41200000) # Parameters to be cleared at reset self.expressions = dict() self.output_pins = list() self.input_pins = list()
def load_ip_data(cls, ip_name, data): """This method writes data to the addressable IP. Note ---- The data is assumed to be in binary format (.bin). The data name will be stored as a state information in the IP dictionary. Parameters ---------- ip_name : str The name of the addressable IP. data : str The absolute path of the data to be loaded. Returns ------- None """ cls._client_request() with open(data, 'rb') as bin: size = (math.ceil(os.fstat(bin.fileno()).st_size/ \ mmap.PAGESIZE))*mmap.PAGESIZE mmio = MMIO(int(cls._ip_dict[ip_name][0], 16), size) buf = bin.read(size) mmio.write(0, buf) cls._ip_dict[ip_name][2] = data cls._server_update()
def __init__(self): self.mmio_control = MMIO(CONTROL_BLOCK_OFFSET, ADDRESS_RANGE) self.mmio_capture = MMIO(CAPTURE_BLOCK_OFFSET, ADDRESS_RANGE) self.mmio_blocks = {'control_axi_block': hex(CONTROL_BLOCK_OFFSET), 'capture_axi_block': hex(CAPTURE_BLOCK_OFFSET)} self.motor_modes = ('reset_mode', 'torque_mode', 'rpm_mode', 'init_mode') self.motor_capture_modes = ('ia_ib_rpm_angle_filtered', 'ia_ib_rpm_angle_raw', 'ialpha_ibeta_rpm_angle', 'id_iq_rpm_angle', 'vd_vq_angle', 'valpha_vbeta_angle', 'va_vb_vc', 'va_vb_vc_PWM')
def __init__(self, chunkSize, numClasses, numFeatures): self.numClasses = numClasses self.numFeatures = numFeatures # ------------------------- # Download Overlay. # ------------------------- ol = Overlay("LogisticRegression.bit") ol.download() # ------------------------- # Physical address of the Accelerator Adapter IP. # ------------------------- ADDR_Accelerator_Adapter_BASE = int(PL.ip_dict["SEG_LR_gradients_kernel_accel_0_if_Reg"][0], 16) ADDR_Accelerator_Adapter_RANGE = int(PL.ip_dict["SEG_LR_gradients_kernel_accel_0_if_Reg"][1], 16) # ------------------------- # Initialize new MMIO object. # ------------------------- self.bus = MMIO(ADDR_Accelerator_Adapter_BASE, ADDR_Accelerator_Adapter_RANGE) # ------------------------- # Physical addresses of the DMA IPs. # ------------------------- ADDR_DMA0_BASE = int(PL.ip_dict["SEG_dm_0_Reg"][0], 16) ADDR_DMA1_BASE = int(PL.ip_dict["SEG_dm_1_Reg"][0], 16) ADDR_DMA2_BASE = int(PL.ip_dict["SEG_dm_2_Reg"][0], 16) ADDR_DMA3_BASE = int(PL.ip_dict["SEG_dm_3_Reg"][0], 16) # ------------------------- # Initialize new DMA objects. # ------------------------- self.dma0 = DMA(ADDR_DMA0_BASE, direction = DMA_TO_DEV) # data1 DMA. self.dma1 = DMA(ADDR_DMA1_BASE, direction = DMA_TO_DEV) # data2 DMA. self.dma2 = DMA(ADDR_DMA2_BASE, direction = DMA_TO_DEV) # weights DMA. self.dma3 = DMA(ADDR_DMA3_BASE, direction = DMA_FROM_DEV) # gradients DMA. # ------------------------- # Allocate physically contiguous memory buffers. # ------------------------- self.dma0.create_buf(int(chunkSize / 2) * (self.numClasses + (1 + self.numFeatures)) * 4, 1) self.dma1.create_buf(int(chunkSize / 2) * (self.numClasses + (1 + self.numFeatures)) * 4, 1) self.dma2.create_buf((self.numClasses * (1 + self.numFeatures)) * 4, 1) self.dma3.create_buf((self.numClasses * (1 + self.numFeatures)) * 4, 1) # ------------------------- # Get CFFI pointers to objects' internal buffers. # ------------------------- self.data1_buf = self.dma0.get_buf(32, data_type = "float") self.data2_buf = self.dma1.get_buf(32, data_type = "float") self.weights_buf = self.dma2.get_buf(32, data_type = "float") self.gradients_buf = self.dma3.get_buf(32, data_type = "float")
def __init__(self): ol = Overlay("TEST_wrapper.bit",0) ol.download() self.DELAY = MMIO(0x41200000,0x10000) self.CTIME0 = MMIO(0x41210000,0x10000) self.CTIME1 = MMIO(0x41220000,0x10000) self.O_UTIL = MMIO(0x41230000,0x10000) self.I_UTIL = MMIO(0x41240000,0x10000)
def __init__(self): ol = Overlay("TEST_wrapper.bit", 0) ol.download() self.DATA = MMIO(0x43c00000, 0x10000) self.UTIL = MMIO(0x43c10000, 0x10000) self.loaded_data = [] for i in range(FIFO_BUFFER): self.loaded_data.append(0) self.loaded_count = 0
def __init__(self): self.PC_OV = Overlay("TDC/PG_OV_wrapper.bit", 0) self.PC_OV.download() self.CLK_WIZ = MMIO(BASE_ADDR, 0x10000) self.CLK_WIZ.write(CCON0, 0xA01) self.CLK_WIZ.write(CCON2, 0x5) while (self.CLK_WIZ.read(SR) == 0): pass self.CLK_WIZ.write(CCON23, 0x3)
def __init__(self, description): super().__init__(description) self.intc1 = MMIO(0x43C10000, 0x10000) #get axis_interconnect_1 self.intc2 = MMIO(0x43C20000, 0x10000) #get axis_interconnect_2 self.filter = 0 self.intc1.write(0x40 + 0 * 4, 0x00000000) #select slave0 for master1 self.intc1.write(0x40 + 1 * 4, 0x80000000) #disable master1 self.intc2.write(0x40, self.filter) #select slave# for master0 self.intc1.write(0x00, 0x2) #reset interconnect 1 self.intc2.write(0x00, 0x2) #reset interconnect 2
def __init__(self): """Class to use the FGPU architecture in iPython FGPU is a soft GPU architecture for FPGAs. It can be programmed using OpenCL. This class offers: * Compilation of OpenCL kernels * Binding memory regions to kernel parameters * Download tasks along with their binaries and execute them """ self.bitfile = "" # bit file to program self.params = {} # array to store the HW physical addresses of kernel parameters #initialize MMIO object self.base_addr = 0x43C00000 # 1st HW address of FGPU self.addr_space = 0x10000 # size of FGPU address space self.status_reg_offset = 0x8000 # HW address of a control register self.start_reg_offset = 0x8004 # HW address of a control register self.clean_cache_reg_offset = 0x8008 # HW address of a control register self.initiate_reg_offset = 0x800C # HW address of a control register self.mmio = MMIO( self.base_addr, self.addr_space) # map the control regsiter address space #initialize kernel descriptor self.kdesc = { #basic parameters (to be set by the user) 'size0': 0, # size of index space in 1st dimension 'size1': 0, # size of index space in 2nd dimension 'size2': 0, # size of index space in 3rd dimension 'offset0': 0, # offset of kernel index space in 1st dimension 'offset1': 0, # offset of kernel index space in 2nd dimension 'offset2': 0, # offset of kernel index space in 3rd dimension 'wg_size0': 0, # work-group size in 1st dimension 'wg_size1': 0, # work-group size in 2nd dimension 'wg_size2': 0, # work-group size in 3rd dimension 'nParams': 0, # number of kernel parameters 'nDim': 0, # number of activated dimensions in kernel index space #calculated parameters (computed according to user input) 'size': 0, # number of work-items to be launched 'n_wg0': 0, # number of work-groups to launch in 1st dimension 'n_wg1': 0, # number of work-groups to launch in 2nd dimension 'n_wg2': 0, # number of work-groups to launch in 3rd dimension 'wg_size': 0, # number of work-items in a work-group 'nWF_WG': 0, # number of wavefronts in a work-group 'start_addr': 0 # address of the first instruction to be executed in CRAM } # file name that contains kernel code self.kernelFileName = "" #kernel code self.kernel_code = []
def __init__(self): ol = Overlay("TEST_wrapper.bit",0) ol.download() self.CONFIG = MMIO(0x43c00000,0x10000) self.DATA0 = MMIO(0x43c10000,0x10000) self.DATA1 = MMIO(0x43c20000,0x10000) self.DELAY = MMIO(0x43c30000,0x10000) self.UTIL = MMIO(0x43c40000,0x10000) self.loaded_data = [] for i in range(FIFO_DEPTH): self.loaded_data.append(0) self.loaded_count = 0
def set_up_rx_channel(self): """Set up the receive channel. If receive channel is enabled, we will work out the max transfer size first. Then depending on (1) whether interrupt is enabled, and (2) whether SG mode is used, we will create the receive channel. """ if 'c_include_s2mm' in self.description['parameters'] and \ bool(int(self.description['parameters']['c_include_s2mm'])): if 'c_include_s2mm_dre' in self.description['parameters']: dre = bool( int(self.description['parameters']['c_include_s2mm_dre'])) else: dre = False data_width = int( self.description['parameters']['c_m_axi_s2mm_data_width']) >> 3 if self._micro: max_size = data_width * int( self.description['parameters']['c_s2mm_burst_size']) else: max_size = self.buffer_max_size #get the rx samples fifo setter to reset the fifo when first frame fetching starts if self.description['parameters']['C_BASEADDR'] == "0x40420000": fifo_mmio = MMIO(0x41200000, 0x4) if self.description['parameters']['C_BASEADDR'] == "0x40400000": fifo_mmio = MMIO(0x41240000, 0x4) if 's2mm_introut' in self.description['interrupts']: if self._sg: self.recvchannel = _SGDMAChannel(self.mmio, fifo_mmio, max_size, data_width, DMA_TYPE_RX, dre, self.s2mm_introut) else: self.recvchannel = _SDMAChannel(self.mmio, max_size, data_width, DMA_TYPE_RX, dre, self.s2mm_introut) else: if self._sg: self.recvchannel = _SGDMAChannel(self.mmio, self.fifo_mmio, max_size, data_width, DMA_TYPE_RX, dre) else: self.recvchannel = _SDMAChannel(self.mmio, max_size, data_width, DMA_TYPE_RX, dre)
class Mixer(HlsCore): """These define the 'reg' argument to the 'pwm' HLS function. The memory space defined here is shared between the HLS core and the ARM PS. """ __IO_REG_LEN = 0x100 regs = {"control": 0x0, "input_base": 0x10} def __init__(self, description): super().__init__(description) self.__hls_reg = MMIO(self.mmio.base_addr, self.__IO_REG_LEN) bindto = ['UCSD:hlsip:mixer:1.0'] def run(self): self.__hls_reg.write(regs["control"], 0x81) return 0 def stop(self): self.__hls_reg.write(regs["control"], 0x0) return 0 def pub(roll, pitch, thrust, yaw): self.__hls_reg.write(regs["input_base"], (roll << 16) + pitch) self.__hls_reg.write(regs["input_base"] + 0x4, (thrust << 16) + yaw) return 0
class ST: def __init__(self): ol = Overlay("TEST_wrapper.bit", 0) ol.download() self.DATA = MMIO(0x41200000, 0x10000) self.UTIL = MMIO(0x41210000, 0x10000) self.DEBUG = MMIO(0x41220000, 0x10000) def wait_for_rdy(self): while (self.UTIL.read(0x8)) == 0: pass def read_time(self): ctime = self.DATA.read(0x0) / REF_CLK finetimevalues = self.DATA.read(0x8) ftime0 = finetimevalues & 0xFF ftime1 = (finetimevalues & 0xFF00) >> 8 log.debug("FTIME0 -- " + bin(ftime0)) log.debug("FTIME1 -- " + bin(ftime1)) return ctime + (ftime0 - ftime1) * FTIME def read_proc(self): self.UTIL.write(0x0, 0x1) self.wait_for_rdy() timev = self.read_time() self.read_debug() self.UTIL.write(0x0, 0x0) return timev def read_debug(self): pt1 = self.DEBUG.read(0x0) lt1 = self.DEBUG.read(0x8) log.debug("CURRENT VECTOR -- " + format((lt1 << 4) | pt1, '#010b'))
class BmeDriver(HlsCore): """These define the 'reg' argument to the 'ctrlloop' HLS function. The memory space defined here is shared between the HLS core and the ARM PS. """ __IO_REG_OFF = 0x200 __IO_REG_LEN = 0x100 def __init__(self, description): super().__init__(description) self.__hls_reg = MMIO(self.mmio.base_addr + self.__IO_REG_OFF, self.__IO_REG_LEN) bindto = ['UCSD:hlsip:bmeDriver:1.0'] def launch(self): """ Start and detatch computation on the io HLS core Returns ------- Nothing """ self._launch() return def land(self): """ Re-Connect and Terminate Computation on the io HLS core Returns ------- The 4-bit value representing the value of the buttons. """ self._land() return self.__hls_reg.read(0) def run(self): """ Launch computation on the io HLS core Returns ------- The 4-bit value representing the value of the buttons. """ self._run() return self.__hls_reg.read(0)
def continuous_capture(capture_count): mmio_stream = MMIO(capture_address, 256) cap_list = [([]) for i in range(4)] for _ in range(capture_count): motor.stream_capture(capture_address) for i in range(4, 260, 4): stream = mmio_stream.read(i - 4, 4) highbits, lowbits = bytesplit(stream) if (i % 8 != 0): cap_list[0].extend([(np.int16(lowbits))]) cap_list[1].extend([(np.int16(highbits))]) else: cap_list[2].extend([(np.int16(lowbits))]) cap_list[3].extend([(np.int16(highbits))]) return cap_list
def __init__(self, iop_name, addr_base, addr_range, gpio_uix, mb_program, intr_pin=None, intr_ack_gpio=None): """Create a new _IOP object. Parameters ---------- iop_name : str The name of the IP corresponding to the I/O Processor. addr_base : int The base address for the MMIO. addr_range : int The address range for the MMIO. gpio_uix : int The user index of the GPIO, starting from 0. mb_program : str The Microblaze program loaded for the IOP. """ self.iop_name = iop_name self.mb_program = mb_program self.state = 'IDLE' self.gpio = GPIO(GPIO.get_gpio_pin(gpio_uix), "out") self.mmio = MMIO(addr_base, addr_range) if intr_pin and intr_ack_gpio: self.interrupt = _IOPInterruptEvent(intr_pin, intr_ack_gpio) self.program()
def __init__(self, index, ip_name="rgbleds_gpio", start_index=float("inf")): """Create a new RGB LED object. Parameters ---------- index : int Index of the RGBLED, Can be an arbitrary value. The smallest index given will set the global value `_rgbleds_start_index`. This behavior can be overridden by defining `start_index`. ìp_name : str Name of the IP in the `ip_dict`. Defaults to "rgbleds_gpio". start_index : int If defined, will be used to update the global value `_rgbleds_start_index`. """ self.index = index if RGBLED._mmio is None: base_addr = PL.ip_dict[ip_name]["phys_addr"] RGBLED._mmio = MMIO(base_addr, 16) if index < start_index and start_index != float("inf"): raise ValueError("Inconsistent use of initialization indexes.") if start_index < RGBLED._rgbleds_start_index: RGBLED._rgbleds_start_index = start_index if index < RGBLED._rgbleds_start_index: RGBLED._rgbleds_start_index = index
def __init__(self): """Return a new Audio object. The PL is queried to get the base address and length. Parameters ---------- None """ self.base_addr = int(PL.ip_dict['SEG_d_axi_pdm_1_S_AXI_reg'][0], 16) self.length = int(PL.ip_dict['SEG_d_axi_pdm_1_S_AXI_reg'][1], 16) self._AudioMMIO = MMIO(self.base_addr, self.length) self._ffi = cffi.FFI() self._libaudio = self._ffi.dlopen(LIB_SEARCH_PATH + "/libaudio.so") self._ffi.cdef("""unsigned int Xil_Out32(unsigned int Addr, unsigned int Value);""") self._ffi.cdef("""unsigned int Xil_In32(unsigned int Addr);""") self._ffi.cdef("""void _Pynq_record(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") self._ffi.cdef("""void _Pynq_play(unsigned int BaseAddr, unsigned int * BufAddr, unsigned int Num_Samles_32Bit);""") char_adrp = self._ffi.from_buffer(self._AudioMMIO.mem) self._uint_adrpv = self._ffi.cast('unsigned int', char_adrp) self.buffer = numpy.zeros(0).astype(numpy.int) self.sample_rate = 0 self.sample_len = 0
class ST: def __init__(self): ol = Overlay("SCS_ST_TEST_wrapper.bit", 0) ol.download() self.DATA = MMIO(0x41200000, 0x10000) self.UTIL = MMIO(0x41210000, 0x10000) def wait_for_rdy(self): while (self.DATA.read(0x8) & 0b1) == 0: pass def read_time(self): ctime = self.DATA.read(0x0) / REF_CLK delvals = self.DATA.read(0x8) ctime = ctime + (((delvals & 0b111111110) >> 1) - ((delvals & 0b11111111000000000) >> 9)) * FTIME return ctime def uencode(self, val, length): cnt = 0 for i in range(length): if ((val >> i) & 0b1 == 1): cnt += 1 return cnt def read_proc(self): self.UTIL.write(0x0, 0x1) self.wait_for_rdy() timev = self.read_time() self.UTIL.write(0x0, 0x0) return timev
def init(): Clocks.fclk0_mhz = 100 overlay = Overlay("./bit/replica_salesman.bit", download=True) mem_address = overlay.ip_dict['vtop_0']['phys_addr'] mem_range = overlay.ip_dict['vtop_0']['addr_range'] global mm_mem mm_mem = MMIO(mem_address, mem_range) return
def __init__(self, mode): if mode == 0: self.PC_OV = Overlay("TDC/TDC_OVERLAY_wrapper.bit", 0) print("Loaded two channel coincidence rising edge TDC") elif mode == 1: self.PC_OV = Overlay("TDC/SC_TDC_OVERLAY.bit", 0) print("Loaded single channel inter rising edge TDC") else: print("What?") self.PC_OV = Overlay("TDC/TDC_OVERLAY_wrapper.bit", 0) print("Loaded two channel coincidence rising edge TDC") self.PC_OV.download() self.GPIO = MMIO(it_a_gpio_addr, axi_gpio_range) self.GPIO_INT = MMIO(it_a_gpioi_addr, axi_gpio_range) self.GPIO.write(ch1_dir, 0xFFFFFFFF) self.GPIO.write(ch2_dir, 0x0) self.GPIO_INT.write(ch1_dir, 0xFFFFFFFF) self.GPIO.write(ch2_data, 0x0) #Hold system in reset for now
def __init__(self, if_id, switch_config): """Return a new instance of a DevMode object. Parameters ---------- if_id : int The interface ID (1,2,3) corresponding to (PMODA,PMODB,ARDUINO). switch_config : list IO Processor switch configuration (8 or 19 integers). """ if not if_id in [PMODA, PMODB, ARDUINO]: raise ValueError("No such IOP for DevMode.") self.if_id = if_id self.iop = request_iop(if_id, iop_const.MAILBOX_PROGRAM) self.iop_switch_config = list(switch_config) self.mmio = MMIO(self.iop.mmio.base_addr + iop_const.MAILBOX_OFFSET, \ iop_const.MAILBOX_SIZE)
def shutdown(self): """Shutdown the AXI connections to the PL in preparation for reconfiguration """ from pynq import MMIO ip = self.ip_dict for name, details in ip.items(): if details['type'] == 'xilinx.com:ip:pr_axi_shutdown_manager:1.0': mmio = MMIO(details['phys_addr'], device=self) # Request shutdown mmio.write(0x0, 0x1) i = 0 while mmio.read(0x0) != 0x0F and i < 16000: i += 1 if i >= 16000: warnings.warn("Timeout for shutdown manager. It's likely " "the configured bitstream and metadata " "don't match.")
def test_mmio(): """Test whether MMIO class is working properly. Generate random tests to swipe through the entire range: >>> mmio.write(all offsets, random data) Steps: 1. Initialize an instance with length in bytes 2. Write an integer to a given offset. 3. Write a number within the range [0, 2^32-1] into a 4-byte location. 4. Change to the next offset and repeat. """ ol = Overlay('base.bit') ol.download() sleep(0.2) mmio_base = int(ol.get_ip_addr_base('SEG_mb_bram_ctrl_1_Mem0'),16) mmio_range = int(ol.get_ip_addr_range('SEG_mb_bram_ctrl_1_Mem0'),16) mmio = MMIO(mmio_base, mmio_range) for offset in range(0, 100, general_const.MMIO_WORD_LENGTH): data1 = randint(0, pow(2,32)-1) mmio.write(offset, data1) sleep(0.02) data2 = mmio.read(offset) assert data1==data2, \ 'MMIO read back a wrong random value at offset {}.'.format(offset) mmio.write(offset, 0) sleep(0.02) assert mmio.read(offset)==0, \ 'MMIO read back a wrong fixed value at offset {}.'.format(offset) del ol
class Trace_Buffer: """Class for the trace buffer, leveraging the sigrok libraries. This trace buffer class gets the traces from DMA and processes it using the sigrok commands. Note ---- The `sigrok-cli` library has to be installed before using this class. Attributes ---------- protocol : str The protocol the sigrok decoder are using. trace_csv: str The absolute path of the trace file `*.csv`. trace_sr: str The absolute path of the trace file `*.sr`, translated from `*.csv`. trace_pd : str The absolute path of the decoded file by sigrok. probes : list The list of probes used for the trace. dma : DMA The DMA object associated with the trace buffer. ctrl : MMIO The MMIO class used to control the DMA. samplerate: int The samplerate of the traces. data : cffi.FFI.CData The pointer to the starting address of the trace data. """ def __init__(self, if_id, protocol, trace=None, data=None, samplerate=500000): """Return a new trace buffer object. Users have to specify the location of the traces, even if no trace has been imported from DMA yet. This method will construct the trace from the DMA data. The maximum sample rate is 100MHz. Note ---- The probes selected by `mask` does not include any tristate probe. Parameters ---------- if_id : int The interface ID (PMODA, PMODB, ARDUINO). protocol : str The protocol the sigrok decoder are using. trace: str The relative/absolute path of the trace file. data : cffi.FFI.CData The pointer to the starting address of the data. samplerate : int The rate of the samples. """ if os.geteuid() != 0: raise EnvironmentError('Root permissions required.') if not isinstance(protocol, str): raise TypeError("Protocol name has to be a string.") if data != None: if not isinstance(data, cffi.FFI.CData): raise TypeError("Data pointer has wrong type.") if not isinstance(samplerate, int): raise TypeError("Sample rate has to be an integer.") if not 1 <= samplerate <= 100000000: raise ValueError("Sample rate out of range.") if if_id in [PMODA, PMODB]: dma_base = int(PL.ip_dict["SEG_axi_dma_0_Reg"][0],16) ctrl_base = int(PL.ip_dict["SEG_trace_cntrl_0_Reg2"][0],16) ctrl_range = int(PL.ip_dict["SEG_trace_cntrl_0_Reg2"][1],16) elif if_id in [ARDUINO]: dma_base = int(PL.ip_dict["SEG_axi_dma_0_Reg1"][0],16) ctrl_base = int(PL.ip_dict["SEG_trace_cntrl_0_Reg"][0],16) ctrl_range = int(PL.ip_dict["SEG_trace_cntrl_0_Reg"][1],16) else: raise ValueError("No such IOP for instrumentation.") self.dma = DMA(dma_base, direction=1) self.ctrl = MMIO(ctrl_base, ctrl_range) self.samplerate = samplerate self.protocol = protocol self.data = data self.probes = [] self.trace_pd = '' if trace != None: if not isinstance(trace, str): raise TypeError("Trace path has to be a string.") if not os.path.isfile(trace): trace_abs = os.getcwd() + '/' + trace else: trace_abs = trace if not os.path.isfile(trace_abs): raise ValueError("Specified trace file does not exist.") _, format = os.path.splitext(trace_abs) if format == '.csv': self.trace_csv = trace_abs self.trace_sr = '' elif format == '.sr': self.trace_sr = trace_abs self.trace_csv = '' else: raise ValueError("Only supporting csv or sr files.") def __del__(self): """Destructor for trace buffer object. Parameters ---------- None Returns ------- None """ del(self.dma) def start(self, timeout=10): """Start the DMA to capture the traces. Parameters ---------- timeout : int The time in number of milliseconds to wait for DMA to be idle. Return ------ None """ # Create buffer self.dma.create_buf(MAX_NUM_SAMPLES*8) self.dma.transfer(MAX_NUM_SAMPLES*8, direction=1) # Wait for DMA to be idle timer = timeout while (self.ctrl.read(0x00) & 0x04)==0: sleep(0.001) timer -= 1 if (timer==0): raise RuntimeError("Timeout when waiting DMA to be idle.") # Configuration self.ctrl.write(TRACE_LENGTH_OFFSET, MAX_NUM_SAMPLES) self.ctrl.write(TRACE_SAMPLE_RATE_OFFSET, \ int(MAX_SAMPLE_RATE / self.samplerate)) self.ctrl.write(TRACE_CMP_LSW_OFFSET, 0x00000) self.ctrl.write(TRACE_CMP_MSW_OFFSET, 0x00000) # Start the DMA self.ctrl.write(TRACE_CTRL_OFFSET,0x01) self.ctrl.write(TRACE_CTRL_OFFSET,0x00) def stop(self): """Stop the DMA after capture is done. Note ---- There is an internal timeout mechanism in the DMA class. Parameters ---------- None Return ------ None """ # Wait for the DMA self.dma.wait() # Get 64-bit samples from DMA self.data = self.dma.get_buf(64) def show(self): """Show information about the specified protocol. Parameters ---------- None Return ------ None """ if os.system("sigrok-cli --protocol-decoders " + \ self.protocol+" --show"): raise RuntimeError('Sigrok-cli show failed.') def csv2sr(self): """Translate the `*.csv` file to `*.sr` file. The translated `*.sr` files can be directly used in PulseView to show the waveform. Note ---- This method also modifies the input `*.csv` file (the comment header, usually 3 lines, will be removed). Parameters ---------- None Return ------ None """ name, _ = os.path.splitext(self.trace_csv) self.trace_sr = name + ".sr" temp = name + ".temp" if os.system("rm -rf " + self.trace_sr): raise RuntimeError('Trace sr file cannot be deleted.') in_file = open(self.trace_csv, 'r') out_file = open(temp, 'w') # Copy only the contents; ignore comments for i, line in enumerate(in_file): if not line.startswith(';'): out_file.write(line) in_file.close() out_file.close() os.remove(self.trace_csv) os.rename(temp, self.trace_csv) command = "sigrok-cli -i " + self.trace_csv + \ " -I csv -o " + self.trace_sr if os.system(command): raise RuntimeError('Sigrok-cli csv to sr failed.') def sr2csv(self): """Translate the `*.sr` file to `*.csv` file. The translated `*.csv` files can be used for interactive plotting. It is human readable. Note ---- This method also removes the redundant header that is generated by sigrok. Parameters ---------- None Return ------ None """ name, _ = os.path.splitext(self.trace_sr) self.trace_csv = name + ".csv" temp = name + ".temp" if os.system("rm -rf " + self.trace_csv): raise RuntimeError('Trace csv file cannot be deleted.') command = "sigrok-cli -i " + self.trace_sr + \ " -O csv > " + temp if os.system(command): raise RuntimeError('Sigrok-cli sr to csv failed.') in_file = open(temp, 'r') out_file = open(self.trace_csv, 'w') # Copy only the contents; ignore comments for i, line in enumerate(in_file): if not line.startswith(';'): out_file.write(line) in_file.close() out_file.close() os.remove(temp) def decode(self, decoded_file, options=''): """Decode and record the trace based on the protocol specified. The `decoded_file` contains the name of the output file. The `option` specifies additional options to be passed to sigrok-cli. For example, users can use option=':wordsize=9:cpol=1:cpha=0' to add these options for the SPI decoder. The decoder will also ignore the pin collected but not required for decoding. Note ---- The output file will have `*.pd` extension. Note ---- The decoded file will be put into the specified path, or in the working directory in case the path does not exist. Parameters ---------- decoded_file : str The name of the file recording the outputs. options : str Additional options to be passed to sigrok-cli. Return ------ None """ if not isinstance(decoded_file, str): raise TypeError("File name has to be a string.") if self.probes == []: raise ValueError("Cannot decode without metadata.") if os.path.isdir(os.path.dirname(decoded_file)): decoded_abs = decoded_file else: decoded_abs = os.getcwd() + '/' + decoded_file name, _ = os.path.splitext(self.trace_sr) temp_file = name + '.temp' if os.system('rm -rf ' + temp_file): raise RuntimeError("Cannot remove temporary file.") self.trace_pd = '' if os.system('rm -rf ' + decoded_abs): raise RuntimeError("Cannot remove old decoded file.") pd_annotation = '' for i in self.probes: if not i=='NC': # Ignore pins not connected to device pd_annotation += (':'+i.lower()+'='+i) command = "sigrok-cli -i " + self.trace_sr + " -P " + \ self.protocol + options + pd_annotation + (' > ' + temp_file) if os.system(command): raise RuntimeError('Sigrok-cli decode failed.') f_decoded = open(decoded_abs, 'w') f_temp = open(temp_file, 'r') j = 0 for line in f_temp: m = re.search('([0-9]+)-([0-9]+) (.*)', line) if m: while (j < int(m.group(1))): f_decoded.write('\n') j += 1 while (j <= int(m.group(2))): f_decoded.write(m.group(3) + '\n') j += 1 f_temp.close() f_decoded.close() self.trace_pd = decoded_abs if os.system('rm -rf ' + temp_file): raise RuntimeError("Cannot remove temporary file.") if os.path.getsize(self.trace_pd)==0: raise RuntimeError("No transactions and decoded file is empty.") def set_metadata(self, probes): """Set metadata for the trace. A `*.sr` file directly generated from `*.csv` will not have any metadata. This method helps to set the sample rate, probe names, etc. The list `probes` depends on the protocol. For instance, the I2C protocol requires a list of ['SDA','SCL']. Parameters ---------- probes : list A list of probe names. Return ------ None """ if not isinstance(probes, list): raise TypeError("Probes have to be in a list.") # Convert csv file to sr file, if necessary if self.trace_sr == '': self.csv2sr() self.probes = probes name, _ = os.path.splitext(self.trace_sr) if os.system("rm -rf " + name): raise RuntimeError('Directory cannot be deleted.') if os.system("mkdir " + name): raise RuntimeError('Directory cannot be created.') if os.system("unzip -q "+ self.trace_sr + " -d " + name): raise RuntimeError('Unzip sr file failed.') metadata = open(name + '/metadata', 'r') temp = open(name + '/temp', 'w') pat = "samplerate=0 Hz" subst = "samplerate=" + str(self.samplerate) +" Hz" j = 0 for i, line in enumerate(metadata): if line.startswith("probe"): # Set the probe names temp.write("probe"+str(j+1)+"="+probes[j]+'\n') j += 1 else: # Set the sample rate temp.write(line.replace(pat, subst)) metadata.close() temp.close() if os.system("rm -rf "+ name + '/metadata'): raise RuntimeError('Cannot remove metadata folder.') if os.system("mv " + name + '/temp ' + name + '/metadata'): raise RuntimeError('Cannot rename metadata folder.') if os.system("cd "+ name +"; zip -rq " + \ self.trace_sr + " * ; cd .."): raise RuntimeError('Zip sr file failed.') if os.system("rm -rf " + name): raise RuntimeError('Cannnot remove temporary folder.') def parse(self, parsed, start=0, stop=MAX_NUM_SAMPLES, mask=MASK_ALL, tri_sel=[], tri_0=[], tri_1=[]): """Parse the input data and generate a `*.csv` file. This method can be used along with the DMA. The input data is assumed to be 64-bit. The generated `*.csv` file can be then used as the trace file. To extract certain bits from the 64-bit data, use the parameter `mask`. Note ---- The probe pins selected by `mask` does not include any tristate probe. To specify a set of tristate probe pins, e.g., users can set tri_sel = [0x0000000000000004], tri_0 = [0x0000000000000010], and tri_1 = [0x0000000000000100]. In this example, the 3rd probe from the LSB is the selection probe; the 5th probe is selected if selection probe is 0, otherwise the 9th probe is selected. There can be multiple sets of tristate probe pins. Note ---- The parsed file will be put into the specified path, or in the working directory in case the path does not exist. Parameters ---------- parsed : str The file name of the parsed output. start : int The first 64-bit sample of the trace. stop : int The last 64-bit sample of the trace. mask : int A 64-bit mask to be applied to the 64-bit samples. tri_sel : list The list of tristate selection probe pins. tri_0 : list The list of probe pins selected when the selection probe is 0. tri_1 : list The list probe pins selected when the selection probe is 1. Return ------ None """ if not isinstance(parsed, str): raise TypeError("File name has to be an string.") if not isinstance(start, int): raise TypeError("Sample number has to be an integer.") if not isinstance(stop, int): raise TypeError("Sample number has to be an integer.") if not 1 <= (stop-start) <= MAX_NUM_SAMPLES: raise ValueError("Data length has to be in [1,{}]."\ .format(MAX_NUM_SAMPLES)) if not isinstance(mask, int): raise TypeError("Data mask has to be an integer.") if not 0<=mask<=MASK_ALL: raise ValueError("Data mask out of range.") if not isinstance(tri_sel, list): raise TypeError("Selection probe pins have to be in a list.") if not isinstance(tri_0, list) or not isinstance(tri_1, list): raise TypeError("Data probe pins have to be in a list.") if not len(tri_sel)==len(tri_0)==len(tri_1): raise ValueError("Inconsistent length for tristate lists.") for element in tri_sel: if not isinstance(element, int) or not 0<element<=MASK_ALL: raise TypeError("Selection probe has to be an integer.") if not (element & element-1)==0: raise ValueError("Selection probe can only have 1-bit set.") if not (element & mask)==0: raise ValueError("Selection probe has be excluded from mask.") for element in tri_0: if not isinstance(element, int) or not 0<element<=MASK_ALL: raise TypeError("Data probe has to be an integer.") if not (element & element-1)==0: raise ValueError("Data probe can only have 1-bit set.") if not (element & mask)==0: raise ValueError("Data probe has be excluded from mask.") for element in tri_1: if not isinstance(element, int) or not 0<element<=MASK_ALL: raise TypeError("Data probe has to be an integer.") if not (element & element-1)==0: raise ValueError("Data probe can only have 1-bit set.") if not (element & mask)==0: raise ValueError("Data probe has be excluded from mask.") if os.path.isdir(os.path.dirname(parsed)): parsed_abs = parsed else: parsed_abs = os.getcwd() + '/' + parsed if os.system('rm -rf ' + parsed_abs): raise RuntimeError("Cannot remove old parsed file.") with open(parsed_abs, 'w') as f: for i in range(start, stop): raw_val = self.data[i] & MASK_ALL list_val = [] for j in range(63,-1,-1): if (mask & 1<<j)>>j: list_val.append(str((raw_val & 1<<j)>>j)) else: for selection in tri_sel: idx = tri_sel.index(selection) if (selection & 1<<j)>>j: if ((raw_val & 1<<j)>>j)==0: log = tri_0[idx].bit_length()-1 list_val.append( str((raw_val & 1<<log)>>log)) else: log = tri_1[idx].bit_length()-1 list_val.append( str((raw_val & 1<<log)>>log)) temp = ','.join(list_val) f.write(temp + '\n') self.trace_csv = parsed_abs self.trace_sr = '' def display(self, start_pos, stop_pos): """Draw digital waveforms in ipython notebook. It utilises the wavedrom java script library, documentation for which can be found here: https://code.google.com/p/wavedrom/. Note ---- Only use this method in Jupyter notebook. Note ---- WaveDrom.js and WaveDromSkin.js are required under the subdirectory js. Example of the data format to draw waveform: >>> data = {'signal': [ {'name': 'clk', 'wave': 'p.....|...'}, {'name': 'dat', 'wave': 'x.345x|=.x', 'data': ['D','A','T','A']}, {'name': 'req', 'wave': '0.1..0|1.0'}, {}, {'name': 'ack', 'wave': '1.....|01.'} ]} Parameters ---------- start_pos : int The starting sample number (relative to the trace). stop_pos : int The stopping sample number (relative to the trace). Returns ------- None """ if self.probes == []: raise ValueError("Cannot display without metadata.") if not isinstance(start_pos, int): raise TypeError("Start position has to be an integer.") if not 1 <= start_pos <= MAX_NUM_SAMPLES: raise ValueError("Start position out of range.") if not isinstance(stop_pos, int): raise TypeError("Stop position has to be an integer.") if not 1 <= stop_pos <= MAX_NUM_SAMPLES: raise ValueError("Stop position out of range.") # Copy the javascript to the notebook location if os.system("cp -rf " + \ os.path.dirname(os.path.realpath(__file__)) + \ '/js' + ' ./'): raise RuntimeError('Cannnot copy wavedrom javascripts.') # Convert sr file to csv file, if necessary if self.trace_csv == '': self.sr2csv() # Read csv trace file with open(self.trace_csv, 'r') as data_file: csv_data = list(csv.reader(data_file)) # Read decoded file with open(self.trace_pd, 'r') as pd_file: pd_data = list(csv.reader(pd_file)) # Construct the decoded transactions data = {} data['signal']=[] if self.trace_pd != '': temp_val = {'name': '', 'wave': '', 'data': []} for i in range(start_pos, stop_pos): if i==start_pos: ref = pd_data[i] if not ref: temp_val['wave'] += 'x' else: temp_val['wave'] += '4' temp_val['data'].append(''.join(pd_data[i])) else: if pd_data[i] == ref: temp_val['wave'] += '.' else: ref = pd_data[i] if not ref: temp_val['wave'] += 'x' else: temp_val['wave'] += '4' temp_val['data'].append(''.join(pd_data[i])) data['signal'].append(temp_val) # Construct the jason format data for signal_name in self.probes: index = self.probes.index(signal_name) temp_val = {'name': signal_name, 'wave': ''} for i in range(start_pos, stop_pos): if i==start_pos: ref = csv_data[i][index] temp_val['wave'] += str(csv_data[i][index]) else: if csv_data[i][index] == ref: temp_val['wave'] += '.' else: ref = csv_data[i][index] temp_val['wave'] += str(csv_data[i][index]) data['signal'].append(temp_val) # Construct the sample numbers and headers head = {} head['text'] = ['tspan', {'class':'info h4'}, \ 'Protocol decoder: ' + self.protocol + \ '; Sample rate: ' + str(self.samplerate) + ' samples/s'] head['tock'] = '' for i in range(start_pos, stop_pos): if i%2: head['tock'] += ' ' else: head['tock'] += (str(i)+' ') data['head'] = head htmldata = '<script type="WaveDrom">' + json.dumps(data) + '</script>' IPython.core.display.display_html(IPython.core.display.HTML(htmldata)) jsdata = 'WaveDrom.ProcessAll();' IPython.core.display.display_javascript( IPython.core.display.Javascript( data=jsdata, \ lib=['files/js/WaveDrom.js', 'files/js/WaveDromSkin.js']))
class DevMode(object): """Control an IO processor running the developer mode program. This class will wait for Python to send commands to Pmod / Arduino IO, IIC, or SPI. Attributes ---------- if_id : int The interface ID (1,2,3) corresponding to (PMODA,PMODB,ARDUINO). iop : _IOP IO processor instance used by DevMode. iop_switch_config :list IO processor switch configuration (8 or 19 integers). mmio : MMIO Memory-mapped IO instance to read and write instructions and data. """ def __init__(self, if_id, switch_config): """Return a new instance of a DevMode object. Parameters ---------- if_id : int The interface ID (1,2,3) corresponding to (PMODA,PMODB,ARDUINO). switch_config : list IO Processor switch configuration (8 or 19 integers). """ if not if_id in [PMODA, PMODB, ARDUINO]: raise ValueError("No such IOP for DevMode.") self.if_id = if_id self.iop = request_iop(if_id, iop_const.MAILBOX_PROGRAM) self.iop_switch_config = list(switch_config) self.mmio = MMIO(self.iop.mmio.base_addr + iop_const.MAILBOX_OFFSET, \ iop_const.MAILBOX_SIZE) def start(self): """Start the IO Processor. The IOP instance will start automatically after instantiation. This method will: 1. zero out mailbox CMD register; 2. load switch config; 3. set IOP status as "RUNNING". """ self.iop.start() self.mmio.write(iop_const.MAILBOX_PY2IOP_CMD_OFFSET, 0) self.load_switch_config(self.iop_switch_config) def stop(self): """Put the IO Processor into Reset. This method will set IOP status as "STOPPED". """ self.iop.stop() def load_switch_config(self, config=None): """Load the IO processor's switch configuration. This method will update switch config. Parameters ---------- config: list A switch configuration list of integers. Raises ---------- TypeError If the config argument is not of the correct type. """ if self.if_id in [PMODA, PMODB]: if config == None: config = iop_const.PMOD_SWCFG_DIOALL elif not len(config) == iop_const.PMOD_SWITCHCONFIG_NUMREGS: raise TypeError('Invalid switch config {}.'.format(config)) # Build switch config word self.iop_switch_config = config sw_config_word = 0 for ix, cfg in enumerate(self.iop_switch_config): sw_config_word |= (cfg << ix*4) # Disable, configure, enable switch self.write_cmd(iop_const.PMOD_SWITCHCONFIG_BASEADDR + 4, 0) self.write_cmd(iop_const.PMOD_SWITCHCONFIG_BASEADDR, \ sw_config_word) self.write_cmd(iop_const.PMOD_SWITCHCONFIG_BASEADDR + 7, \ 0x80, dWidth=1) elif self.if_id in [ARDUINO]: if config == None: config = iop_const.ARDUINO_SWCFG_DIOALL elif not len(config) == iop_const.ARDUINO_SWITCHCONFIG_NUMREGS: raise TypeError('Invalid switch config {}.'.format(config)) # Build switch config word self.iop_switch_config = config sw_config_words = [0, 0, 0, 0] for ix, cfg in enumerate(self.iop_switch_config): if ix < 6: sw_config_words[0] |= (cfg << ix*2) elif ix == 6: sw_config_words[0] |= (cfg << 31) elif 7 <= ix < 11: sw_config_words[1] |= (cfg << (ix-7)*4) elif 11 <= ix < 15: sw_config_words[2] |= (cfg << (ix-11)*4) else: sw_config_words[3] |= (cfg << (ix-15)*4) # Configure switch for i in range(4): self.write_cmd(iop_const.ARDUINO_SWITCHCONFIG_BASEADDR + \ 4*i, sw_config_words[i]) else: raise ValueError("Cannot load switch for unknown IOP.") def status(self): """Returns the status of the IO processor. Parameters ---------- None Returns ------- str The IOP status ("IDLE", "RUNNING", or "STOPPED"). """ return self.iop.state def write_cmd(self, address, data, dWidth=4, dLength=1, timeout=10): """Send a write command to the mailbox. Parameters ---------- address : int The address tied to IO processor's memory map. data : int 32-bit value to be written (None for read). dWidth : int Command data width. dLength : int Command burst length (currently only supporting dLength 1). timeout : int Time in milliseconds before function exits with warning. Returns ------- None """ return self._send_cmd(iop_const.WRITE_CMD, address, data, dWidth=dWidth, timeout=timeout) def read_cmd(self, address, dWidth=4, dLength=1, timeout=10): """Send a read command to the mailbox. Parameters ---------- address : int The address tied to IO processor's memory map. dWidth : int Command data width. dLength : int Command burst length (currently only supporting dLength 1). timeout : int Time in milliseconds before function exits with warning. Returns ------- list A list of data returned by MMIO read. """ return self._send_cmd(iop_const.READ_CMD, address, None, dWidth=dWidth, timeout=timeout) def is_cmd_mailbox_idle(self): """Check whether the IOP command mailbox is idle. Parameters ---------- None Returns ------- bool True if IOP command mailbox idle. """ mb_cmd_word = self.mmio.read(iop_const.MAILBOX_PY2IOP_CMD_OFFSET) return (mb_cmd_word & 0x1) == 0 def get_cmd_word(self, cmd, dWidth, dLength): """Build the command word. Note ---- The returned command word has the following format: Bit [0] : valid bit. Bit [2:1] : command data width. Bit [3] : command type (read or write). Bit [15:8] : command burst length. Bit [31:16] : unused. Parameters ---------- cmd : int Either 1 (read IOP register) or 0 (write IOP register). dWidth : int Command data width. dLength : int Command burst length (currently only supporting dLength 1). Returns ------- int The command word following a specific format. """ word = 0x1 # cmd valid word = word | (dWidth-1) << 1 # cmd dataWidth (3->4B, 1->2B, 0->1B) word = word | (cmd) << 3 # cmd type (1->RD, 0->WR) word = word | (dLength) << 8 # cmd burst length (1->1 word) word = word | (0) << 16 # unused return word def _send_cmd(self, cmd, address, data, dWidth=4, dLength=1, timeout=10): """Send a command to the IO processor via mailbox. Note ---- User should avoid to call this method directly. Use the read_cmd() or write_cmd() instead. Example: >>> _send_cmd(1, 4, None) # Read address 4. Parameters ---------- cmd : int Either 1 (read IOP Reg) or 0 (write IOP Reg). address : int The address tied to IO processor's memory map. data : int 32-bit value to be written (None for read). dWidth : int Command data width. dLength : int Command burst length (currently only supporting dLength 1). timeout : int Time in milliseconds before function exits with warning. Raises ------ LookupError If it takes too long to receive the ACK from the IOP. """ self.mmio.write(iop_const.MAILBOX_PY2IOP_ADDR_OFFSET, address) if data != None: self.mmio.write(iop_const.MAILBOX_PY2IOP_DATA_OFFSET, data) # Build the write command cmd_word = self.get_cmd_word(cmd, dWidth, dLength) self.mmio.write(iop_const.MAILBOX_PY2IOP_CMD_OFFSET, cmd_word) # Wait for ACK in steps of 1ms cntdown = timeout while not self.is_cmd_mailbox_idle() and cntdown > 0: time.sleep(0.001) cntdown -= 1 # If ACK is not received, alert users. if cntdown == 0: raise LookupError("DevMode _send_cmd() not acknowledged.") # Return data if expected from read, otherwise return None if cmd == iop_const.WRITE_CMD: return None else: return self.mmio.read(iop_const.MAILBOX_PY2IOP_DATA_OFFSET)
def __init__(self, if_id, protocol, trace=None, data=None, samplerate=500000): """Return a new trace buffer object. Users have to specify the location of the traces, even if no trace has been imported from DMA yet. This method will construct the trace from the DMA data. The maximum sample rate is 100MHz. Note ---- The probes selected by `mask` does not include any tristate probe. Parameters ---------- if_id : int The interface ID (PMODA, PMODB, ARDUINO). protocol : str The protocol the sigrok decoder are using. trace: str The relative/absolute path of the trace file. data : cffi.FFI.CData The pointer to the starting address of the data. samplerate : int The rate of the samples. """ if os.geteuid() != 0: raise EnvironmentError('Root permissions required.') if not isinstance(protocol, str): raise TypeError("Protocol name has to be a string.") if data != None: if not isinstance(data, cffi.FFI.CData): raise TypeError("Data pointer has wrong type.") if not isinstance(samplerate, int): raise TypeError("Sample rate has to be an integer.") if not 1 <= samplerate <= 100000000: raise ValueError("Sample rate out of range.") if if_id in [PMODA, PMODB]: dma_base = int(PL.ip_dict["SEG_axi_dma_0_Reg"][0],16) ctrl_base = int(PL.ip_dict["SEG_trace_cntrl_0_Reg2"][0],16) ctrl_range = int(PL.ip_dict["SEG_trace_cntrl_0_Reg2"][1],16) elif if_id in [ARDUINO]: dma_base = int(PL.ip_dict["SEG_axi_dma_0_Reg1"][0],16) ctrl_base = int(PL.ip_dict["SEG_trace_cntrl_0_Reg"][0],16) ctrl_range = int(PL.ip_dict["SEG_trace_cntrl_0_Reg"][1],16) else: raise ValueError("No such IOP for instrumentation.") self.dma = DMA(dma_base, direction=1) self.ctrl = MMIO(ctrl_base, ctrl_range) self.samplerate = samplerate self.protocol = protocol self.data = data self.probes = [] self.trace_pd = '' if trace != None: if not isinstance(trace, str): raise TypeError("Trace path has to be a string.") if not os.path.isfile(trace): trace_abs = os.getcwd() + '/' + trace else: trace_abs = trace if not os.path.isfile(trace_abs): raise ValueError("Specified trace file does not exist.") _, format = os.path.splitext(trace_abs) if format == '.csv': self.trace_csv = trace_abs self.trace_sr = '' elif format == '.sr': self.trace_sr = trace_abs self.trace_csv = '' else: raise ValueError("Only supporting csv or sr files.")