def _set_frequency(self, frequency): """Convert a frequency value into a TCK divisor setting""" if frequency > self.frequency_max: raise FtdiError("Unsupported frequency: %f" % frequency) if frequency <= Ftdi.BUS_CLOCK_BASE: divcode = Ftdi.ENABLE_CLK_DIV5 divisor = int(Ftdi.BUS_CLOCK_BASE/frequency)-1 actual_freq = Ftdi.BUS_CLOCK_BASE/(divisor+1) elif frequency <= Ftdi.BUS_CLOCK_HIGH: # not supported on non-H device, however it seems that 2232D # devices simply ignore the settings. Could be improved though divcode = Ftdi.DISABLE_CLK_DIV5 divisor = int(Ftdi.BUS_CLOCK_HIGH/frequency)-1 actual_freq = Ftdi.BUS_CLOCK_HIGH/(divisor+1) else: raise FtdiError("Unsupported frequency: %f" % frequency) # FTDI expects little endian if self.ic_name in self.HISPEED_DEVICES: cmd = Array('B', (divcode,)) else: cmd = Array('B') cmd.extend((Ftdi.TCK_DIVISOR, divisor & 0xff, (divisor >> 8) & 0xff)) self.write_data(cmd) self.validate_mpsse() # Drain input buffer self.purge_rx_buffer() return actual_freq
def stream_read_write_bram(dut): """ Description: Read and write data to the block ram Test ID: 2 Expected Results: Write Data the Block RAM through Wishbone interface Read Same data from the block RAM through wishbone interface """ dut.test_id = 2 nysa = NysaSim(dut, SIM_CONFIG, CLK_PERIOD, user_paths = [MODULE_PATH]) setup_dut(dut) yield(nysa.reset()) nysa.read_sdb() yield(nysa.wait_clocks(10)) driver = wb_hs_demoDriver(nysa, nysa.find_device(wb_hs_demoDriver)[0]) data = Array('B') SIZE =1024 for i in range(SIZE): data.append(i % 256) yield cocotb.external(driver.write_data)(0x00, data) yield (nysa.wait_clocks(100)) v = yield cocotb.external(driver.read_data)(0x00, (SIZE / 4)) if len(v) != len(data): raise cocotb.result.TestFailure("Test %d: Length of incomming data and outgoing data is equal %d = %d" % (dut.test_id, len(v), len(data))) for i in range(len(data)): if v[i] != data[i]: raise cocotb.result.TestFailure("Test %d: Address 0x%02X 0x%02X != 0x%02X" % (dut.test_id, i, v[i], data[i])) dut.log.info("Success")
def memory_read_write_test(dut): dut.test_id <= 1 print "module path: %s" % MODULE_PATH nysa = NysaSim(dut, SIM_CONFIG, CLK_PERIOD, user_paths = [MODULE_PATH]) setup_dut(dut) yield(nysa.reset()) nysa.read_sdb() yield (nysa.wait_clocks(10)) nysa.pretty_print_sdb() driver = wb_master_testDriver(nysa, nysa.find_device(wb_master_testDriver)[0]) yield (nysa.wait_clocks(10)) dut.log.info("Ready") LENGTH = 100 DATA = Array('B') for i in range (LENGTH): DATA.append(i % 256) while len(DATA) % 4 != 0: DATA.append(0) yield cocotb.external(nysa.write_memory)(0x00000, DATA) data = yield cocotb.external(nysa.read_memory)(0x00000, (len(DATA) / 4)) for i in range (len(DATA)): if DATA[i] != data[i]: log.error("Failed at Address: %04d: 0x%02X != 0x%02X" % (i, DATA[i], data[i]))
def write(self, address, data): """SST25 uses a very specific implementation to write data. It offers very poor performances, because the device lacks an internal buffer which translates into an ultra-heavy load on SPI bus. However, the device offers lightning-speed for flash data erasure""" if address+len(data) > len(self): raise SerialFlashValueError('Cannot fit in flash area') if not isinstance(data, Array): data = Array('B', data) length = len(data) if (address&0x1) or (length&0x1) or (length==0): raise AssertionError("Alignement/size not supported") self._unprotect() self._enable_write() aai_cmd = Array('B', [Sst25FlashDevice.CMD_PROGRAM_WORD, (address>>16)&0xff, (address>>8)&0xff, address&0xff, data.pop(0), data.pop(0)]) offset = 0 percent = 0.0 while True: percent = (1000.0*offset/length) offset += 2 self._spi.exchange(aai_cmd) while self.is_busy(): time.sleep(0.01) # 10 ms if not data: break aai_cmd = Array('B', [Sst25FlashDevice.CMD_PROGRAM_WORD, data.pop(0), data.pop(0)]) self._disable_write()
def dword_to_array(value): out = Array('B') out.append((value >> 24) & 0xFF) out.append((value >> 16) & 0xFF) out.append((value >> 8) & 0xFF) out.append((value >> 0) & 0xFF) return out
class UARTCommReader(BusDriver): _signals = ["rd_data", "rd_stb"] def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.read_data_busy = Lock("%s_wbusy" % name) self.data = Array('B') @cocotb.coroutine def read(self, size): yield self.read_data_busy.acquire() self.data = Array('B') count = 0 while count < size: yield ReadOnly() yield RisingEdge(self.clock) if self.bus.rd_stb.value == 1: self.data.append(self.bus.rd_data.value) count += 1 yield RisingEdge(self.clock) self.read_data_busy.release() def get_data(self): return self.data
def read(self, address, length = 1, disable_auto_inc = False): """read Generic read command used to read data from a Nysa image Args: length (int): Number of 32 bit words to read from the FPGA address (int): Address of the register/memory to read disable_auto_inc (bool): if true, auto increment feature will be disabled Returns: (Array of unsigned bytes): A byte array containtin the raw data returned from Nysa Raises: NysaCommError: When a failure of communication is detected """ read_cmd = "L%07X00000002%08X00000000" read_cmd = (read_cmd) % (length, address) self.ser.flushInput() self.ser.write(read_cmd) read_resp = self.ser.read(24 + ((length) * 8)) response = Array('B') d = read_resp[24:] for i in range (0, len(d), 2): v = int(d[i], 16) << 4 v |= int(d[i + 1], 16) response.append(v) return response
def read_string(self, count = 1): """read_string Read a string of characters Args: count: the number of characters and returns a string if -1 read all characters Returns: string Raises: OlympusCommError: Error in communication """ if self.debug: print "read_string" data = Array('B') if count == -1: data = self.read_all_data() else: data = self.read_raw(count) string = data.tostring() return string
def read_voltage_range(self): # print "Read Volage range" # read_data = self.send_command(CMD_READ_VOLT, COMMAND_LENGTH + 32) # print "Read data: %s" % str(read_data) # self.get_r1_response(read_data) self.spi.set_character_length(COMMAND_LENGTH + 32) crc = self.generate_crc(CMD_READ_VOLT) data = Array('B', CMD_READ_VOLT) data.append(crc) self.spi.set_write_data(data) self.spi.start_transaction() while self.spi.is_busy(): print ".", time.sleep(0.01) read_data = self.spi.get_read_data(COMMAND_LENGTH + 32) r1 = 0xFF index = 0 for i in range (0, len(read_data)): if read_data[i] < 0x08: r1 = read_data[i] index = i #print "index: %d" % i self.print_r1_response(r1) print "read data: %s" % str(read_data)
def read_command(self, address, length): """ read data or status from the MCU, the length specifies how much data to read from the MCU after the address is written Args: address (integer): register address to write to length (integer): number of bytes to read from the register Returns: (Array of bytes) 8-bit value of the register Raises: NysaCommError: Error in communication """ output = Array('B') #Get the control register self.set_register_bit(CONTROL, CONTROL_COMMAND_MODE) #Tell the lcd command controller we are sending the command self.clear_register_bit(CONTROL, CONTROL_COMMAND_PARAMETER) #Put the data in the register self.write_register(COMMAND_DATA, address) #We are going to be writing self.set_register_bit(CONTROL, CONTROL_COMMAND_WRITE) for i in range (length): #Tell the lcd command controller we are sending parameters self.set_register_bit(CONTROL, CONTROL_COMMAND_PARAMETER) #We are going to be reading self.set_register_bit(CONTROL, CONTROL_COMMAND_READ) #Read the data from the data register output.append(self.read_register(COMMAND_DATA)) self.clear_register_bit(CONTROL, CONTROL_COMMAND_MODE) return output
def get_capture_data(self): """get_capture_data returns an array of the captured data Args: Nothing Return: Array of 32-bit unsigned values Raises: OlympusCommError: Error in communication LAError: Capture was not finished """ if not self.is_capture_finished(): raise LAError("Capture is not finished") #get the number of 32-bits to read count = self.get_data_count() print "Reading %d Vaues" % count data_in = self.o.read(self.dev_id, DATA, count) #change this to 32-bit value data_out = Array('L') print "Data in Lenght: %d" % len(data_in) print "Data length: %d" % len(data_out) for i in range(0, len(data_in), 4): data_out.append (data_in[i] << 24 | data_in[i + 1] << 16 | data_in[i + 2] << 8 | data_in[i + 3]) return data_out
def FindZeroes(mesh,func,Z=0,tol=0.001): try: MyRange = mesh.coordinates()[:] except AttributeError: MyRange=mesh pass x,y=MyArray('f'),MyArray('f') for i in MyRange: if Z==1: tmp=func(i[0],i[1]) if tmp < tol: x.append(i[0]) y.append(i[1]) else: tmp=func(i) print func(i),tmp if abs(tmp) < tol: x.append(i[0]) y.append(i[1]) return TGraph(len(x),x,y)
def clear_memory(self): total_size = self.n.get_device_size(self.urn) offset = self.n.get_device_address(self.urn) position = 0 size = 0 if self.status.is_command_line(): self.status.Verbose( "Clearing Memory") self.status.Verbose( "Memory Size: 0x%08X" % size) if total_size > MAX_LONG_SIZE: self.status.Info("Memory Size: 0x%08X is larger than read/write size" % total_size) self.status.Info("\tBreaking transaction into 0x%08X chunks" % MAX_LONG_SIZE) size = MAX_LONG_SIZE else: size = total_size while position < total_size: data_out = Array('B') for i in range(0, ((size / 4) - 1)): num = 0x00 data_out.append(num) self.n.write_memory(offset + position, data_out) #Increment the position prev_pos = position position += size if position + size > total_size: size = total_size - position if self.status: self.status.Verbose("Cleared: 0x%08X - 0x%08X" % (prev_pos, position))
def fill_memory_with_pattern(self): position = 0 #self.clear_memory() total_size = self.n.get_device_size(self.memory_urn) size = 0 if total_size > MAX_LONG_SIZE: self.s.Verbose("Memory Size: 0x%08X is larger than write size" % total_size) self.s.Verbose("\tBreaking transaction into 0x%08X chunks" % MAX_LONG_SIZE) size = MAX_LONG_SIZE else: size = total_size #Write Data Out data_out = Array('B') for i in range (0, size): data_out.append((i % 0x100)) while position < total_size: self.n.write_memory(position, data_out) #Increment the position prev_pos = position if position + size > total_size: size = total_size - position position += size self.s.Verbose("Wrote: 0x%08X - 0x%08X" % (prev_pos, position))
def clear_memory(self): total_size = self.n.get_device_size(self.urn) position = 0 size = 0 print ( "Clearing Memory") print ( "Memory Size: 0x%08X" % size) if total_size > MAX_LONG_SIZE: print("Memory Size: 0x%08X is larger than read/write size" % total_size) print("\tBreaking transaction into 0x%08X chunks" % MAX_LONG_SIZE) size = MAX_LONG_SIZE else: size = total_size while position < total_size: data_out = Array('B') for i in range (0, size): data_out.append(0x00) self.n.write_memory(position, data_out) #Increment the position prev_pos = position if position + size > total_size: size = total_size - position position += size
def read_sdb(self, n = None): """ Reads the SDB of the device, this is used to initialize the SDB Object Model with the content of the SDB on the host Args: n (Nysa Instance): A reference to nysa that the controller will use to extrapolate the SDB from the device Returns: Array of bytes consisting of SDB Raises: NysaCommError: Errors associated with communication """ if n is None: n = self.n sdb_data = Array('B') #self.s.Important("Parsing Top Interconnect Buffer") #Because Nysa works with many different platforms we need to get the #platform specific location of where the SDB actually is sdb_base_address = n.get_sdb_base_address() self.som = som.SOM() self.som.initialize_root() bus = self.som.get_root() sdb_data.extend(_parse_bus(n, self.som, bus, sdb_base_address, sdb_base_address, self.s)) sdb_data = n.read(sdb_base_address, len(sdb_data) / 4) return sdb_data
def write_local_buffer(self, addr, data): #Make sure data is 32-bit Aligned data = Array('B', data) while len(data) % 4 > 0: data.append(0x00) self.write(BUFFER_OFFSET + addr, data)
def create_byte_array_from_dword(dword): d = Array('B') d.append((dword >> 24) & 0xFF) d.append((dword >> 16) & 0xFF) d.append((dword >> 8) & 0xFF) d.append((dword >> 0) & 0xFF) return d
def read_dma_data(self, count): d = Array('B') self.write_command(CMD_DMA_READ, count, 0x00) print "Send Peripheral Read Command" data = Array('B') data.fromstring(os.read(self.f, count * 4)) print "Data: %s" % str(data) print_32bit_hex_array(d)
def _write_bytes(self, out): """Output bytes on TDI""" bytes_ = out.tobytes(msby=True) # don't ask... olen = len(bytes_)-1 #print "WRITE BYTES %s" % out cmd = Array('B', [Ftdi.WRITE_BYTES_NVE_LSB, olen&0xff, (olen>>8)&0xff]) cmd.extend(bytes_) self._stack_cmd(cmd)
def write_register(self, address, data): d = Array('B') d.extend(dword_to_array(address)) d.extend(dword_to_array(data)) self.set_command_mode() #self.f.write(d) os.write(self.f, d) self.set_data_mode()
def entropy_density(mesh,u,name="test",D=2): x,y,z = MyArray('f'),MyArray('f'),MyArray('f') for i in mesh.coordinates()[:]: tmp = sqrt(pow(u(i),2)) x.append(i[0]) y.append(i[1]) z.append(-tmp*ln(tmp)) return TGraph2D(len(x),x,y,z)
def Lorenz_Psect(u,mesh = Rectangle(-30,-30,30,30,40,40),z=27): x,y,z = MyArray('f'),MyArray('f'),MyArray('f') for i in mesh.coordinates()[:]: x.append(i[0]) y.append(i[1]) z.append(u([i[0],i[1],z])) return TGraph2D(len(x),x,y,z)
def small_multi_byte_data_write(dut): """ Description: Perform a small write on the data bus Test ID: 4 Expected Results: Multi byte data transfer, this will use the data bus, not FIFO mode """ dut.test_id = 4 SDIO_PATH = get_verilog_path("sdio-device") sdio_config = os.path.join(SDIO_PATH, "sdio_configuration.json") config = None with open (sdio_config, "r") as f: dut.log.warning("Run %s before running this function" % os.path.join(SDIO_PATH, "tools", "generate_config.py")) config = json.load(f) #print "SDIO PATH: %s" % SDIO_PATH #print "module path: %s" % MODULE_PATH nysa = NysaSim(dut, SIM_CONFIG, CLK_PERIOD, user_paths = [MODULE_PATH]) setup_dut(dut) yield(nysa.reset()) nysa.read_sdb() yield (nysa.wait_clocks(10)) #nysa.pretty_print_sdb() #sdhost = SDHostDriver(nysa, nysa.find_device(SDHostDriver)[0]) sdhost = yield cocotb.external(SDHostDriver)(nysa, nysa.find_device(SDHostDriver)[0]) sddev = yield cocotb.external(SDIODeviceDriver)(nysa, nysa.find_device(SDIODeviceDriver)[0]) yield (nysa.wait_clocks(200)) yield cocotb.external(sddev.enable_sdio_device)(False) yield (nysa.wait_clocks(100)) yield cocotb.external(sddev.reset_core)() yield (nysa.wait_clocks(100)) yield cocotb.external(sddev.enable_sdio_device)(True) yield (nysa.wait_clocks(100)) #Enable SDIO yield cocotb.external(sdhost.enable_sd_host)(True) yield cocotb.external(sdhost.cmd_io_send_op_cond)(enable_1p8v = True) yield cocotb.external(sdhost.cmd_get_relative_card_address)() yield cocotb.external(sdhost.cmd_enable_card)(True) #data = Array ('B', [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]) data = Array ('B') for i in range (8): value = i % 256 data.append(value) yield cocotb.external(sdhost.write_sd_data)(0, 0x00, data, fifo_mode = False, read_after_write = False) value = dut.s2.sdio_device.cia.cccr.o_func_enable.value.get_value() if value != 0x02: raise TestFailure ("Failed to write configuration byte to CCCR Memory Space: Should be 0x02 is: 0x%02X" % value) value = dut.s2.sdio_device.cia.cccr.o_func_int_enable.value.get_value() if value != 0x04: raise TestFailure ("Failed to write configuration byte to CCCR Memory Space: Should be 0x04 is: 0x%02X" % value) yield (nysa.wait_clocks(1000))
def enable_lcd(self, enable): self.enable_register_bit(CONTROL, CONTROL_ENABLE, enable) self.enable_register_bit(CONTROL, CONTROL_ENABLE_INTERRUPT, enable) mode = Array('B') if enable: mode.append(0x01) else: mode.append(0x00) self.write_command(MEM_ADR_SET_GPIO_VAL, mode)
def long_write_read(dut): """ Description: Very Basic Functionality Startup Nysa Test ID: 1 Expected Results: Write to all registers """ dut.test_id = 1 print "module path: %s" % MODULE_PATH nysa = NysaSim(dut, SIM_CONFIG, CLK_PERIOD, user_paths = [MODULE_PATH]) setup_dut(dut) yield(nysa.reset()) nysa.read_sdb() yield (nysa.wait_clocks(10)) nysa.pretty_print_sdb() driver = ft_fifo_testerDriver(nysa, nysa.find_device(ft_fifo_testerDriver)[0]) dut.log.info("Ready") memory_urns = nysa.get_memory_devices_as_urns() mem_addrs = [] for m in memory_urns: mem_addrs.append(nysa.get_device_address(m)) dut.log.info("Memory Size: 0x%08X" % nysa.get_total_memory_size()) #DWORD_SIZE = nysa.get_total_memory_size() DWORD_SIZE = 4 write_data = Array('B') for i in range (0, DWORD_SIZE * 4, 4): write_data.append((i + 0) % 256) write_data.append((i + 1) % 256) write_data.append((i + 2) % 256) write_data.append((i + 3) % 256) #For a demo write a value to the control register (See the ${SDB_NAME}Driver for addresses) yield cocotb.external(nysa.write_memory)(0x00, write_data) yield (nysa.wait_clocks(100)) read_data = yield cocotb.external(nysa.read_memory)(0x00, DWORD_SIZE) yield (nysa.wait_clocks(100)) #dut.log.info("Read Data: %s" % list_to_hex_string(read_data)) fail_count = 0 if len(write_data) != len(read_data): print "Length of read data is not equal to the length of write data: 0x%04X != 0x!04X" % (len(write_data), len(read_data)) else: for i in range(len(write_data)): if write_data[i] != read_data[i]: if fail_count < 16: print "[0x%04X] %02X != %02X" % (i, write_data[i], read_data[i]) fail_count += 1
def _update_length(self, length, msb): """If a specific length is specified, extend the sequence as expected""" if length and (len(self) < length): extra = Array('B', [False] * (length-len(self))) if msb: extra.extend(self._seq) self._seq = extra else: self._seq.extend(extra)
def energy_density(mesh,u): x,y,z = MyArray('f'),MyArray('f'),MyArray('f') for i in mesh.coordinates()[:]: tmp = sqrt(pow(u(i),2)) x.append(i[0]) y.append(i[1]) z.append(-ln(tmp)) tmp = TGraph2D(len(x),x,y,z) return tmp
def write(self, address, data): """Write a sequence of bytes, starting at the specified address.""" length = len(data) if address+length > len(self): raise SerialFlashValueError('Cannot fit in flash area') if not isinstance(data, Array): data = Array('B', data) pos = 0 page_size = self.get_size('page') while pos < length: boffset = (address+pos) & (page_size-1) poffset = (address+pos) & ~(page_size-1) # first step: write data to the device RAM buffer count = min(length-pos, page_size-boffset) buf = Array('B', '\xFF'*boffset) buf.extend(data[pos:pos+count]) pad = Array('B', '\xFF'*(page_size-count-boffset)) buf.extend(pad) assert len(buf) == page_size wcmd = Array('B', (self.CMD_WRITE_BUFFER1, 0, 0, 0)) wcmd.extend(buf) self._spi.exchange(wcmd) self._wait_for_completion(self.get_timings('page')) # second step: commit device buffer into flash cells wcmd = Array('B', (self.CMD_COMMIT_BUFFER1, (poffset >> 16) & 0xff, (poffset >> 8) & 0xff, poffset & 0xff)) self._spi.exchange(wcmd) self._wait_for_completion(self.get_timings('page')) pos += page_size
def small_multi_byte_data_write_to_func1(dut): """ Description: Perform a small write on the data bus Test ID: 12 Expected Results: Multi byte data transfer, this will use the data bus, not FIFO mode """ dut.test_id = 12 SDIO_PATH = get_verilog_path("sdio-device") sdio_config = os.path.join(SDIO_PATH, "sdio_configuration.json") config = None with open (sdio_config, "r") as f: dut.log.warning("Run %s before running this function" % os.path.join(SDIO_PATH, "tools", "generate_config.py")) config = json.load(f) #print "SDIO PATH: %s" % SDIO_PATH #print "module path: %s" % MODULE_PATH nysa = NysaSim(dut, SIM_CONFIG, CLK_PERIOD, user_paths = [MODULE_PATH]) setup_dut(dut) yield(nysa.reset()) nysa.read_sdb() yield (nysa.wait_clocks(10)) #nysa.pretty_print_sdb() #sdhost = SDHostDriver(nysa, nysa.find_device(SDHostDriver)[0]) sdhost = yield cocotb.external(SDHostDriver)(nysa, nysa.find_device(SDHostDriver)[0]) sddev = yield cocotb.external(SDIODeviceDriver)(nysa, nysa.find_device(SDIODeviceDriver)[0]) yield (nysa.wait_clocks(200)) yield cocotb.external(sddev.enable_sdio_device)(False) yield (nysa.wait_clocks(100)) yield cocotb.external(sddev.reset_core)() yield (nysa.wait_clocks(100)) yield cocotb.external(sddev.enable_sdio_device)(True) yield (nysa.wait_clocks(100)) #Enable SDIO yield cocotb.external(sdhost.enable_sd_host)(True) yield cocotb.external(sdhost.cmd_io_send_op_cond)(enable_1p8v = True) yield cocotb.external(sdhost.cmd_get_relative_card_address)() yield cocotb.external(sdhost.cmd_enable_card)(True) #data = Array ('B', [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]) data = Array ('B') for i in range (16): value = i % 256 data.append(value) data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF] yield cocotb.external(sdhost.write_sd_data)(1, 0x00, data, fifo_mode = False, read_after_write = False) yield (nysa.wait_clocks(100)) read_data = yield cocotb.external(sddev.read_local_buffer)(0, len(data) / 4) print "Read data: %s" % print_hex_array(read_data) yield (nysa.wait_clocks(1000))
def create_empty_buf(count): buf = Array('B') for i in range(count): buf.append(0x00) return buf
def test_1khz_sine_wave(self, debug=False): """generate_1khz_sine_wave generates 1kHz sine wave and plays it through the i2s Args: Debug: True (debug enabled) Returns: 1 khz sine wave in a 32-bit array Raises: Nothing """ byte_array = Array('B') for i in range(0, 35000): byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x12) byte_array.append(0x37) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x12) byte_array.append(0x37) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x24) byte_array.append(0x0F) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x24) byte_array.append(0x0F) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x35) byte_array.append(0x2C) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x35) byte_array.append(0x2C) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x45) byte_array.append(0x33) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x45) byte_array.append(0x33) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x53) byte_array.append(0xD2) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x53) byte_array.append(0xD2) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x60) byte_array.append(0xBC) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x60) byte_array.append(0xBC) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x6B) byte_array.append(0xAE) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x6B) byte_array.append(0xAE) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x74) byte_array.append(0x6E) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x74) byte_array.append(0x6E) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x7A) byte_array.append(0xD0) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x7A) byte_array.append(0xD0) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x7E) byte_array.append(0xB2) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x7E) byte_array.append(0xB2) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x7F) byte_array.append(0xFF) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x7F) byte_array.append(0xFF) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x7E) byte_array.append(0xB2) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x7E) byte_array.append(0xB2) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x7A) byte_array.append(0xD0) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x7A) byte_array.append(0xD0) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x74) byte_array.append(0x6E) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x74) byte_array.append(0x6E) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x6B) byte_array.append(0xAE) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x6B) byte_array.append(0xAE) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x60) byte_array.append(0xBC) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x60) byte_array.append(0xBC) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x53) byte_array.append(0xD2) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x53) byte_array.append(0xD2) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x45) byte_array.append(0x33) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x45) byte_array.append(0x33) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x35) byte_array.append(0x2C) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x35) byte_array.append(0x2C) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x24) byte_array.append(0x0F) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x24) byte_array.append(0x0F) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x12) byte_array.append(0x37) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x12) byte_array.append(0x37) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xED) byte_array.append(0xC9) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xED) byte_array.append(0xC9) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xDB) byte_array.append(0xF1) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xDB) byte_array.append(0xF1) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xCA) byte_array.append(0xD4) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xCA) byte_array.append(0xD4) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xBA) byte_array.append(0xCD) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xBA) byte_array.append(0xCD) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xAC) byte_array.append(0x2E) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xAC) byte_array.append(0x2E) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x9F) byte_array.append(0x43) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x9F) byte_array.append(0x43) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x94) byte_array.append(0x52) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x94) byte_array.append(0x52) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x8B) byte_array.append(0x92) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x8B) byte_array.append(0x92) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x85) byte_array.append(0x30) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x85) byte_array.append(0x30) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x81) byte_array.append(0x4E) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x81) byte_array.append(0x4E) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x01) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x80) byte_array.append(0x01) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x81) byte_array.append(0x4E) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x81) byte_array.append(0x4E) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x85) byte_array.append(0x30) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x85) byte_array.append(0x30) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x8B) byte_array.append(0x92) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x8B) byte_array.append(0x92) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x94) byte_array.append(0x52) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x94) byte_array.append(0x52) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0x9F) byte_array.append(0x43) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0x9F) byte_array.append(0x43) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xAC) byte_array.append(0x2E) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xAC) byte_array.append(0x2E) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xBA) byte_array.append(0xCD) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xBA) byte_array.append(0xCD) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xCA) byte_array.append(0xD4) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xCA) byte_array.append(0xD4) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xDB) byte_array.append(0xF1) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xDB) byte_array.append(0xF1) byte_array.append(0x00) byte_array.append(0x00) byte_array.append(0xED) byte_array.append(0xC9) byte_array.append(0x00) byte_array.append(0x80) byte_array.append(0xED) byte_array.append(0xC9) byte_array.append(0x00) while ((len(byte_array) % 4) > 0): byte_array.append(0x00) print "length of byte_array: %d, megabytes: %d" % ( len(byte_array), (len(byte_array) / 4) / 1e6) self.i2s.write_all_audio_data(byte_array) print "Fin"
def write(self, address, data = None, disable_auto_inc=False): print "Writing" mem_device = False write_data = Array('B') if self.mem_addr is None: self.mem_addr = self.nsm.get_address_of_memory_bus() if address >= self.mem_addr: address = address - self.mem_addr write_data.extend(create_byte_array_from_dword(0x00010001)) else: write_data.extend(create_byte_array_from_dword(0x00000001)) while (len(data) % 4) != 0: data.append(0) data_count = len(data) / 4 write_data.extend(create_byte_array_from_dword(data_count)) write_data.extend(create_byte_array_from_dword(address)) write_data.extend(data) if data_count == 0: raise NysaCommError("Length of data to write is 0!") data_index = 0 timeout_count = 0 yield(self.comm_lock.acquire()) #while data_index < data_count: yield(self.ingress.write(write_data)) self.comm_lock.release()
def test_dma_sata(self): if self.sata_drv is None: self.s.Fatal("Cannot Run Test when no device is found!") return self.s.Info("Reseting Hard Drive...") self.sata_drv.enable_sata_reset(True) time.sleep(0.5) self.sata_drv.enable_sata_reset(False) time.sleep(0.75) self.s.Info("Reset Complete") if self.sata_drv.is_linkup(): self.s.Important("Linked up with Hard Drive!") self.s.Info("\tInitial Status of hard drive (Status): 0x%02X" % self.sata_drv.get_d2h_status()) if (self.sata_drv.get_d2h_status() & 0x040) == 0: self.s.Warning( "\tReceived 0 for status of hard drive, sending reset!") self.s.Warning("Sending reset command to hard drive") self.sata_drv.send_hard_drive_command(0x08) if (self.sata_drv.get_d2h_status() & 0x040) == 0: self.s.Warning( "Still Received 0x00 after reset, send a sequence of identify commands to get hard drive into known state" ) for i in range(32): self.sata_drv.send_hard_drive_command(0xEC) if (self.sata_drv.get_d2h_status() & 0x040) > 0: print "Found!" break if (self.sata_drv.get_d2h_status() & 0x040) == 0: self.s.Warning( "Did not get a normal status response from the hard drive attempting soft reset" ) time.sleep(0.1) self.sata_drv.enable_sata_command_layer_reset(True) time.sleep(0.1) self.sata_drv.enable_sata_command_layer_reset(False) self.sata_drv.send_hard_drive_command(0x00) if (self.sata_drv.get_d2h_status() & 0x040) == 0: self.s.Error( "After Soft Reset Still Did not get a good response" ) sys.exit(1) self.sata_drv.identify_hard_drive() config = self.sata_drv.get_config() self.s.Verbose("Hard Drive Serial Number: %s" % config.serial_number()) max_user_lba = config.max_user_sectors() self.s.Verbose("Max User Sectors: %d" % config.max_user_sectors()) self.s.Verbose("Max User Size (GB): %f" % ((config.max_user_sectors() * 512.0) * 0.000000001)) #Clear out a block of memory values = Array('B') clear_values = Array('B') for i in range(2048 * 4): values.append(i % 256) clear_values.append(0) self.sata_drv.set_local_buffer_write_size(128) self.sata_drv.write_local_buffer(clear_values) self.sata_drv.load_local_buffer() self.sata_drv.hard_drive_write(0x0000, 1) print "\tSATA Status: 0x%08X" % self.sata_drv.get_d2h_status( ) print "\tSATA Sector Count: 0x%08X" % self.sata_drv.get_sector_count( ) print "\tSATA Current Address: 0x%08X" % self.sata_drv.get_hard_drive_lba( ) self.sata_drv.hard_drive_read(0x0000, 1) data = self.sata_drv.read_local_buffer() #self.s.Verbose("Data from Hard Drive Before DMA Transfer (Should be all zeros):") #print str(data[0:128]) self.sata_drv.enable_dma_control(True) self.s.Info("Setup DMA") self.dma.setup() self.dma.enable_dma(True) #DMA Configuration CHANNEL_ADDR = 2 SINK_ADDR = 0 INST_ADDR = 0 DDR3_ADDRESS = 0x0000000000000000 SATA_ADDRESS = 0x0000000000000000 #WORD_TRANSFER_COUNT = 0x1000 #WORD_TRANSFER_COUNT = 0x800 #WORD_TRANSFER_COUNT = 2048 #Rarely Failed: #WORD_TRANSFER_COUNT = 0x2000 #WORD_TRANSFER_COUNT = 0x16000 WORD_TRANSFER_COUNT = 0x0A00000 #WORD_TRANSFER_COUNT = 0x100000 #WORD_TRANSFER_COUNT = 0xF00000 #WORD_TRANSFER_COUNT = 0x800000 #WORD_TRANSFER_COUNT = 0x900000 #WORD_TRANSFER_COUNT = 0xB00000 MEGABYTES = (WORD_TRANSFER_COUNT * 4.0) / 1000000.0 self.s.Info("Transfer Size: 0x%08X" % WORD_TRANSFER_COUNT) #Clear SATA self.clear_memory() #Fill Memory With Data self.s.Important("Fill memory with zeros") self.s.Important( "Configure DMA to transfer %f MB from DDR3 to Hard Drive" % MEGABYTES) #self.fill_memory_with_pattern() self.dma.enable_channel(CHANNEL_ADDR, False) #Configure DMA to transfer 100MB of data from DDR3 to hard drive self.dma.set_channel_sink_addr(CHANNEL_ADDR, SINK_ADDR) self.dma.set_channel_instruction_pointer(CHANNEL_ADDR, INST_ADDR) self.dma.enable_source_address_increment(CHANNEL_ADDR, True) self.dma.enable_dest_address_increment(SINK_ADDR, True) self.dma.enable_dest_respect_quantum(SINK_ADDR, True) self.dma.set_instruction_source_address(INST_ADDR, DDR3_ADDRESS) self.dma.set_instruction_dest_address(INST_ADDR, SATA_ADDRESS) self.dma.set_instruction_data_count(INST_ADDR, WORD_TRANSFER_COUNT) #This is only needed if we are going to another instruction after this self.dma.set_instruction_next_instruction(INST_ADDR, INST_ADDR) self.dma.enable_instruction_continue(INST_ADDR, False) #Initate DMA Transaction self.s.Important("Intiate a DMA Transaction") self.dma.enable_interrupt_when_command_finished(True) self.dma.enable_channel(CHANNEL_ADDR, True) #Transaction Complete self.s.Important("DMA Transaction is complete") #self.dma.wait_for_interrupts(wait_time = 10) self.s.Info("Wait for transaction to finish") fail = False timeout = time.time() + TIMEOUT self.sata_drv.hard_drive_read(0x0000, 1) data = self.sata_drv.read_local_buffer() self.s.Verbose( "Data from first sector of hard drive (Should be all zeros):") print str(data[0:128]) self.sata_drv.enable_dma_control(True) print("") #Fill Memory With Data self.s.Important("Fill memory with pattern") self.s.Important( "Configure DMA to transfer %f MB from DDR3 to Hard Drive" % MEGABYTES) self.fill_memory_with_pattern() self.dma.enable_channel(CHANNEL_ADDR, False) #Configure DMA to transfer 100MB of data from DDR3 to hard drive self.dma.set_channel_sink_addr(CHANNEL_ADDR, SINK_ADDR) self.dma.set_channel_instruction_pointer(CHANNEL_ADDR, INST_ADDR) self.dma.enable_source_address_increment(CHANNEL_ADDR, True) self.dma.enable_dest_address_increment(SINK_ADDR, True) self.dma.enable_dest_respect_quantum(SINK_ADDR, True) self.dma.set_instruction_source_address(INST_ADDR, DDR3_ADDRESS) self.dma.set_instruction_dest_address(INST_ADDR, SATA_ADDRESS) self.dma.set_instruction_data_count(INST_ADDR, WORD_TRANSFER_COUNT) #This is only needed if we are going to another instruction after this self.dma.set_instruction_next_instruction(INST_ADDR, INST_ADDR) self.dma.enable_instruction_continue(INST_ADDR, False) #Initate DMA Transaction self.s.Important("Intiate a DMA Transaction") self.dma.enable_interrupt_when_command_finished(True) self.dma.enable_channel(CHANNEL_ADDR, True) #Transaction Complete self.s.Important("DMA Transaction is complete") #self.dma.wait_for_interrupts(wait_time = 10) self.s.Info("Wait for transaction to finish") fail = False timeout = time.time() + TIMEOUT ''' self.fail_analysis(CHANNEL_ADDR, SINK_ADDR, INST_ADDR) print "\tCurrent SATA DMA Address: 0x%08X" % self.dma.get_current_sink_address(SINK_ADDR) print "\tSATA Status: 0x%08X" % self.sata_drv.get_d2h_status() print "\tSATA Sector Count: 0x%08X" % self.sata_drv.get_sector_count() status = self.dma.get_channel_status(CHANNEL_ADDR) print "\tFinished: %s" % str(((status & 0x04) > 0)) print "\tStatus: 0x%08X" % status ''' while not self.dma.is_channel_finished(CHANNEL_ADDR): #while (self.dma.get_current_sink_address(SINK_ADDR) - SATA_ADDRESS) >= WORD_TRANSFER_COUNT: print ".", if time.time() > timeout: print "" self.s.Error("Timeout Occured!") fail = True break if fail: self.fail_analysis(CHANNEL_ADDR, SINK_ADDR, INST_ADDR) return self.s.Info("Transaction Finished!") print "\tCurrent SATA DMA Address: 0x%08X" % self.dma.get_current_sink_address( SINK_ADDR) print "\tSATA Status: 0x%08X" % self.sata_drv.get_d2h_status( ) print "\tSATA Sector Count: 0x%08X" % self.sata_drv.get_sector_count( ) #self.fail_analysis(CHANNEL_ADDR, SINK_ADDR, INST_ADDR) self.dma.enable_channel(CHANNEL_ADDR, False) self.sata_drv.enable_dma_control(False) self.sata_drv.hard_drive_read(0x0000, 1) data = self.sata_drv.read_local_buffer() self.s.Verbose( "Data from first sector of the hard drive (Should be incrementing number patter):" ) print str(data[0:128]) self.sata_drv.enable_dma_control(True) #Clear DDR3 Memory self.s.Important("Clear DDR3 Memory") self.clear_memory() data = self.n.read_memory(0x00, 128) self.s.Verbose( "Data read from memory after clear (Should be all zeros):") print str(data[0:128]) #Configure DMA to transfer 100MB of data from hard drive to DDR3 CHANNEL_ADDR = 0 SINK_ADDR = 2 self.s.Important( "Configure DMA to transfer %f MB from Hard Drive to DDR3" % MEGABYTES) self.dma.set_channel_sink_addr(CHANNEL_ADDR, SINK_ADDR) self.dma.set_channel_instruction_pointer(CHANNEL_ADDR, INST_ADDR) self.dma.enable_source_address_increment(CHANNEL_ADDR, True) self.dma.enable_dest_address_increment(SINK_ADDR, True) #self.dma.enable_dest_respect_quantum (SINK_ADDR, True ) self.dma.enable_dest_respect_quantum(SINK_ADDR, False) self.dma.set_instruction_source_address(INST_ADDR, SATA_ADDRESS) self.dma.set_instruction_dest_address(INST_ADDR, SATA_ADDRESS) self.dma.set_instruction_data_count(INST_ADDR, WORD_TRANSFER_COUNT) #This is only needed if we are going to another instruction after this self.dma.set_instruction_next_instruction(INST_ADDR, INST_ADDR) self.dma.enable_instruction_continue(INST_ADDR, False) #Initate DMA Transaction self.s.Important("Intiate a DMA Transaction") self.dma.enable_interrupt_when_command_finished(True) self.dma.enable_channel(CHANNEL_ADDR, True) #Transaction Complete self.s.Important("DMA Transaction is complete") #self.dma.wait_for_interrupts(wait_time = 10) self.s.Info("Wait for transaction to finish (Timeout: %d)" % TIMEOUT) timeout = time.time() + TIMEOUT fail = False while not self.dma.is_channel_finished(CHANNEL_ADDR): print ".", if time.time() > timeout: print "" self.s.Error("Timeout Occured!") fail = True break if fail: self.fail_analysis(CHANNEL_ADDR, SINK_ADDR, INST_ADDR) return self.s.Info("Transaction Finished!") print "\tSATA Sector Count: 0x%08X" % self.sata_drv.get_sector_count( ) #Transaction Complete self.s.Important("DMA Transaction is complete") #Verify values of memory are correct self.s.Important("Verify values of DDR3 are correct") data = self.n.read_memory(0x00, 128) self.s.Verbose( "Data read from memory after clear (Should be all incrementing number pattern):" ) print str(data[0:128]) #self.verify_memory_pattern() self.s.Verbose("Put Hard Drive to Sleep") self.sata_drv.hard_drive_sleep()
def convert_wave_to_i2s(self, wave_filename, debug=False): """convert_wave_to_i2s_format Converts a wave file into a series of 32-bit dwords that can be read by the i2s device Args: wave_filename: path of the wave file to decode Returns: An array of bytes suitable to be processed by Olympus Raises: ValueError: Unsupported number of channels WaveError: File not found """ wf = None try: wf = wave.open(wave_filename, 'rb') except wave.Error as err: print str(err) sys.exit(1) if debug: print "Number of channels: %d" % wf.getnchannels() print "Sample Width: %d" % wf.getsampwidth() print "getframerate: %d" % wf.getframerate() print "number of frames: %d" % wf.getnframes() print "type of compression: %s" % wf.getcomptype() raw_data = wf.readframes(wf.getnframes()) total_samples = wf.getnframes() * wf.getnchannels() sample_width = wf.getsampwidth() wf.close() #thanks SaphireSun for this peice of code #http://stackoverflow.com/questions/2226853/interpreting-wav-data if sample_width == 1: fmt = "%iB" % total_samples # read unsigned chars elif sample_width == 2: fmt = "%ih" % total_samples # read signed 2 byte shorts else: raise ValueError("Only supports 8 and 16 bit audio formats.") integer_data = struct.unpack(fmt, raw_data) del raw_data byte_array = Array('B') if sample_width == 1: for i in integer_data: #set the bit for left or right channel #change the value to a 24-bit audio sample value = (integer_data[i] & 0xFF) << 16 byte_array.append((value >> 24) & 0xFF) byte_array.append((value >> 16) & 0xFF) byte_array.append((value >> 8) & 0xFF) byte_array.append(value & 0xFF) elif sample_width == 2: lr = False for i in range(0, len(integer_data)): #set the bit for left or right channel value = 0x00000000 if lr: value = 0x80000000 #change the value to a 24-bit audio sample value = value | ((integer_data[i] & 0xFFFF) << 8) byte_array.append((value >> 24) & 0xFF) byte_array.append((value >> 16) & 0xFF) byte_array.append((value >> 8) & 0xFF) byte_array.append(value & 0xFF) lr = not lr #Uncommenting out the next two lines will print LOTS of data #for i in range (0, (len(byte_array) / 4)): # print "0x%02X%02X%02X%02X" % (byte_array[(i * 4)], byte_array[(i * 4) + 1], byte_array[(i * 4) + 2], byte_array[(i * 4) + 3]) return byte_array
class JtagController(object): """JTAG master of an FTDI device""" TCK_BIT = 0x01 # FTDI output TDI_BIT = 0x02 # FTDI output TDO_BIT = 0x04 # FTDI input TMS_BIT = 0x08 # FTDI output TRST_BIT = 0x10 # FTDI output, not available on 2232 JTAG debugger JTAG_MASK = 0x1f FTDI_PIPE_LEN = 512 # Private API def __init__(self, trst=False, frequency=3.0E6): """ trst uses the nTRST optional JTAG line to hard-reset the TAP controller """ self._ftdi = Ftdi() self._trst = trst self._frequency = frequency self.direction = JtagController.TCK_BIT | \ JtagController.TDI_BIT | \ JtagController.TMS_BIT | \ (self._trst and JtagController.TRST_BIT or 0) self._last = None # Last deferred TDO bit self._write_buff = Array('B') def __del__(self): self.close() # Public API def configure(self, vendor, product, interface): """Configure the FTDI interface as a JTAG controller""" curfreq = self._ftdi.open_mpsse( vendor, product, interface, direction=self.direction, #initial=0x0, frequency=self._frequency) # FTDI requires to initialize all GPIOs before MPSSE kicks in cmd = Array('B', [Ftdi.SET_BITS_LOW, 0x0, self.direction]) self._ftdi.write_data(cmd) def close(self): if self._ftdi: self._ftdi.close() self._ftdi = None def purge(self): self._ftdi.purge_buffers() def reset(self, sync=False): """Reset the attached TAP controller. sync sends the command immediately (no caching) """ # we can either send a TRST HW signal or perform 5 cycles with TMS=1 # to move the remote TAP controller back to 'test_logic_reset' state # do both for now if not self._ftdi: raise JtagError("FTDI controller terminated") if self._trst: # nTRST value = 0 cmd = Array('B', [Ftdi.SET_BITS_LOW, value, self.direction]) self._ftdi.write_data(cmd) time.sleep(0.1) # nTRST should be left to the high state value = JtagController.TRST_BIT cmd = Array('B', [Ftdi.SET_BITS_LOW, value, self.direction]) self._ftdi.write_data(cmd) time.sleep(0.1) # TAP reset (even with HW reset, could be removed though) self.write_tms(BitSequence('11111')) if sync: self.sync() def sync(self): if not self._ftdi: raise JtagError("FTDI controller terminated") if self._write_buff: self._ftdi.write_data(self._write_buff) self._write_buff = Array('B') def write_tms(self, tms): """Change the TAP controller state""" if not isinstance(tms, BitSequence): raise JtagError('Expect a BitSequence') length = len(tms) if not (0 < length < 8): raise JtagError('Invalid TMS length') out = BitSequence(tms, length=8) # apply the last TDO bit if self._last is not None: out[7] = self._last # print "TMS", tms, (self._last is not None) and 'w/ Last' or '' # reset last bit self._last = None cmd = Array('B', [Ftdi.WRITE_BITS_TMS_NVE, length - 1, out.tobyte()]) self._stack_cmd(cmd) self.sync() #self._ftdi.validate_mpsse() def read(self, length): """Read out a sequence of bits from TDO""" byte_count = length // 8 bit_count = length - 8 * byte_count bs = BitSequence() if byte_count: bytes = self._read_bytes(byte_count) bs.append(bytes) if bit_count: bits = self._read_bits(bit_count) bs.append(bits) return bs def write(self, out, use_last=True): """Write a sequence of bits to TDI""" if isinstance(out, str): if len(out) > 1: self._write_bytes_raw(out[:-1]) out = out[-1] out = BitSequence(bytes_=out) elif not isinstance(out, BitSequence): out = BitSequence(out) if use_last: (out, self._last) = (out[:-1], bool(out[-1])) byte_count = len(out) // 8 pos = 8 * byte_count bit_count = len(out) - pos if byte_count: self._write_bytes(out[:pos]) if bit_count: self._write_bits(out[pos:]) def shift_register(self, out, use_last=False): """Shift a BitSequence into the current register and retrieve the register output""" if not isinstance(out, BitSequence): return JtagError('Expect a BitSequence') length = len(out) if use_last: (out, self._last) = (out[:-1], int(out[-1])) byte_count = len(out) // 8 pos = 8 * byte_count bit_count = len(out) - pos if not byte_count and not bit_count: raise JtagError("Nothing to shift") if byte_count: blen = byte_count - 1 #print "RW OUT %s" % out[:pos] cmd = Array('B', [Ftdi.RW_BYTES_PVE_NVE_LSB, blen, (blen >> 8) & 0xff]) cmd.extend(out[:pos].tobytes(msby=True)) self._stack_cmd(cmd) #print "push %d bytes" % byte_count if bit_count: #print "RW OUT %s" % out[pos:] cmd = Array('B', [Ftdi.RW_BITS_PVE_NVE_LSB, bit_count - 1]) cmd.append(out[pos:].tobyte()) self._stack_cmd(cmd) #print "push %d bits" % bit_count self.sync() bs = BitSequence() byte_count = length // 8 pos = 8 * byte_count bit_count = length - pos if byte_count: data = self._ftdi.read_data_bytes(byte_count, 4) if not data: raise JtagError('Unable to read data from FTDI') byteseq = BitSequence(bytes_=data, length=8 * byte_count) #print "RW IN %s" % byteseq bs.append(byteseq) #print "pop %d bytes" % byte_count if bit_count: data = self._ftdi.read_data_bytes(1, 4) if not data: raise JtagError('Unable to read data from FTDI') byte = data[0] # need to shift bits as they are shifted in from the MSB in FTDI byte >>= 8 - bit_count bitseq = BitSequence(byte, length=bit_count) bs.append(bitseq) #print "pop %d bits" % bit_count if len(bs) != length: raise AssertionError("Internal error") #self._ftdi.validate_mpsse() return bs def _stack_cmd(self, cmd): if not isinstance(cmd, Array): raise TypeError('Expect a byte array') if not self._ftdi: raise JtagError("FTDI controller terminated") # Currrent buffer + new command + send_immediate if (len(self._write_buff) + len(cmd) + 1) >= JtagController.FTDI_PIPE_LEN: self.sync() self._write_buff.extend(cmd) def _read_bits(self, length): """Read out bits from TDO""" data = '' if length > 8: raise JtagError("Cannot fit into FTDI fifo") cmd = Array('B', [Ftdi.READ_BITS_NVE_LSB, length - 1]) self._stack_cmd(cmd) self.sync() data = self._ftdi.read_data_bytes(1, 4) # need to shift bits as they are shifted in from the MSB in FTDI byte = ord(data) >> 8 - bit_count bs = BitSequence(byte, length=length) #print "READ BITS %s" % (bs) return bs def _write_bits(self, out): """Output bits on TDI""" length = len(out) byte = out.tobyte() #print "WRITE BITS %s" % out cmd = Array('B', [Ftdi.WRITE_BITS_NVE_LSB, length - 1, byte]) self._stack_cmd(cmd) def _read_bytes(self, length): """Read out bytes from TDO""" data = '' if length > JtagController.FTDI_PIPE_LEN: raise JtagError("Cannot fit into FTDI fifo") alen = length - 1 cmd = Array('B', [Ftdi.READ_BYTES_NVE_LSB, alen & 0xff, (alen >> 8) & 0xff]) self._stack_cmd(cmd) self.sync() data = self._ftdi.read_data_bytes(length, 4) bs = BitSequence(bytes_=data, length=8 * length) #print "READ BYTES %s" % bs return bs def _write_bytes(self, out): """Output bytes on TDI""" bytes_ = out.tobytes(msby=True) # don't ask... olen = len(bytes_) - 1 #print "WRITE BYTES %s" % out cmd = Array( 'B', [Ftdi.WRITE_BYTES_NVE_LSB, olen & 0xff, (olen >> 8) & 0xff]) cmd.extend(bytes_) self._stack_cmd(cmd) def _write_bytes_raw(self, out): """Output bytes on TDI""" olen = len(out) - 1 cmd = Array( 'B', [Ftdi.WRITE_BYTES_NVE_LSB, olen & 0xff, (olen >> 8) & 0xff]) cmd.fromstring(out) self._stack_cmd(cmd)
class BitSequence(object): """Bit sequence manipulation""" __slots__ = [ '_seq' ] def __init__(self, value=None, msb=False, length=0, bytes_=None, msby=True): self._seq = Array('B') seq = self._seq if value and bytes_: raise BitSequenceError("Cannot inialize with both a value and " "bytes") if bytes_: provider = msby and list(bytes_).__iter__() or reversed(bytes_) for byte in provider: if isinstance(byte, str): byte = ord(byte) elif byte > 0xff: raise BitSequenceError("Invalid byte value") b = [] for x in xrange(8): b.append(byte&0x1 and True or False) byte >>= 1 if msb: b.reverse() seq.extend(b) else: value = self._tomutable(value) if isinstance(value, Integral): self._init_from_integer(value, msb, length) elif isinstance(value, BitSequence): self._init_from_sibling(value, msb) elif is_iterable(value): self._init_from_iterable(value, msb) elif value is None: pass else: raise BitSequenceError("Cannot initialize from a %s" % type(value)) self._update_length(length, msb) def sequence(self): """Return the internal representation as a new mutable sequence""" return Array('B', self._seq) def reverse(self): """In-place reverse""" self._seq.reverse() return self def invert(self): """In-place invert sequence values""" self._seq = Array('B', [x^1 for x in self._seq]) return self def append(self, seq): """Concatenate a new BitSequence""" if not isinstance(seq, BitSequence): seq = BitSequence(seq) self._seq.extend(seq.sequence()) return self def lsr(self, count): "Left shift rotate" count %= len(self) self._seq[:] = self._seq[count:] + self._seq[:count] def rsr(self, count): "Right shift rotate" count %= len(self) self._seq[:] = self._seq[-count:] + self._seq[:-count] def tobit(self): """Degenerate the sequence into a single bit, if possible""" if len(self) != 1: raise BitSequenceError("BitSequence should be a scalar") return self._seq[0] and True or False def tobyte(self, msb=False): """Convert the sequence into a single byte value, if possible""" if len(self) > 8: raise BitSequenceError("Cannot fit into a single byte") byte = 0 pos = not msb and -1 or 0 # copy the sequence seq = self._seq[:] while seq: byte <<= 1 byte |= seq.pop(pos) return byte def tobytes(self, msb=False, msby=False): """Convert the sequence into a sequence of byte values""" blength = (len(self)+7) & (~0x7) sequence = list(self._seq) if not msb: sequence.reverse() bytes_ = Array('B') for pos in xrange(0, blength, 8): seq = sequence[pos:pos+8] byte = 0 while seq: byte <<= 1 byte |= seq.pop(0) bytes_.append(byte) if msby: bytes_.reverse() return bytes_.tolist() @staticmethod def _tomutable(value): """Convert a immutable sequence into a mutable one""" if isinstance(value, tuple): # convert immutable sequence into a list so it can be popped out value = list(value) elif isinstance(value, str): # convert immutable sequence into a list so it can be popped out if value.startswith('0b'): value = list(value[2:]) else: value = list(value) return value def _init_from_integer(self, value, msb, length): """Initialize from any integer value""" l = length or -1 seq = self._seq while l: seq.append((value & 1) and True or False) value >>= 1 if not value: break l -= 1 if msb: seq.reverse() def _init_from_iterable(self, iterable, msb): """Initialize from an iterable""" smap = { '0': 0, '1': 1, False: 0, True: 1, 0: 0, 1: 1 } seq = self._seq try: if msb: seq.extend([smap[bit] for bit in reversed(iterable)]) else: seq.extend([smap[bit] for bit in iterable]) except KeyError: raise BitSequenceError("Invalid binary character in initializer") def _init_from_sibling(self, value, msb): """Initialize from a fellow object""" self._seq = value.sequence() if msb: self._seq.reverse() def _update_length(self, length, msb): """If a specific length is specified, extend the sequence as expected""" if length and (len(self) < length): extra = Array('B', [False] * (length-len(self))) if msb: extra.extend(self._seq) self._seq = extra else: self._seq.extend(extra) def __iter__(self): return self._seq.__iter__() def __reversed__(self): return self._seq.__reversed__() def __getitem__(self, index): if isinstance(index, slice): return self.__class__(value=self._seq[index]) else: return self._seq[index] def __setitem__(self, index, value): if not isinstance(value, BitSequence): value = self.__class__(value) else: if issubclass(value.__class__, self.__class__) and \ value.__class__ != self.__class__: raise BitSequenceError("Cannot set item with instance of a " "subclass") if isinstance(index, slice): self._seq[index] = value.sequence() else: val = value.tobit() if len(self._seq) < index: # auto-resize sequence extra = Array('B', [False] * (index+1-len(self))) self._seq.extend(extra) self._seq[index] = val def __len__(self): return len(self._seq) def __cmp__(self, other): # the bit sequence should be of the same length ld = len(self) - len(other) if ld: return ld for n, (x, y) in enumerate(zip(self._seq, other.sequence()), start=1): if xor(x, y): return n return 0 def __repr__(self): # cannot use bin() as it truncates the MSB zero bits return ''.join([b and '1' or '0' for b in reversed(self._seq)]) def __str__(self): chunks = [] srepr = repr(self) length = len(self) for i in xrange(0, length, 8): if i: j = -i else: j = None chunks.append(srepr[-i-8:j]) return '%d: %s' % (len(self), ' '.join(reversed(chunks))) def __int__(self): return int(long(self)) def __long__(self): value = 0 for b in reversed(self._seq): value <<= 1 value |= b and 1 return value def __and__(self, other): if type(other) is not type(self.__class__()): raise BitSequenceError('Need a BitSequence to combine') if len(self) != len(other): raise BitSequenceError('Sequences must be the same size') return self.__class__(value=map(lambda x, y: x and y, self._seq, other.sequence())) def __or__(self, other): if type(other) is not type(self.__class__()): raise BitSequenceError('Need a BitSequence to combine') if len(self) != len(other): raise BitSequenceError('Sequences must be the same size') return self.__class__(value=map(lambda x, y: x or y, self._seq, other.sequence())) def __add__(self, other): return self.__class__(value = self._seq + other.sequence()) def __ilshift__(self, count): count %= len(self) seq = Array('B', [0]*count) seq.extend(self._seq[:-count]) self._seq = seq return self def __irshift__(self, count): count %= len(self) seq = self._seq[count:] seq.extend([0]*count) self._seq = seq return self def inc(self): """Increment the sequence""" for p, b in enumerate(self._seq): b ^= True self._seq[p] = b if b: break def dec(self): """Decrement the sequence""" for p, b in enumerate(self._seq): b ^= True self._seq[p] = b if not b: break def invariant(self): """Tells whether all bits of the sequence are of the same value. Return the value, or ValueError if the bits are not of the same value """ try: ref = self._seq[0] except IndexError: raise ValueError('Empty sequence') if len(self._seq) == 1: return ref for b in self._seq[1:]: if b != ref: raise ValueError('Bits do no match') return ref
def program_fpga(self, path): f = open(path, 'r') fpga_binary = Array('B') fpga_binary.fromstring(f.read()) f.close() self.fx3.program_fpga(fpga_binary)
def transaction(self, write_data, response_bit_length = 0, slave_select_bit = 1, auto_slave_select = True): total_bit_length = (len(write_data) * 8) + response_bit_length read_data = Array('B') #print "SPI total bit length: %d" % total_bit_length if auto_slave_select: self.set_slave_select_raw(0x00) self.auto_ss_control_enable(True) self.set_spi_slave_select(slave_select_bit, True) if self.max_bit_length > total_bit_length: #print "SPI Auto SS Mode" #print "SPI Write Data: %s" % str(write_data) self.set_character_length(total_bit_length) self.set_write_data(write_data) self.start_transaction() while self.is_busy(): time.sleep(0.01) return self.get_read_data(response_bit_length / 8) #Because there is more data than can fit inside the internal buffer of #the SPI register we need to manually control the SPI register #We will read all data as it comes in and parse it out after we are finished #print "SPI manual slave select mode" if auto_slave_select: self.set_slave_select_raw(0x00) self.auto_ss_control_enable(False) #self.set_slave_select_raw(1 << slave_select_bit) self.set_spi_slave_select(slave_select_bit, True) while len(write_data) > 0: if (len(write_data) * 8) >= self.max_bit_length: #print "SPI write data bit length >= max bit length: %d >= %d" % ((len(write_data) * 8), self.max_bit_length) wd = write_data[0:self.max_bit_length / 8] write_data = write_data[self.max_bit_length / 8:] self.set_character_length(self.max_bit_length) self.set_write_data(wd) self.start_transaction() while self.is_busy(): print ".", time.sleep(0.01) #print "Reading: %d bytes" % (self.max_bit_length / 8) read_data.extend(self.get_read_data(self.max_bit_length / 8)) else: bit_length = len(write_data) * 8 #print "SPI write data bit length < max bit length: %d < %d" % (bit_length, self.max_bit_length) self.set_write_data(write_data) self.set_character_length(bit_length) self.start_transaction() while self.is_busy(): print ".", time.sleep(0.01) #read_data.extend(self.read(self.read_data_reg, len(write_data))) #print "Reading: %d bytes" % (len(write_data)) read_data.extend(self.get_read_data(len(write_data))) write_data = Array('B') #print "...Read data: %s" % str(read_data) #brlen = response_bit_length + 8 brlen = response_bit_length self.set_write_data(Array('B')) while brlen > 0: if brlen >= self.max_bit_length: #print "SPI read length >= max_bit_length: %d >= %d" % (brlen, self.max_bit_length) self.set_character_length(self.max_bit_length) self.start_transaction() while self.is_busy(): print ".", time.sleep(0.01) read_data.extend(self.get_read_data(self.max_bit_length / 8)) #print "Reading: %d bytes" % (self.max_bit_length) brlen -= self.max_bit_length else: #print "SPI read length < max_bit_length: %d < %d" % (brlen, self.max_bit_length) self.set_character_length(brlen) self.start_transaction() while self.is_busy(): print ".", time.sleep(0.01) read_data.extend(self.get_read_data(brlen / 8)) #print "Reading: %d bytes" % (brlen / 8) brlen = 0 if auto_slave_select: self.set_slave_select_raw(0x00) self.auto_ss_control_enable(True) #self.set_slave_select_raw(1 << slave_select_bit) self.set_spi_slave_select(slave_select_bit, True) #print "SPI: Final total read data: %s" % str(read_data) return read_data[-(response_bit_length / 8):]
def dump_core(self): data = Array('B') data.extend([ 0xCD, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]) #if self.s: # self.s.Debug( "Sending core dump request...") self.dev.purge_buffers() self.dev.write_data(data) core_dump = Array('L') wait_time = 5 timeout = time.time() + wait_time temp = Array('B') while time.time() < timeout: rsp = self.dev.read_data_bytes(1) temp.extend(rsp) if 0xDC in rsp: #self.s.Debug( "Read a response from the core dump") break if not 0xDC in rsp: #if self.s: # self.s.Debug( "Response not found!") raise NysaCommError("Response Not Found") rsp = Array('B') read_total = 4 read_count = len(rsp) #Get the number of items from the incomming data, This size is set by the #Wishbone Master timeout = time.time() + wait_time while (time.time() < timeout) and (read_count < read_total): rsp += self.dev.read_data_bytes(read_total - read_count) read_count = len(rsp) count = (rsp[1] << 16 | rsp[2] << 8 | rsp[3]) * 4 ''' if self.s: self.s.Debug( "Length of read:%d" % len(rsp)) self.s.Debug( "Data: %s" % str(rsp)) self.s.Debug( "Number of core registers: %d" % (count / 4)) ''' timeout = time.time() + wait_time read_total = count read_count = 0 temp = Array('B') rsp = Array('B') while (time.time() < timeout) and (read_count < read_total): rsp += self.dev.read_data_bytes(read_total - read_count) read_count = len(rsp) #if self.s: # self.s.Debug( "Length read: %d" % (len(rsp) / 4)) # self.s.Debug( "Data: %s" % str(rsp)) core_data = Array('L') ''' for i in range(0, count, 4): if self.s: self.s.Debug( "Count: %d" % i) core_data.append(rsp[i] << 24 | rsp[i + 1] << 16 | rsp[i + 2] << 8 | rsp[i + 3]) if self.s: self.s.Debug( "Core Data: %s" % str(core_data)) ''' self.d.data = core_data self.hrq.put(ARTEMIS_RESP_OK)
class NysaSim(FauxNysa): def __init__(self, dut, period=CLK_PERIOD): self.status = Status() self.status.set_level('verbose') self.comm_lock = cocotb.triggers.Lock('comm') self.dut = dut dev_dict = json.load(open('test_dict.json')) super(NysaSim, self).__init__(dev_dict, self.status) self.timeout = 1000 self.response = Array('B') self.dut.rst <= 0 self.dut.ih_reset <= 0 self.dut.in_ready <= 0 self.dut.in_command <= 0 self.dut.in_address <= 0 self.dut.in_data <= 0 self.dut.in_data_count <= 0 gd = GenSDB() self.rom = gd.gen_rom(self.dev_dict, debug=False) #yield ClockCycles(self.dut.clk, 10) cocotb.fork(Clock(dut.clk, period).start()) #self.dut.log.info("Clock Started") @cocotb.coroutine def wait_clocks(self, num_clks): for i in range(num_clks): yield RisingEdge(self.dut.clk) def read_sdb(self): """read_sdb Read the contents of the DRT Args: Nothing Returns (Array of bytes): the raw DRT data, this can be ignored for normal operation Raises: Nothing """ self.s.Verbose("entered") gd = GenSDB() self.rom = gd.gen_rom(self.dev_dict, debug=False) return self.nsm.read_sdb(self) def read(self, address, length=1, mem_device=False): if (address * 4) + (length * 4) <= len(self.rom): length *= 4 address *= 4 ra = Array('B') for count in range(0, length, 4): ra.extend(self.rom[address + count:address + count + 4]) #print "ra: %s" % str(ra) return ra self._read(address, length, mem_device) return self.response @cocotb.function def _read(self, address, length=1, mem_device=False): yield (self.comm_lock.acquire()) #print "_Read Acquire Lock" data_index = 0 self.dut.in_ready <= 0 self.dut.out_ready <= 0 self.response = Array('B') yield (self.wait_clocks(10)) if (mem_device): self.dut.in_command <= 0x00010002 else: self.dut.in_command <= 0x00000002 self.dut.in_data_count <= length self.dut.in_address <= address self.dut.in_data <= 0 yield (self.wait_clocks(1)) self.dut.in_ready <= 1 yield FallingEdge(self.dut.master_ready) yield (self.wait_clocks(1)) self.dut.in_ready <= 0 yield (self.wait_clocks(1)) self.dut.out_ready <= 1 while data_index < length: #self.dut.log.info("Waiting for master to assert out enable") yield RisingEdge(self.dut.out_en) yield (self.wait_clocks(1)) self.dut.out_ready <= 0 timeout_count = 0 data_index += 1 value = self.dut.out_data.value.get_value() self.response.append(0xFF & (value >> 24)) self.response.append(0xFF & (value >> 16)) self.response.append(0xFF & (value >> 8)) self.response.append(0xFF & value) yield (self.wait_clocks(1)) self.dut.out_ready <= 1 if self.dut.master_ready.value.get_value() == 0: yield RisingEdge(self.dut.master_ready) yield (self.wait_clocks(10)) self.comm_lock.release() raise ReturnValue(self.response) @cocotb.function def write(self, address, data=None, mem_device=False): yield (self.comm_lock.acquire()) # print "Write Acquired Lock" data_count = len(data) / 4 #print "data count: %d" % data_count yield (self.wait_clocks(1)) if data_count == 0: raise NysaCommError("Length of data to write is 0!") data_index = 0 timeout_count = 0 #self.dut.log.info("Writing data") self.dut.in_address <= address if (mem_device): self.dut.in_command <= 0x00010001 else: self.dut.in_command <= 0x00000001 self.dut.in_data_count <= data_count while data_index < data_count: self.dut.in_data <= (data[data_index ] << 24) | \ (data[data_index + 1] << 16) | \ (data[data_index + 2] << 8 ) | \ (data[data_index + 3] ) self.dut.in_ready <= 1 #self.dut.log.info("Waiting for master to deassert ready") yield FallingEdge(self.dut.master_ready) yield (self.wait_clocks(1)) data_index += 1 timeout_count = 0 #self.dut.log.info("Waiting for master to be ready") self.dut.in_ready <= 0 yield RisingEdge(self.dut.master_ready) yield (self.wait_clocks(1)) self.response = Array('B') value = self.dut.out_data.value.get_value() self.response.append(0xFF & (value >> 24)) self.response.append(0xFF & (value >> 16)) self.response.append(0xFF & (value >> 8)) self.response.append(0xFF & value) yield (self.wait_clocks(10)) self.comm_lock.release() @cocotb.coroutine def wait_for_interrupts(self, wait_time=1): pass @cocotb.coroutine def dump_core(self): pass @cocotb.coroutine def reset(self): yield (self.comm_lock.acquire()) #print "Reset Acquired Lock" yield (self.wait_clocks(RESET_PERIOD / 2)) self.dut.rst <= 1 #self.dut.log.info("Sending Reset to the bus") self.dut.in_ready <= 0 self.dut.out_ready <= 0 self.dut.in_command <= 0 self.dut.in_address <= 0 self.dut.in_data <= 0 self.dut.in_data_count <= 0 yield (self.wait_clocks(RESET_PERIOD / 2)) self.dut.rst <= 0 yield (self.wait_clocks(RESET_PERIOD / 2)) yield (self.wait_clocks(10)) self.comm_lock.release() #print "Reset Release Lock" @cocotb.coroutine def ping(self): timeout_count = 0 while timeout_count < self.timeout: yield RisingEdge(self.dut.clk) timeout_count += 1 yield ReadOnly() if self.master_ready.value.get_value() == 0: continue else: break if timeout_count == self.timeout: self.dut.log.error( "Timed out while waiting for master to be ready") return yield ReadWrite() self.dut.in_ready <= 1 self.dut.in_command <= 0 self.dut.in_data <= 0 self.dut.in_address <= 0 self.dut.in_data_count <= 0 self.dut.out_ready <= 1 timeout_count = 0 while timeout_count < self.timeout: yield RisingEdge(self.dut.clk) timeout_count += 1 yield ReadOnly() if self.dut.out_en.value.get_value() == 0: continue else: break if timeout_count == self.timeout: self.dut.log.error("Timed out while waiting for master to respond") return self.dut.in_ready <= 0 self.dut.log.info("Master Responded to ping") self.dut.log.info("\t0x%08X" % self.out_status.value.get_value()) def register_interrupt_callback(self, index, callback): pass def unregister_interrupt_callback(self, index, callback=None): pass def get_sdb_base_address(self): return 0x0 def get_board_name(self): return "Cocotb" def upload(self, filepath): pass def program(self): pass
class SpiController(object): """SPI master. :param silent_clock: should be set to avoid clocking out SCLK when all /CS signals are released. This clock beat is used to enforce a delay between /CS signal activation. When weird SPI devices are used, SCLK beating may cause trouble. In this case, silent_clock should be set but beware that SCLK line should be fitted with a pull-down resistor, as SCLK is high-Z during this short period of time. Note that in this mode, it is recommended to use an external pull-down on SCLK :param cs_count: is the number of /CS lines (one per device to drive on the SPI bus) """ SCK_BIT = 0x01 DO_BIT = 0x02 DI_BIT = 0x04 CS_BIT = 0x08 PAYLOAD_MAX_LENGTH = 0x10000 # 16 bits max def __init__(self, silent_clock=False, cs_count=4, turbo=True): self._ftdi = Ftdi() self._cs_bits = (((SpiController.CS_BIT << cs_count) - 1) & ~(SpiController.CS_BIT - 1)) self._ports = [None] * cs_count self._direction = (self._cs_bits | SpiController.DO_BIT | SpiController.SCK_BIT) self._turbo = turbo self._cs_high = Array('B') if self._turbo: if silent_clock: # Set SCLK as input to avoid emitting clock beats self._cs_high.extend([ Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT ]) # /CS to SCLK delay, use 8 clock cycles as a HW tempo self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8 - 1, 0xff]) # Restore idle state self._cs_high.extend( [Ftdi.SET_BITS_LOW, self._cs_bits, self._direction]) if not self._turbo: self._cs_high.append(Ftdi.SEND_IMMEDIATE) self._immediate = Array('B', [Ftdi.SEND_IMMEDIATE]) self._frequency = 0.0 def configure(self, vendor, product, interface, **kwargs): """Configure the FTDI interface as a SPI master""" for k in ('direction', 'initial'): if k in kwargs: del kwargs[k] self._frequency = \ self._ftdi.open_mpsse(vendor, product, interface, direction=self._direction, initial=self._cs_bits, # /CS all high **kwargs) def terminate(self): """Close the FTDI interface""" if self._ftdi: self._ftdi.close() self._ftdi = None def get_port(self, cs): """Obtain a SPI port to drive a SPI device selected by cs""" if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if cs >= len(self._ports): raise SpiIOError("No such SPI port") if not self._ports[cs]: cs_state = 0xFF & ~((SpiController.CS_BIT << cs) | SpiController.SCK_BIT | SpiController.DO_BIT) cs_cmd = Array('B', [Ftdi.SET_BITS_LOW, cs_state, self._direction]) self._ports[cs] = SpiPort(self, cs_cmd) self._flush() return self._ports[cs] @property def frequency_max(self): """Returns the maximum SPI clock""" return self._ftdi.frequency_max @property def frequency(self): """Returns the current SPI clock""" return self._frequency def _exchange(self, frequency, cs_cmd, out, readlen): """Perform a half-duplex transaction with the SPI slave""" if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if len(out) > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Output payload is too large") if readlen > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Input payload is too large") if self._frequency != frequency: self._ftdi.set_frequency(frequency) # store the requested value, not the actual one (best effort) self._frequency = frequency write_cmd = struct.pack('<BH', Ftdi.WRITE_BYTES_NVE_MSB, len(out) - 1) if readlen: read_cmd = struct.pack('<BH', Ftdi.READ_BYTES_NVE_MSB, readlen - 1) cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) cmd.fromstring(read_cmd) cmd.extend(self._immediate) if self._turbo: cmd.extend(self._cs_high) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) self._ftdi.write_data(self._cs_high) # USB read cycle may occur before the FTDI device has actually # sent the data, so try to read more than once if no data is # actually received data = self._ftdi.read_data_bytes(readlen, 4) else: cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) if self._turbo: cmd.extend(self._cs_high) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) self._ftdi.write_data(self._cs_high) data = Array('B') return data def _flush(self): """Flush the HW FIFOs""" self._ftdi.write_data(self._immediate) self._ftdi.purge_buffers()
def _exchange(self, frequency, cs_cmd, out, readlen): """Perform a half-duplex transaction with the SPI slave""" if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if len(out) > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Output payload is too large") if readlen > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Input payload is too large") if self._frequency != frequency: self._ftdi.set_frequency(frequency) # store the requested value, not the actual one (best effort) self._frequency = frequency write_cmd = struct.pack('<BH', Ftdi.WRITE_BYTES_NVE_MSB, len(out) - 1) if readlen: read_cmd = struct.pack('<BH', Ftdi.READ_BYTES_NVE_MSB, readlen - 1) cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) cmd.fromstring(read_cmd) cmd.extend(self._immediate) if self._turbo: cmd.extend(self._cs_high) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) self._ftdi.write_data(self._cs_high) # USB read cycle may occur before the FTDI device has actually # sent the data, so try to read more than once if no data is # actually received data = self._ftdi.read_data_bytes(readlen, 4) else: cmd = Array('B', cs_cmd) cmd.fromstring(write_cmd) cmd.extend(out) if self._turbo: cmd.extend(self._cs_high) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) self._ftdi.write_data(self._cs_high) data = Array('B') return data
def test_flashdevice_4_long_rw(self): """Long R/W test """ # Max size to perform the test on size = 1 << 20 # Whether to test with random value, or contiguous values to ease debug randomize = True # Fill in the whole flash with a monotonic increasing value, that is # the current flash 32-bit address, then verify the sequence has been # properly read back # limit the test to 1MiB to keep the test duration short, but performs # test at the end of the flash to verify that high addresses may be # reached length = min(len(self.flash), size) start = len(self.flash)-length print("Erase %s from flash @ 0x%06x (may take a while...)" % (pretty_size(length), start)) delta = now() self.flash.unlock() self.flash.erase(start, length, True) delta = now()-delta self._report_bw('Erased', length, delta) if str(self.flash).startswith('SST'): # SST25 flash devices are tremendously slow at writing (one or two # bytes per SPI request MAX...). So keep the test sequence short # enough length = 16 << 10 print("Build test sequence") if not randomize: buf = Array('I') back = Array('I') for address in range(0, length, 4): buf.append(address) # Expect to run on x86 or ARM (little endian), so swap the values # to ease debugging # A cleaner test would verify the host endianess, or use struct # module buf.byteswap() # Cannot use buf directly, as it's an I-array, # and SPI expects a B-array else: seed(0) buf = Array('B') back = Array('B') buf.extend((randint(0, 255) for _ in range(0, length))) bufstr = buf.tobytes() print("Writing %s to flash (may take a while...)" % pretty_size(len(bufstr))) delta = now() self.flash.write(start, bufstr) delta = now()-delta length = len(bufstr) self._report_bw('Wrote', length, delta) wmd = sha1() wmd.update(buf.tobytes()) refdigest = wmd.hexdigest() print("Reading %s from flash" % pretty_size(length)) delta = now() data = self.flash.read(start, length) delta = now()-delta self._report_bw('Read', length, delta) # print "Dump flash" # print hexdump(data.tobytes()) print("Verify flash") rmd = sha1() rmd.update(data.tobytes()) newdigest = rmd.hexdigest() print("Reference:", refdigest) print("Retrieved:", newdigest) if refdigest != newdigest: errcount = 0 back.fromstring(data) for pos in range(len(buf)): if buf[pos] != data[pos]: print('Invalid byte @ offset 0x%06x: 0x%02x / 0x%02x' % (pos, buf[pos], back[pos])) errcount += 1 # Stop report after 16 errors if errcount >= 32: break raise self.fail('Data comparison mismatch')
def generate_cis(config, cis_output_path, cia_output_path): #Return a list of addresses of where the offsets for the FBR will be main_cis = Array('B') address_list = [] cia_template = None with open(cia_output_path, 'r') as f: cia_template = Template(f.read()) f.close() #Main CIS main_cis.append(CIS_TYPE["MANUFACTURER_ID"]["code"]) main_cis.append(CIS_TYPE["MANUFACTURER_ID"]["length"]) vendor = int(str(config["vendor id"]), 0) product = int(str(config["product id"]), 0) main_cis.append((vendor >> 8) & 0xFF) main_cis.append((vendor) & 0xFF) main_cis.append((product >> 8) & 0xFF) main_cis.append((product) & 0xFF) #Main CIS Function ID main_cis.append(CIS_TYPE["FUNCTION_ID"]["code"]) main_cis.append(CIS_TYPE["FUNCTION_ID"]["length"]) main_cis.append(0x0C) main_cis.append(0x00) #Main CIS Function Extension main_cis.append(CIS_TYPE["FUNCTION_EXT"]["code"]) main_cis.append(0x06) main_cis.append(0x00) #Extension Type (0x00) main_cis.append((config["max byte transfer size"] >> 8) & 0xFF) #Maximum num of bytes to be transfered in block main_cis.append((config["max byte transfer size"]) & 0xFF) #Maximum num of bytes to be transfered in block #Max Transfer Speed main_cis.append(generate_speed_byte(config)) #Temperature constraints main_cis.append(0x00) main_cis.append(0x00) #Last Entry main_cis.append(CIS_TYPE["END"]["code"]) #FBRs for i in range(1, 8): address_list.append(len(main_cis) - 1) if not is_valid_func(i, config): main_cis.append(CIS_TYPE["END"]["code"]) continue f = config["functions"][i - 1] #print "f: %s" % str(f) #Add Function ID main_cis.append(CIS_TYPE["FUNCTION_ID"]["code"]) main_cis.append(CIS_TYPE["FUNCTION_ID"]["length"]) main_cis.append(0x0C) main_cis.append(0x00) #Add Function ID Extension main_cis.append(CIS_TYPE["FUNCTION_ID"]["code"]) main_cis.append(CIS_TYPE["FUNCTION_ID"]["length"]) main_cis.append(f["type"]) main_cis.append(0x00) if f["support wakeup"]: main_cis.append(0x01) else: main_cis.append(0x00) major = f["version"].partition(".")[0] minor = f["version"].partition(".")[2] major = int(major) minor = int(minor) main_cis.append((major << 4) | minor) main_cis.append((f["serial number"] >> 24) & 0xFF) main_cis.append((f["serial number"] >> 16) & 0xFF) main_cis.append((f["serial number"] >> 8) & 0xFF) main_cis.append((f["serial number"]) & 0xFF) #Size main_cis.append((f["size"] >> 24) & 0xFF) main_cis.append((f["size"] >> 16) & 0xFF) main_cis.append((f["size"] >> 8) & 0xFF) main_cis.append((f["size"]) & 0xFF) #Flags flags = 0x00 if f["read only"]: flags |= 0x1 if f["do not format"]: flags |= 0x2 main_cis.append(flags) #Max Block Transfer Size main_cis.append( (f["max byte transfer size"] >> 8) & 0xFF) #Maximum num of bytes to be transfered in block main_cis.append( (f["max byte transfer size"]) & 0xFF) #Maximum num of bytes to be transfered in block #Main CIS Function Extension main_cis.append(CIS_TYPE["FUNCTION_EXT"]["code"]) main_cis.append(0x2A) main_cis.append(0x01) #Extension Type (0x01) main_cis.append( (config["max byte transfer size"] >> 8) & 0xFF) #Maximum num of bytes to be transfered in block main_cis.append( (config["max byte transfer size"]) & 0xFF) #Maximum num of bytes to be transfered in block #Max Transfer Speed main_cis.append(generate_speed_byte(config)) #OCR ocr = generate_ocr(config) main_cis.append((ocr >> 8) & 0xFF) main_cis.append((ocr) & 0xFF) #Temperature constraints main_cis.append(DEFAULT_MIN_CURRENT) main_cis.append(DEFAULT_AVG_CURRENT) main_cis.append(DEFAULT_MAX_CURRENT) main_cis.append(DEFAULT_SB_MIN_CURRENT) main_cis.append(DEFAULT_SB_AVG_CURRENT) main_cis.append(DEFAULT_SB_MAX_CURRENT) #Min Bandwidth main_cis.append((f["min bandwidth"] >> 8) & 0xFF) main_cis.append((f["min bandwidth"]) & 0xFF) #Optimal Bandwidth main_cis.append((f["optimal bandwidth"] >> 8) & 0xFF) main_cis.append((f["optimal bandwidth"]) & 0xFF) #Timeout in 10mS main_cis.append((f["timeout"] >> 8) & 0xFF) main_cis.append((f["timeout"]) & 0xFF) #AVG Power @ 3.3V main_cis.append(DEFAULT_AVG_CURRENT) #MAX Power @ 3.3V main_cis.append(DEFAULT_MAX_CURRENT) #HP AVG Power @ 3.3V main_cis.append((DEFAULT_HP_AVG_CURRENT >> 8) & 0xFF) main_cis.append((DEFAULT_HP_AVG_CURRENT) & 0xFF) #HP MAX Power @ 3.3V main_cis.append((DEFAULT_HP_MAX_CURRENT >> 8) & 0xFF) main_cis.append((DEFAULT_HP_MAX_CURRENT) & 0xFF) #LP AVG Power @ 3.3V main_cis.append((DEFAULT_LP_AVG_CURRENT >> 8) & 0xFF) main_cis.append((DEFAULT_LP_AVG_CURRENT) & 0xFF) #LP MAX Power @ 3.3V main_cis.append((DEFAULT_LP_MAX_CURRENT >> 8) & 0xFF) main_cis.append((DEFAULT_LP_MAX_CURRENT) & 0xFF) #Add SDIO Standard Extension if f["type"] > 0: print "Standard SDIO CIS is Not Supported at this time!" #Add End main_cis.append(CIS_TYPE["END"]["code"]) address_list.append(len(main_cis) - 1) #print "test :%s" % str(main_cis) #Tuple returnning the offsets for each of the address for main CIS, and function CIS as well as the length of the # Total CIS with open(cis_output_path, 'w') as f: while (len(main_cis) % 4) != 0: main_cis.append(0) for pos in range(0, len(main_cis), 4): f.write("%02X%02X%02X%02X\n" % (main_cis[pos + 0], main_cis[pos + 1], main_cis[pos + 2], main_cis[pos + 3])) #main_cis.tofile(f) #print "Substituting..." cia_output_buf = cia_template.safe_substitute( FUNC1_CIS_OFFSET=address_list[0], FUNC2_CIS_OFFSET=address_list[1], FUNC3_CIS_OFFSET=address_list[2], FUNC4_CIS_OFFSET=address_list[3], FUNC5_CIS_OFFSET=address_list[4], FUNC6_CIS_OFFSET=address_list[5], FUNC7_CIS_OFFSET=address_list[6], CIS_FILE_NAME=os.path.split(cis_output_path)[-1], CIS_FILE_LENGTH=len(main_cis)) with open(cia_output_path, 'w') as f: f.write(cia_output_buf) return address_list
class FT245(BusDriver): _signals = ["data", "txe_n", "wr_n", "rd_n", "rde_n", "oe_n", "siwu"] def __init__(self, entity, name, clock, buffer_size = BUFFER_SIZE, debug = False): BusDriver.__init__(self, entity, name, clock) if debug: self.log.setLevel(logging.DEBUG) self.buffer_size = buffer_size self.bus.data.binstr = 'ZZZZZZZZ' self.bus.txe_n <= 1 self.bus.rde_n <= 1 self.data = Array('B') @cocotb.coroutine def write(self, data): length = len(data) data_pos = 0 #XXX: Need to simulate the buffer size behavior to exercise the delay behavior buffer_pos = 0 #print "Sending: %s" % list_to_hex_string(data) self.bus.data <= data[data_pos] while data_pos < length: if not self.bus.oe_n.value: self.bus.data <= data[data_pos] else: #self.log.error("User requested data when OE is not low!!") self.bus.data.binstr = 'ZZZZZZZZ' if not self.bus.rde_n.value and not self.bus.rd_n.value: data_pos += 1 buffer_pos += 1 if self.bus.oe_n.value: self.log.error("User requested data when OE is not low!!") if data_pos < length: self.bus.data <= data[data_pos] else: break if buffer_pos < self.buffer_size: #Notify the FPGA that we have data available self.bus.rde_n <= 0 else: #print "Buffer pos is too large..." buffer_pos = 0 self.bus.rde_n <= 1 yield RisingEdge(self.clock) self.bus.data.binstr = 'ZZZZZZZZ' self.bus.rde_n <= 1 yield RisingEdge(self.clock) @cocotb.coroutine def read(self, byte_length): data_pos = 0 self.data = Array('B') buffer_pos = 0 self.bus.data.binstr = 'ZZZZZZZZ' self.bus.txe_n <= 1 while data_pos < byte_length: if buffer_pos < self.buffer_size: self.bus.txe_n <= 0 else: self.bus.txe_n <= 1 buffer_pos = 0 yield ReadOnly() if not self.bus.wr_n.value: self.data.append(self.bus.data.value) data_pos += 1 buffer_pos += 1 yield FallingEdge(self.clock) self.bus.txe_n <= 1 yield RisingEdge(self.clock) def get_data(self): return self.data
def tostring(x: array) -> str: return x.tobytes().decode('utf-8')
def from_array(self, param: array): if param.typecode != 'd': raise TypeError("Must be an array of doubles") ptr, _ = param.buffer_info() return ctypes.cast(ptr, ctypes.POINTER(ctypes.c_double)) # type: ignore
def test_long_burst(self): status = "Passed" fail = False fail_count = 0 position = 0 #self.clear_memory() total_size = self.n.get_device_size(self.urn) total_size = MAX_LONG_SIZE * 2 size = 0 if total_size > MAX_LONG_SIZE: print("Memory Size: 0x%08X is larger than read/write size" % total_size) print("\tBreaking transaction into 0x%08X chunks" % MAX_LONG_SIZE) size = MAX_LONG_SIZE else: size = total_size #Write Data Out while position < total_size: data_out = Array('B') for i in range(0, size): data_out.append((i % 0x100)) self.n.write_memory(position, data_out) #Increment the position prev_pos = position if position + size > total_size: size = total_size - position position += size print("Wrote: 0x%08X - 0x%08X" % (prev_pos, position)) #time.sleep(0.1) position = 0 size = total_size if total_size > MAX_LONG_SIZE: print("Memory Size: 0x%08X is larger than read/write size" % total_size) print("\tBreaking transaction into 0x%08X chunks" % MAX_LONG_SIZE) size = MAX_LONG_SIZE while (position < total_size) and fail_count < 257: data_in = self.n.read_memory(position, size / 4) if size != len(data_in): print("Data in length not equal to data_out length") print("\toutgoing: %d" % size) print("\tincomming: %d" % len(data_in)) dout = data_out.tolist() din = data_in.tolist() for i in range(len(data_out)): out_val = dout[i] in_val = din[i] if out_val != in_val: fail = True status = "Failed" print( "Mismatch @ 0x%08X: Write: (Hex): 0x%08X Read (Hex): 0x%08X" % (position + i, data_out[i], data_in[i])) if fail_count >= 16: break fail_count += 1 prev_pos = position if (position + size) > total_size: size = total_size - position position += size print("Read: 0x%08X - 0x%08X" % (prev_pos, position)) return status
def create_inc_buf(count): buf = Array('B') for i in range(count): buf.append(i % 256) return buf
def __init__(self, entity, name, clock): BusDriver.__init__(self, entity, name, clock) self.read_data_busy = Lock("%s_wbusy" % name) self.data = Array('B')
class SpiController(object): """SPI master. :param silent_clock: deprecated. :param int cs_count: is the number of /CS lines (one per device to drive on the SPI bus) :param boolean turbo: to be documented """ SCK_BIT = 0x01 DO_BIT = 0x02 DI_BIT = 0x04 CS_BIT = 0x08 PAYLOAD_MAX_LENGTH = 0x10000 # 16 bits max def __init__(self, silent_clock=False, cs_count=4, turbo=True): self._ftdi = Ftdi() self._cs_bits = (((SpiController.CS_BIT << cs_count) - 1) & ~(SpiController.CS_BIT - 1)) self._ports = [None] * cs_count self._direction = (self._cs_bits | SpiController.DO_BIT | SpiController.SCK_BIT) self._turbo = turbo self._cs_high = Array('B') # Restore idle state self._cs_high.extend( (Ftdi.SET_BITS_LOW, self._cs_bits, self._direction)) if not self._turbo: self._cs_high.append(Ftdi.SEND_IMMEDIATE) self._immediate = Array('B', (Ftdi.SEND_IMMEDIATE, )) self._frequency = 0.0 self._clock_phase = False @property def direction(self): return self._direction def configure(self, url, **kwargs): """Configure the FTDI interface as a SPI master""" for k in ('direction', 'initial'): if k in kwargs: del kwargs[k] self._frequency = self._ftdi.open_mpsse_from_url( # /CS all high url, direction=self._direction, initial=self._cs_bits, **kwargs) self._ftdi.enable_adaptive_clock(False) def terminate(self): """Close the FTDI interface""" if self._ftdi: self._ftdi.close() self._ftdi = None def get_port(self, cs, freq=None, mode=0): """Obtain a SPI port to drive a SPI device selected by cs :param int cs: chip select slot, starting from 0 :param int freq: SPI bus frequency for this slave :param int mode: SPI mode [0,1,3] :rtype: SpiPort """ if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if cs >= len(self._ports): raise SpiIOError("No such SPI port") if not (0 <= mode <= 3): raise SpiIOError("Invalid SPI mode") if (mode & 0x2) and not self._ftdi.is_H_series: raise SpiIOError("SPI with CPHA high is not supported by " "this FTDI device") if mode == 2: raise SpiIOError("SPI mode 2 has no known workaround with FTDI " "devices") if not self._ports[cs]: freq = min(freq or self.frequency_max, self.frequency_max) hold = freq and (1 + int(1E6 / freq)) self._ports[cs] = SpiPort(self, cs, cs_hold=hold, spi_mode=mode) self._ports[cs].set_frequency(freq) self._flush() return self._ports[cs] @property def frequency_max(self): """Returns the maximum SPI clock""" return self._ftdi.frequency_max @property def frequency(self): """Returns the current SPI clock""" return self._frequency def _exchange(self, frequency, out, readlen, cs_cmd=None, cs_release=None, cpol=False, cpha=False): """Perform a half-duplex exchange or transaction with the SPI slave :param frequency: SPI bus clock :param out: an array of bytes to send to the SPI slave, may be empty to only read out data from the slave :param readlen: count of bytes to read out from the slave, may be zero to only write to the slave :param cs_cmd: the prolog sequence to activate the /CS line on the SPI bus. May be empty to resume a previously started transaction :param cs_release: the epilog sequence to send to move the /CS line back to the idle state. May be empty to if another part of a transaction is expected :return: an array of bytes containing the data read out from the slave """ if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if len(out) > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Output payload is too large") if readlen > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Input payload is too large") if cpha: # to enable CPHA, we need to use a workaround with FTDI device, # that is enable 3-phase clocking (which is usually dedicated to # I2C support). This mode use use 3 clock period instead of 2, # which implies the FTDI frequency should be fixed to match the # requested one. frequency = (3 * frequency) // 2 if self._frequency != frequency: self._ftdi.set_frequency(frequency) # store the requested value, not the actual one (best effort) self._frequency = frequency cmd = cs_cmd and Array('B', cs_cmd) or Array('B') if cs_release: epilog = Array('B', cs_release) epilog.extend(self._cs_high) else: epilog = None writelen = len(out) if self._clock_phase != cpha: self._ftdi.enable_3phase_clock(cpha) self._clock_phase = cpha if writelen: wcmd = (cpol ^ cpha) and \ Ftdi.WRITE_BYTES_PVE_MSB or Ftdi.WRITE_BYTES_NVE_MSB write_cmd = struct.pack('<BH', wcmd, writelen - 1) cmd.frombytes(write_cmd) cmd.extend(out) if readlen: rcmd = (cpol ^ cpha) and \ Ftdi.READ_BYTES_PVE_MSB or Ftdi.READ_BYTES_NVE_MSB read_cmd = struct.pack('<BH', rcmd, readlen - 1) cmd.frombytes(read_cmd) cmd.extend(self._immediate) if self._turbo: if epilog: cmd.extend(epilog) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) if epilog: self._ftdi.write_data(epilog) # USB read cycle may occur before the FTDI device has actually # sent the data, so try to read more than once if no data is # actually received data = self._ftdi.read_data_bytes(readlen, 4) else: if writelen: if self._turbo: if epilog: cmd.extend(epilog) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) if epilog: self._ftdi.write_data(epilog) data = Array('B') return data def _flush(self): """Flush the HW FIFOs""" self._ftdi.write_data(self._immediate) self._ftdi.purge_buffers()
def invert(self): """In-place invert sequence values""" self._seq = Array('B', [x^1 for x in self._seq]) return self
def _exchange(self, frequency, out, readlen, cs_cmd=None, cs_release=None, cpol=False, cpha=False): """Perform a half-duplex exchange or transaction with the SPI slave :param frequency: SPI bus clock :param out: an array of bytes to send to the SPI slave, may be empty to only read out data from the slave :param readlen: count of bytes to read out from the slave, may be zero to only write to the slave :param cs_cmd: the prolog sequence to activate the /CS line on the SPI bus. May be empty to resume a previously started transaction :param cs_release: the epilog sequence to send to move the /CS line back to the idle state. May be empty to if another part of a transaction is expected :return: an array of bytes containing the data read out from the slave """ if not self._ftdi: raise SpiIOError("FTDI controller not initialized") if len(out) > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Output payload is too large") if readlen > SpiController.PAYLOAD_MAX_LENGTH: raise SpiIOError("Input payload is too large") if cpha: # to enable CPHA, we need to use a workaround with FTDI device, # that is enable 3-phase clocking (which is usually dedicated to # I2C support). This mode use use 3 clock period instead of 2, # which implies the FTDI frequency should be fixed to match the # requested one. frequency = (3 * frequency) // 2 if self._frequency != frequency: self._ftdi.set_frequency(frequency) # store the requested value, not the actual one (best effort) self._frequency = frequency cmd = cs_cmd and Array('B', cs_cmd) or Array('B') if cs_release: epilog = Array('B', cs_release) epilog.extend(self._cs_high) else: epilog = None writelen = len(out) if self._clock_phase != cpha: self._ftdi.enable_3phase_clock(cpha) self._clock_phase = cpha if writelen: wcmd = (cpol ^ cpha) and \ Ftdi.WRITE_BYTES_PVE_MSB or Ftdi.WRITE_BYTES_NVE_MSB write_cmd = struct.pack('<BH', wcmd, writelen - 1) cmd.frombytes(write_cmd) cmd.extend(out) if readlen: rcmd = (cpol ^ cpha) and \ Ftdi.READ_BYTES_PVE_MSB or Ftdi.READ_BYTES_NVE_MSB read_cmd = struct.pack('<BH', rcmd, readlen - 1) cmd.frombytes(read_cmd) cmd.extend(self._immediate) if self._turbo: if epilog: cmd.extend(epilog) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) if epilog: self._ftdi.write_data(epilog) # USB read cycle may occur before the FTDI device has actually # sent the data, so try to read more than once if no data is # actually received data = self._ftdi.read_data_bytes(readlen, 4) else: if writelen: if self._turbo: if epilog: cmd.extend(epilog) self._ftdi.write_data(cmd) else: self._ftdi.write_data(cmd) if epilog: self._ftdi.write_data(epilog) data = Array('B') return data
def __ilshift__(self, count): count %= len(self) seq = Array('B', [0]*count) seq.extend(self._seq[:-count]) self._seq = seq return self
def tostring(x: array) -> str: return x.tobytes().decode('utf-8') class Strand(CNObject):
class NysaSimUart(Nysa): def __init__(self, dut, uart_if, sim_config, period=CLK_PERIOD, user_paths=[], status=None): self.dev_dict = json.load(open(sim_config), object_pairs_hook=OrderedDict) Nysa.__init__(self, Status()) self.s.set_level('verbose') self.user_paths = user_paths self.comm_lock = cocotb.triggers.Lock('comm') self.dut = dut cocotb.fork(Clock(dut.clk, period).start()) gd = GenSDB() self.rom = gd.gen_rom(self.dev_dict, user_paths=self.user_paths, debug=False) self.uart = uart_if self.response = Array('B') @cocotb.coroutine def wait_clocks(self, num_clks): for i in range(num_clks): yield RisingEdge(self.dut.clk) def read_sdb(self): """read_sdb Read the contents of the DRT Args: Nothing Returns (Array of bytes): the raw DRT data, this can be ignored for normal operation Raises: Nothing """ self.s.Verbose("entered") gd = GenSDB() self.rom = gd.gen_rom(self.dev_dict, user_paths=self.user_paths, debug=False) return self.nsm.read_sdb(self) def read(self, address, length=1, disable_auto_inc=False): if (address * 4) + (length * 4) <= len(self.rom): length *= 4 address *= 4 ra = Array('B') for count in range(0, length, 4): ra.extend(self.rom[address + count:address + count + 4]) #print "ra: %s" % str(ra) return ra mem_device = False if self.mem_addr is None: self.mem_addr = self.nsm.get_address_of_memory_bus() if address >= self.mem_addr: address = address - self.mem_addr mem_device = True self._read(address, length, mem_device) return self.response @cocotb.coroutine def _read(self, address, length=1, disable_auto_inc=False): self.dut.log.info("read response: %s" % str(read_rsp)) read_cmd = "L%0.7X00000002%0.8X00000000" read_cmd = (read_cmd) % (length, address) yield (self.uart.read)(32 + (length * 8)) read_rsp = self.read_data() self.response = Array('B') if len(read_rsp) > 0: for i in range(0, length + 1): value = Array('B', read_rsp[(24 + (i * 8)):(32 + (i * 8))]) self.response.extend(value) def get_data(self): return self.response @cocotb.coroutine def write(self, address, data, disable_auto_inc=False): """write Generic write command usd to write data to a Nysa image Args: address (int): Address of the register/memory to read data (array of unsigned bytes): Array of raw bytes to send to the device disable_auto_inc (bool): if true, auto increment feature will be disabled Returns: Nothing Raises: AssertionError: This function must be overriden by a board specific implementation """ self.dut.log.info("write value: %s" % str(read_rsp)) if not isinstance(data, list): data = [data] length = len(data) - 1 write_cmd = "L%0.7X00000001%0.8X" write_cmd = (write_cmd) % (length, address) yield self.uart.write(write_cmd) write_rsp = self.uart.read(32) def ping(self): """ping Pings the Nysa image Args: Nothing Returns: Nothing Raises: NysaCommError: When a failure of communication is detected """ self.uart.write("L0000000000000000000000000000000") ping_string = self.uart.read(32) @cocotb.coroutine def reset(self): """reset Software reset the Nysa FPGA Master, this may not actually reset the entire FPGA image Args: Nothing Returns: Nothing Raises: NysaCommError: A failure of communication is detected """ yield (self.comm_lock.acquire()) #print "Reset Acquired Lock" yield (self.wait_clocks(RESET_PERIOD / 2)) self.dut.rst <= 1 #self.dut.log.info("Sending Reset to the bus") self.dut.in_ready <= 0 self.dut.out_ready <= 0 self.dut.in_command <= 0 self.dut.in_address <= 0 self.dut.in_data <= 0 self.dut.in_data_count <= 0 yield (self.wait_clocks(RESET_PERIOD / 2)) self.dut.rst <= 0 yield (self.wait_clocks(RESET_PERIOD / 2)) yield (self.wait_clocks(10)) self.comm_lock.release() #print "Reset Release Lock" def is_programmed(self): """ Returns True if the FPGA is programmed Args: Nothing Returns (Boolean): True: FPGA is programmed False: FPGA is not programmed Raises: NysaCommError: A failure of communication is detected """ raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def get_sdb_base_address(self): """ Return the base address of the SDB (This is platform specific) Args: Nothing Returns: 32-bit unsigned integer of the address where the SDB can be read Raises: Nothing """ #raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) #Normally with Nysa platform address is at adress 0x00 on the peripheral bus return 0x00 def wait_for_interrupts(self, wait_time=1): """wait_for_interrupts listen for interrupts for the specified amount of time Args: wait_time (int): the amount of time in seconds to wait for an interrupt Returns: (boolean): True: Interrupts were detected False: No interrupts detected Raises: NysaCommError: A failure of communication is detected """ raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def register_interrupt_callback(self, index, callback): """ register_interrupt Setup the thread to call the callback when an interrupt is detected Args: index (Integer): bit position of the device if the device is 1, then set index = 1 callback: a function to call when an interrupt is detected Returns: Nothing Raises: Nothing """ temp_string = self.uart.read(32) if len(temp_string) == 0: return False self.interrupt_address = string.atoi(temp_string[16:24], 16) self.interrupts = string.atoi(temp_string[24:32], 16) return True def unregister_interrupt_callback(self, index, callback=None): """ unregister_interrupt_callback Removes an interrupt callback from the reader thread list Args: index (Integer): bit position of the associated device EX: if the device that will receive callbacks is 1, index = 1 callback: a function to remove from the callback list Returns: Nothing Raises: Nothing (This function fails quietly if ther callback is not found) """ raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def get_board_name(self): return "uart" def upload(self, filepath): """ Uploads an image to a board Args: filepath (String): path to the file to upload Returns: Nothing Raises: NysaError: Failed to upload data AssertionError: Not Implemented """ raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def program(self): """ Initiate an FPGA program sequence, THIS DOES NOT UPLOAD AN IMAGE, use upload to upload an FPGA image Args: Nothing Returns: Nothing Raises: AssertionError: Not Implemented """ raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def ioctl(self, name, arg=None): """ Platform specific functions to execute on a Nysa device implementation. For example a board may be capable of setting an external voltage or reading configuration data from an EEPROM. All these extra functions cannot be encompused in a generic driver Args: name (String): Name of the function to execute args (object): A generic object that can be used to pass an arbitrary or multiple arbitrary variables to the device Returns: (object) an object from the underlying function Raises: NysaError: An implementation specific error """ raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name) def list_ioctl(self): """ Return a tuple of ioctl functions and argument types and descriptions in the following format: { [name, description, args_type_object], [name, description, args_type_object] ... } Args: Nothing Raises: AssertionError: Not Implemented """ raise AssertionError("%s not implemented" % sys._getframe().f_code.co_name)
def encode_py_array(data: array.array) -> bytes: typecode = data.typecode count = data.buffer_info()[1] byte_count = count * data.itemsize buffer = encode_string(typecode) + encode_int(byte_count) + data.tobytes() return buffer
def sync(self): if not self._ftdi: raise JtagError("FTDI controller terminated") if self._write_buff: self._ftdi.write_data(self._write_buff) self._write_buff = Array('B')
def load_rom(self, filename): f = open(filename, 'r') #data = f.read() data = Array('B') data.fromstring(f.read()) print "Length of data: %d" % len(data) print "Type: %s" % str(type(data)) f.close() #if ((data[0] != 'N') or (data[1] != 'E') or (data[2] != 'S') or (data[3] != 0x1A)): if ((data[0] != 0x4E) or (data[1] != 0x45) or (data[2] != 0x53) or (data[3] != 0x1A)): raise NESError("Invalid ROM header") prg_rom_banks = data[4] chr_rom_banks = data[5] if (prg_rom_banks > 2) or (chr_rom_banks > 1): raise NESError("Too many ROM banks: PRG_ROM: %d CHR ROM: %d" % (prg_rom_banks, chr_rom_banks)) mapper = (((data[6] & 0xF0) >> 4) | ((data[7] & 0xF0)) != 0) if mapper != 0: raise NESError("Only mapper 0 is supported") # Issue a debug break yield self.enter_debug() #Disable PPU yield self.disable_ppu() #Set header info to config mapper config = [0] * 5 config[0] = data[4] config[1] = data[5] config[2] = data[6] config[3] = data[7] config[4] = data[8] yield self.set_cart_config(config) #Calculate all the sizes prg_rom_size = prg_rom_banks * 0x4000 chr_rom_size = chr_rom_banks * 0x2000 total_size = prg_rom_size + chr_rom_size transfer_block_size = 0x400 prg_rom = data[16:16 + prg_rom_size] chr_rom = data[16 + prg_rom_size: 16 + prg_rom_size + chr_rom_size] #XXX: SIMULATION Don't write too much data if SIM: load_prg_rom = prg_rom[0:256] load_chr_rom = prg_rom[0:256] prg_offset = 0x8000 #Copy PRG ROM data if SIM: yield self.write_cpu_mem(prg_offset, load_prg_rom) else: yield self.write_cpu_mem(prg_offset, prg_rom) #Copy CHR ROM data #chr_offset = prg_offset + len(prg_rom) chr_offset = 0x00 #yield self.write_cpu_mem(chr_offset, chr_rom) if SIM: yield self.write_ppu_mem(chr_offset, load_chr_rom) else: yield self.write_ppu_mem(chr_offset, chr_rom) #Update PC to point to the reset interrupt vector location pcl_val = data[16 + prg_rom_size - 4] pch_val = data[16 + prg_rom_size - 3] print "PCH:PCL: %02X:%02X" % (pch_val, pcl_val) yield self.write_cpu_register(CPU_REG_PCL, pcl_val) yield self.write_cpu_register(CPU_REG_PCH, pch_val) #Issue a debug run command yield self.exit_debug()