def synchronize(m, signal, *, output=None, o_domain='sync', stages=2): """ Convenience function. Synchronizes a signal, or equivalent collection. Parameters: input -- The signal to be synchronized. output -- The signal to output the result of the synchronization to, or None to have one created for you. domain -- The name of the domain to be synchronized to. stages -- The depth (in FFs) of the synchronization chain. Longer incurs more delay. Must be >= 2 to avoid metastability. Returns: record -- The post-synchronization signal. Will be equivalent to the `output` record if provided, or a new, created signal otherwise. """ # Quick function to create a synchronizer with our domain and stages. def create_synchronizer(signal, output): return FFSynchronizer(signal, output, o_domain=o_domain, stages=stages) if output is None: if isinstance(signal, Signal): output = Signal.like(signal) else: output = Record.like(signal) # If the object knows how to synchronize itself, let it. if hasattr(signal, '_synchronize_'): signal._synchronize_(m, output, o_domain=o_domain, stages=stages) return output # Trivial case: if this element doesn't have a layout, # we can just synchronize it directly. if not hasattr(signal, 'layout'): m.submodules += create_synchronizer(signal, output) return output # Otherwise, we'll need to make sure we only synchronize # elements with non-output directions. for name, layout, direction in signal.layout: # If this is a record itself, we'll need to recurse. if isinstance(signal[name], (Record, Pin)): synchronize(m, signal[name], output=output[name], o_domain=o_domain, stages=stages) continue # Skip any output elements, as they're already # in our clock domain, and we don't want to drive them. if (direction == DIR_FANOUT) or (hasattr(signal[name], 'o') and ~hasattr(signal[name], 'i')): m.d.comb += signal[name].eq(output[name]) continue m.submodules += create_synchronizer(signal[name], output[name]) return output
def __init__(self): super().__init__() self.reg_verify_value = Signal(32) self.accelerator_start = Signal() self.accelerator_reset = Signal() self.config = Record(ACCELERATOR_CONFIGURATION_LAYOUT) self.filter_output = Endpoint(FILTER_WRITE_COMMAND) self.post_process_params = Endpoint(POST_PROCESS_PARAMS)
def instantiate_dut(self): # Create a record that recreates the layout of our RAM signals. self.ram_signals = Record([("clk", 1), ("clkN", 1), ("dq", [("i", 8), ("o", 8), ("oe", 1)]), ("rwds", [("i", 1), ("o", 1), ("oe", 1)]), ("cs", 1), ("reset", 1)]) # Create our HyperRAM interface... return HyperRAMInterface(bus=self.ram_signals)
def test_nested_record(self): m = Module() record = Record([('sig_in', 1, DIR_FANIN), ('sig_out', 1, DIR_FANOUT), ('nested', [ ('subsig_in', 1, DIR_FANIN), ('subsig_out', 1, DIR_FANOUT), ])]) synchronize(m, record)
def get_axi(self, axi): assert axi in self.MAXI + self.SAXI if axi in self.MAXI: layout = get_axi_layout('master') elif axi in self.SAXI: layout = get_axi_layout('slave') fields = {f: self._ports[axi.upper() + f] for f, w, d in layout} layout = [(f, w) for f, w, _ in layout] rec = Record(layout, fields=fields, name=axi) return rec
def instantiate_dut(self): self.utmi = Record([ ('tx_data', 8), ('rx_data', 8), ('rx_valid', 1), ('rx_active', 1), ('rx_error', 1), ('rx_complete', 1), ]) return USBAnalyzer(utmi_interface=self.utmi, mem_depth=128)
def instantiate_dut(self): self.ulpi = Record([ ("dir", 1), ("nxt", 1), ("data", [ ("i", 8), ]) ]) return ULPIRxEventDecoder(ulpi_bus=self.ulpi)
def __init__(self, specialize_nx=False): self._specialize_nx = specialize_nx self.reset = Signal() self.start = Signal() self.config = Record(ACCELERATOR_CONFIGURATION_LAYOUT) self.write_filter_input = Endpoint(FILTER_WRITE_COMMAND) self.lram_addr = [Signal(14, name=f"lram_addr{i}") for i in range(4)] self.lram_data = [Signal(32, name=f"lram_data{i}") for i in range(4)] self.post_process_params = Endpoint(POST_PROCESS_PARAMS) self.output = Endpoint(unsigned(32))
def instantiate_dut(self): from ..interface.ulpi import UTMITranslator self.ulpi = Record([('data', [ ('i', 8), ('o', 8), ('oe', 8), ]), ('nxt', 1), ('stp', 1), ('dir', [('i', 1)]), ('clk', 1), ('rst', 1)]) # Create a stack of our UTMITranslator and our USBAnalyzer. # We'll wrap the both in a module to establish a synthetic hierarchy. m = Module() m.submodules.translator = self.translator = UTMITranslator( ulpi=self.ulpi, handle_clocking=False) m.submodules.analyzer = self.analyzer = USBAnalyzer( utmi_interface=self.translator, mem_depth=128) return m
def test_directional_record(self): m = Module() record = Record([('sig_in', 1, DIR_FANIN), ('sig_out', 1, DIR_FANOUT)]) synchronize(m, record)
def __init__(self): self.sizes = Record(POST_PROCESS_SIZES) self.reset = Signal() self.output_data = Endpoint(POST_PROCESS_PARAMS) self.mem_addr = Signal(range(Constants.MAX_CHANNEL_DEPTH)) self.mem_data = Signal(POST_PROCESS_PARAMS_WIDTH)
""" name = signal.name for i in range(cycles): delayed = Signal.like(signal, name=f"{name}_delay_{i}") m.d.sync += delayed.eq(signal) signal = delayed return signal POST_PROCESS_PARAMS = [ ('bias', signed(18)), ('multiplier', signed(32)), ('shift', unsigned(4)), ] POST_PROCESS_PARAMS_WIDTH = len(Record(POST_PROCESS_PARAMS)) class PostProcessPipeline(SimpleElaboratable): """Converts an accumulator into an 8-bit value Attributes ---------- input: Endpoint(signed(32)), in The accumulated value to convert params: Endpoint(POST_PROCESS_PARAMS), in Parameters assumed always ready and then read on input output: Endpoint(signed(8)), out