class Top(Elaboratable): def __init__(self): self.reset = ControlSignal() self.to_write = ControlSignal(reset=32 * 1024 * 1024) self.data_counter = StatusSignal(32) self.perf_counter = StatusSignal(32) self.data_valid = ControlSignal() self.data_ready = StatusSignal() def elaborate(self, platform: ZynqSocPlatform): m = Module() platform.ps7.fck_domain(requested_frequency=200e6) m.d.comb += ResetSignal().eq(self.reset) ring_buffer = RingBufferAddressStorage(buffer_size=0x1200000, n=4) stream_source = StreamEndpoint(64, is_sink=False, has_last=True) m.d.comb += self.data_ready.eq(stream_source.ready) m.d.comb += stream_source.valid.eq(self.data_valid) clock_signal = Signal() m.d.comb += clock_signal.eq(ClockSignal()) axi_slave = platform.ps7.get_axi_hp_slave(clock_signal) axi_writer = m.submodules.axi_writer = AxiBufferWriter(ring_buffer, stream_source, axi_slave=axi_slave) with m.If(axi_writer.stream_source.ready & axi_writer.stream_source.valid): m.d.sync += self.data_counter.eq(self.data_counter + 1) m.d.comb += stream_source.payload.eq(Cat(self.data_counter, self.data_counter+1000)) with m.If((stream_source.valid) & (axi_writer.words_written < (self.to_write >> int(math.log2(axi_slave.data_bytes))))): m.d.sync += self.perf_counter.eq(self.perf_counter+1) return m
def __init__(self, video_timing, vertical_signals_shape=range(8000), horizontal_signals_shape=range(4000)): self.hscan = ControlSignal(horizontal_signals_shape, reset=video_timing.hscan) self.vscan = ControlSignal(vertical_signals_shape, reset=video_timing.vscan) self.width = ControlSignal(horizontal_signals_shape, reset=video_timing.hres) self.height = ControlSignal(vertical_signals_shape, reset=video_timing.vres) self.hsync_start = ControlSignal(horizontal_signals_shape, reset=video_timing.hsync_start) self.hsync_end = ControlSignal(horizontal_signals_shape, reset=video_timing.hsync_end) self.vsync_start = ControlSignal(vertical_signals_shape, reset=video_timing.vsync_start) self.vsync_end = ControlSignal(vertical_signals_shape, reset=video_timing.vsync_end) self.x = StatusSignal(horizontal_signals_shape, name="x") self.y = StatusSignal(vertical_signals_shape, name="y") self.active = StatusSignal(name="active") self.hsync = StatusSignal(name="hsync") self.vsync = StatusSignal(name="vsync")
def __init__(self, plugin): """ This module needs to run in the word clock domain of the bus. """ self.plugin = plugin self.output = StreamEndpoint(32, is_sink=False, has_last=False) self.ready = StatusSignal()
def __init__(self, num_lanes=4, bits=12): assert bits == 12 self.hispi_clk = Signal() self.hispi_lanes = Signal(num_lanes) self.bitslip = [Signal() for _ in range(num_lanes)] self.out = [Signal(12) for _ in range(num_lanes)] self.hispi_x6_in_domain_counter = StatusSignal(32)
def __init__( self, address_source: StreamEndpoint, axi_slave=None, axi_data_width=64 ): assert address_source.has_last is False self.address_source = address_source self.axi_slave = axi_slave self.output = StreamEndpoint(axi_data_width, is_sink=False, has_last=False) self.last_resp = StatusSignal(Response) self.error_count = StatusSignal(32)
def __init__(self, streams): self._streams = streams self.has_last = self._streams[0].has_last assert not any(self.has_last is not other.has_last for other in self._streams) width = sum(len(stream.payload) for stream in self._streams) self.output = StreamEndpoint(width, is_sink=False, has_last=self.has_last) self.different_last_error = StatusSignal() self.different_valid_error = StatusSignal()
class AxiBufferReader(Elaboratable): def __init__( self, address_source: StreamEndpoint, axi_slave=None, axi_data_width=64 ): assert address_source.has_last is False self.address_source = address_source self.axi_slave = axi_slave self.output = StreamEndpoint(axi_data_width, is_sink=False, has_last=False) self.last_resp = StatusSignal(Response) self.error_count = StatusSignal(32) def elaborate(self, platform): m = Module() if self.axi_slave is not None: assert not self.axi_slave.is_lite assert not self.axi_slave.is_master axi_slave = self.axi_slave else: clock_signal = Signal() m.d.comb += clock_signal.eq(ClockSignal()) axi_slave = platform.ps7.get_axi_hp_slave(clock_signal) axi = AxiEndpoint.like(axi_slave, master=True) m.d.comb += axi.connect_slave(axi_slave) assert len(self.output.payload) == axi.data_bits address_stream = StreamEndpoint.like(self.address_source, is_sink=True, name="address_sink") m.d.comb += address_stream.connect(self.address_source) assert len(address_stream.payload) == axi.addr_bits # we dont generate bursts for now m.d.comb += axi.read_address.valid.eq(address_stream.valid) m.d.comb += axi.read_address.value.eq(address_stream.payload) m.d.comb += address_stream.ready.eq(axi.read_address.ready) m.d.comb += axi.read_address.burst_len.eq(0) m.d.comb += axi.read_data.ready.eq(self.output.ready) m.d.comb += axi.read_data.last.eq(1) m.d.comb += self.output.valid.eq(axi.read_data.valid) m.d.comb += self.output.payload.eq(axi.read_data.value) m.d.sync += self.last_resp.eq(axi.read_data.resp) with m.If(axi.read_data.valid & (axi.read_data.resp != Response.OKAY)): m.d.sync += self.error_count.eq(self.error_count + 1) return m
def __init__(self, input: StreamEndpoint, depth: int, buffered=True, fwtf=False): assert input.is_sink is False self.input = input self.output = StreamEndpoint.like(input, name="stream_fifo_output") self.depth = depth self.buffered = buffered self.fwtf = fwtf self.max_w_level = StatusSignal(range(depth)) self.overflow_cnt = StatusSignal(32) self.underrun_cnt = StatusSignal(32) self.r_level = StatusSignal(range(depth + 1)) self.w_level = StatusSignal(range(depth + 1))
def __init__(self, input_clock, vco_mul, vco_div, input_domain="sync"): Mmcm.is_valid_vco_conf(input_clock, vco_mul, vco_div, exception=True) self._mmcm = InstanceHelper("+/xilinx/cells_xtra.v", "MMCME2_ADV")( clkin1_period=1 / input_clock * 1e9, clkfbout_mult_f=vco_mul, divclk_divide=vco_div, ) m = self.m = Module() m.d.comb += self._mmcm.clk.fbin.eq(self._mmcm.clk.fbout) m.d.comb += self._mmcm.clk.in_[1].eq(ClockSignal(input_domain)) m.d.comb += self._mmcm.clk.ins.el.eq(1) # HIGH for clkin1 self.locked = StatusSignal() self._input_domain = input_domain self._input_clock = input_clock self._vco = Clock(input_clock * vco_mul / vco_div) self._clock_constraints = {}
def __init__(self, input_freq, vco_mul, vco_div, input_domain="sync"): Pll.is_valid_vco_conf(input_freq, vco_mul, vco_div, exception=True) self._pll = RawPll( clkin1_period=1 / input_freq * 1e9, clkfbout_mult=vco_mul, divclk_divide=vco_div, ) m = self.m = Module() m.d.comb += self._pll.clk.fbin.eq(self._pll.clk.fbout) m.d.comb += self._pll.clk.in_[1].eq(ClockSignal(input_domain)) m.d.comb += self._pll.clk.insel.eq(1) # HIGH for clkin1 self.locked = StatusSignal() self._input_domain = input_domain self._input_freq = input_freq self._vco = Clock(input_freq * vco_mul / vco_div) self._clock_constraints = {}
class Top(Elaboratable): def __init__(self): self.counter = StatusSignal(32) self.test_reg = ControlSignal(32) def elaborate(self, platform): m = Module() if isinstance(platform, ZynqSocPlatform): platform.ps7.fck_domain(requested_frequency=100e6) m.d.sync += self.counter.eq(self.counter + 1) elif isinstance(platform, LatticeMachXO2Platform): osc = m.submodules.osc = Osc() m.d.sync += self.counter.eq(self.counter + 1) else: m.d.comb += self.counter.eq( 42) # we dont have a clock source so we cant count return m
class StreamCombiner(Elaboratable): def __init__(self, streams): self._streams = streams self.has_last = self._streams[0].has_last assert not any(self.has_last is not other.has_last for other in self._streams) width = sum(len(stream.payload) for stream in self._streams) self.output = StreamEndpoint(width, is_sink=False, has_last=self.has_last) self.different_last_error = StatusSignal() self.different_valid_error = StatusSignal() def elaborate(self, platform): m = Module() highest_bit = 0 for i, stream in enumerate(self._streams): sink = StreamEndpoint.like( stream, is_sink=True, name="stream_combiner_sink_{}".format(i)) sink.connect(stream) m.d.comb += stream.ready.eq(self.output.ready) m.d.comb += self.output.payload[highest_bit:highest_bit + len(stream.payload)].eq( stream.payload) highest_bit += len(stream.payload) m.d.comb += self.output.valid.eq(stream.valid) with m.If(self.output.valid != stream.valid): m.d.sync += self.different_valid_error.eq(1) if self.has_last: m.d.comb += self.output.last.eq(stream.last) with m.If(self.output.last != stream.last): m.d.sync += self.different_last_error.eq(1) return m
def __init__(self): self.reset = ControlSignal() self.to_write = ControlSignal(reset=32 * 1024 * 1024) self.data_counter = StatusSignal(32) self.perf_counter = StatusSignal(32) self.data_valid = ControlSignal() self.data_ready = StatusSignal()
def __init__(self, pads, name_suffix=""): """ A simple gpio peripheral, that is compatible with the gpio-mmio.c linux kernel pydriver. see https://github.com/torvalds/linux/blob/master/drivers/gpio/gpio-mmio.c """ self._pads = pads # see https://github.com/torvalds/linux/blob/master/drivers/gpio/gpio-mmio.c#L473 # we are using a configuration with one output one input and one direction register w = len(self._pads) self.set = ControlSignal(w) self.dat = StatusSignal(w) self.dirout = ControlSignal(w) self.devicetree_name = "mmio_gpio" + name_suffix
def __init__( self, ringbuffer: RingBufferAddressStorage, stream_source: StreamEndpoint, axi_slave=None, fifo_depth=32, max_burst_length=16 ): self.ringbuffer = ringbuffer self.current_buffer = ringbuffer.current_write_buffer assert stream_source.is_sink is False assert stream_source.has_last self.stream_source = stream_source self.axi_slave = axi_slave self.fifo_depth = fifo_depth self.max_burst_length = max_burst_length self.error = StatusSignal() self.state = StatusSignal(32) self.burst_position = StatusSignal(range(self.max_burst_length)) self.words_written = StatusSignal(32) self.buffers_written = StatusSignal(32)
class TimingGenerator(Elaboratable): def __init__(self, video_timing, vertical_signals_shape=range(8000), horizontal_signals_shape=range(4000)): self.hscan = ControlSignal(horizontal_signals_shape, reset=video_timing.hscan) self.vscan = ControlSignal(vertical_signals_shape, reset=video_timing.vscan) self.width = ControlSignal(horizontal_signals_shape, reset=video_timing.hres) self.height = ControlSignal(vertical_signals_shape, reset=video_timing.vres) self.hsync_start = ControlSignal(horizontal_signals_shape, reset=video_timing.hsync_start) self.hsync_end = ControlSignal(horizontal_signals_shape, reset=video_timing.hsync_end) self.vsync_start = ControlSignal(vertical_signals_shape, reset=video_timing.vsync_start) self.vsync_end = ControlSignal(vertical_signals_shape, reset=video_timing.vsync_end) self.x = StatusSignal(horizontal_signals_shape, name="x") self.y = StatusSignal(vertical_signals_shape, name="y") self.active = StatusSignal(name="active") self.hsync = StatusSignal(name="hsync") self.vsync = StatusSignal(name="vsync") def elaborate(self, plat): m = Module() # set the xy coordinates with m.If(self.x < self.hscan - 1): m.d.sync += self.x.eq(self.x + 1) with m.Else(): m.d.sync += self.x.eq(0) with m.If(self.y < self.vscan - 1): m.d.sync += self.y.eq(self.y + 1) with m.Else(): m.d.sync += self.y.eq(0) m.d.comb += [ self.active.eq((self.x < self.width) & (self.y < self.height)), self.hsync.eq((self.x >= self.hsync_start) & (self.x < self.hsync_end)), self.vsync.eq((self.y >= self.vsync_start) & (self.y < self.vsync_end)) ] return m
class PluginModuleStreamerRx(Elaboratable): def __init__(self, plugin): """ This module needs to run in the word clock domain of the bus. """ self.plugin = plugin self.output = StreamEndpoint(32, is_sink=False, has_last=False) self.ready = StatusSignal() def elaborate(self, platform): m = Module() m.domains += ClockDomain("wclk_in") m.d.comb += ClockSignal("wclk_in").eq(self.plugin.clk_word) pll = m.submodules.pll = Pll(50e6, 4, 1, "wclk_in") pll.output_domain("ddr_domain", 1) m.submodules.eclk_ddr = EClkSync("ddr_domain", "ddr_domain_eclk") m.submodules.clk_div_half = ClkDiv("ddr_domain_eclk", "ddr_domain_x1_1", "word_x2", div=2) m.submodules.clk_div_quater = ClkDiv("ddr_domain_eclk", "ddr_domain_x1_2", "sync", div=4) lanes = [] for i in range(4): lane = m.submodules["lane{}".format(i)] = LaneAligner( i=self.plugin["lvds{}".format(i)], in_testpattern_mode=~self.output.valid, ddr_domain="ddr_domain_eclk", word_x2_domain="word_x2", ) lanes.append(lane) m.d.sync += self.output.valid.eq(self.plugin.valid) m.d.sync += self.output.payload.eq( Cat(*[lane.output for lane in lanes])) m.d.comb += self.ready.eq(self.output.ready & ( reduce(lambda a, b: a & b, [lane.word_aligned & lane.bit_aligned for lane in lanes]))) return m
def __init__(self, i, in_testpattern_mode, ddr_domain, word_x2_domain, testpattern=0b00000110): """ Does bit and lane alignment of one lane usig a given testpattern if in_testpattern_mode is high """ self.i = i self.in_testpattern_mode = in_testpattern_mode self.testpattern = testpattern self.word_x2_domain = word_x2_domain self.ddr_domain = ddr_domain self.output = Signal(8) self.bit_aligned = StatusSignal() self.word_aligned = StatusSignal() self.bitslips = StatusSignal(32) self.delay = StatusSignal(5) self.error = StatusSignal()
def __init__(self, input, depth, r_domain, w_domain, buffered=True, exact_depth=False): assert input.is_sink is False self.input = input self.output = StreamEndpoint.like(input, name="stream_fifo_output") self.r_domain = r_domain self.w_domain = w_domain self.depth = depth self.exact_depth = exact_depth self.buffered = buffered self.overflow_cnt = StatusSignal(32) self.underrun_cnt = StatusSignal(32) self.r_level = StatusSignal(range(depth + 1)) self.w_level = StatusSignal(range(depth + 1))
def __init__( self, ringbuffer: RingBufferAddressStorage, max_line_width=5000, address_width=32, data_width=64, ): self.next_frame = Signal() self.line_words_total = ControlSignal(32, reset=2304 // 4) self.line_words_read = StatusSignal(32) self.ringbuffer = ringbuffer self.address_width = address_width self.data_width = data_width self.max_line_width = max_line_width self.output = StreamEndpoint(address_width, is_sink=False, has_last=False)
def __init__(self, input_freq, vco_mul, vco_div, input_domain="sync"): Pll.is_valid_vco_conf(input_freq, vco_mul, vco_div, exception=True) self.vco_freq = input_freq * vco_mul / vco_div self.locked = StatusSignal() m = self.m = Module() clkop = Signal() clkfb = Signal() m.submodules.clkbufa = Instance("CLKFBBUFA", i_A=clkop, o_Z=clkfb) self.output_port_names = ["CLKOS", "CLKOS2", "CLKOS3"] self.params = { "CLKI_DIV": vco_div, # we use OLKOP as our feedback path "CLKFB_DIV": vco_mul, "FEEDBK_PATH": "USERCLOCK", "CLKOP_DIV": 1, **{ "{}_ENABLE".format(output): "DISABLED" for output in self.output_port_names } } self.attributes = { "FREQUENCY_PIN_CLKI": str(input_freq / 1e6), "FREQUENCY_PIN_CLKOP": str(self.vco_freq / 1e6) } self.inputs = { "CLKI": ClockSignal(input_domain), "RST": ResetSignal(input_domain), "CLKFB": clkfb, } self.outputs = { "LOCK": self.locked, "CLKOP": clkop, }
class LaneAligner(Elaboratable): def __init__(self, i, in_testpattern_mode, ddr_domain, word_x2_domain, testpattern=0b00000110): """ Does bit and lane alignment of one lane usig a given testpattern if in_testpattern_mode is high """ self.i = i self.in_testpattern_mode = in_testpattern_mode self.testpattern = testpattern self.word_x2_domain = word_x2_domain self.ddr_domain = ddr_domain self.output = Signal(8) self.bit_aligned = StatusSignal() self.word_aligned = StatusSignal() self.bitslips = StatusSignal(32) self.delay = StatusSignal(5) self.error = StatusSignal() def elaborate(self, platform): m = Module() delayed = Signal() m.submodules.delayd = Instance( "DELAYD", i_A=self.i, i_DEL0=self.delay[0], i_DEL1=self.delay[1], i_DEL2=self.delay[2], i_DEL3=self.delay[3], i_DEL4=self.delay[4], o_Z=delayed, ) iserdes = m.submodules.iserdes = FakeX8ISerdes(delayed, self.ddr_domain, self.word_x2_domain) with m.If(self.in_testpattern_mode): with m.FSM(): last_captured_word = Signal(8) with m.State("INITIAL"): m.d.sync += last_captured_word.eq(self.output) m.next = "ALIGN_BIT" with m.State("ALIGN_BIT"): start_longest = Signal.like(self.delay) len_longest = Signal.like(self.delay) start_current = Signal.like(self.delay) m.d.sync += last_captured_word.eq(self.output) with m.If((self.output != last_captured_word) | (self.delay == ((2**len(self.delay)) - 1))): m.d.sync += start_current.eq(self.delay) len_current = (self.delay - start_current) with m.If(len_current > len_longest): m.d.sync += len_longest.eq(len_current) m.d.sync += start_longest.eq(start_current) with m.If(self.delay < 2**len(self.delay)): m.d.sync += self.delay.eq(self.delay + 1) with m.Else(): m.d.sync += self.delay.eq(start_longest + (len_longest >> 1)) m.d.sync += self.bit_aligned.eq(1) m.next = "ALIGN_WORD" with m.State("ALIGN_WORD"): with m.If(self.output != self.testpattern): m.d.comb += iserdes.bitslip.eq(1) m.next = "ALIGN_WORD" with m.Else(): m.d.sync += self.word_aligned.eq(1) m.next = "ALIGNED" with m.State("ALIGNED"): with m.If(self.output != self.testpattern): m.d.sync += self.error.eq(1) # TODO: retrain if this is the case after we finished basic debugging return m
class SyncStreamFifo(Elaboratable): def __init__(self, input: StreamEndpoint, depth: int, buffered=True, fwtf=False): assert input.is_sink is False self.input = input self.output = StreamEndpoint.like(input, name="stream_fifo_output") self.depth = depth self.buffered = buffered self.fwtf = fwtf self.max_w_level = StatusSignal(range(depth)) self.overflow_cnt = StatusSignal(32) self.underrun_cnt = StatusSignal(32) self.r_level = StatusSignal(range(depth + 1)) self.w_level = StatusSignal(range(depth + 1)) def elaborate(self, platform): m = Module() input_sink = StreamEndpoint.like(self.input, is_sink=True, name="stream_fifo_input") m.d.comb += input_sink.connect(self.input) if input_sink.has_last: fifo_data = Cat(input_sink.payload, input_sink.last) else: fifo_data = input_sink.payload if self.buffered: assert not self.fwtf fifo = m.submodules.fifo = SyncFIFOBuffered(width=len(fifo_data), depth=self.depth) else: fifo = m.submodules.fifo = SyncFIFO(width=len(fifo_data), depth=self.depth, fwft=self.fwtf) m.d.comb += self.r_level.eq(fifo.r_level) m.d.comb += self.w_level.eq(fifo.w_level) with m.If(self.w_level > self.max_w_level): m.d.sync += self.max_w_level.eq(self.w_level) m.d.comb += input_sink.ready.eq(fifo.w_rdy) m.d.comb += fifo.w_data.eq(fifo_data) m.d.comb += fifo.w_en.eq(input_sink.valid) with m.If(input_sink.valid & (~input_sink.ready)): m.d.sync += self.overflow_cnt.eq(self.overflow_cnt + 1) with m.If(self.output.ready & (~self.output.valid)): m.d.sync += self.underrun_cnt.eq(self.underrun_cnt + 1) if self.output.has_last: m.d.comb += Cat(self.output.payload, self.output.last).eq(fifo.r_data) else: m.d.comb += self.output.payload.eq(fifo.r_data) m.d.comb += self.output.valid.eq(fifo.r_rdy) m.d.comb += fifo.r_en.eq(self.output.ready) return m
def elaborate(self, platform: ZynqSocPlatform): m = Module() # clock_setup: the serdes clockdomain has double the frequency of fclk1 platform.ps7.fck_domain() pll = m.submodules.pll = RawPll(startup_wait=False, ref_jitter1=0.01, clkin1_period=8.0, clkfbout_mult=8, divclk_divide=1, clkout0_divide=16, clkout0_phase=0.0, clkout1_divide=4, clkout1_phase=0.0) platform.ps7.fck_domain(requested_frequency=200e6, domain_name="pll_clk_in") m.d.comb += pll.clk.in_[1].eq(ClockSignal("pll_clk_in")) m.d.comb += pll.clk.fbin.eq(pll.clk.fbout) bufg_serdes = m.submodules.bufg_serdes = Bufg(pll.clk.out[0]) m.domains += ClockDomain("serdes") m.d.comb += ClockSignal("serdes").eq(bufg_serdes.o) bufg_serdes_4x = m.submodules.bufg_serdes_4x = Bufg(pll.clk.out[1]) m.domains += ClockDomain("serdes_4x") m.d.comb += ClockSignal("serdes_4x").eq(bufg_serdes_4x.o) # make the design resettable via a axi register reset_serdes = ControlSignal() for domain in ["sync", "serdes", "serdes_4x"]: m.d.comb += ResetSignal(domain).eq(reset_serdes) # loopback loopback = platform.request("loopback") ## sender side to_oserdes = Signal(8) oserdes = m.submodules.oserdes = Oserdes(data_width=8, tristate_width=1, data_rate_oq="ddr", serdes_mode="master", data_rate_tq="buf") m.d.comb += oserdes.oce.eq(1) m.d.comb += oserdes.clk.eq(ClockSignal("serdes_4x")) m.d.comb += oserdes.clkdiv.eq(ClockSignal("serdes")) m.d.comb += oserdes.rst.eq(ResetSignal("serdes")) m.d.comb += Cat(oserdes.d[i] for i in reversed(range(1, 9))).eq( to_oserdes) # reversed is needed!!1 m.d.comb += loopback.tx.eq(oserdes.oq) ## reciver side bufg_idelay_refclk = m.submodules.bufg_idelay_refclk = Bufg( pll.clk.out[1]) m.domains += ClockDomain("idelay_refclk") m.d.comb += ClockSignal("idelay_refclk").eq(bufg_idelay_refclk.o) idelay_ctl = m.submodules.idelay_ctl = IdelayCtrl() m.d.comb += StatusSignal(name="idelay_crl_rdy").eq(idelay_ctl.rdy) m.d.comb += idelay_ctl.refclk.eq(ClockSignal("idelay_refclk")) m.d.comb += idelay_ctl.rst.eq(ResetSignal("idelay_refclk")) idelay = m.submodules.idelay = Idelay(delay_src="iDataIn", signal_pattern="data", cinvctrl_sel=False, high_performance_mode=True, refclk_frequency=200.0, pipe_sel=False, idelay_type="var_load", idelay_value=0) m.d.comb += idelay.c.eq( ClockSignal() ) # this is really the clock to which the control inputs are syncronous! m.d.comb += idelay.ld.eq(ControlSignal(name="idelay_ld")) m.d.comb += idelay.ldpipeen.eq(0) m.d.comb += idelay.ce.eq(0) m.d.comb += idelay.inc.eq(0) m.d.comb += idelay.cntvalue.in_.eq( ControlSignal(5, name="idelay_cntvaluein")) m.d.comb += StatusSignal(5, name="idelay_cntvalueout").eq( idelay.cntvalue.out) m.d.comb += idelay.idatain.eq(loopback.rx) idelay_out = Signal() m.d.comb += idelay_out.eq(idelay.data.out) iserdes = m.submodules.iserdes = Iserdes( data_width=8, data_rate="ddr", serdes_mode="master", interface_type="networking", num_ce=1, iobDelay="ifd", ) m.d.comb += iserdes.ddly.eq(idelay_out) m.d.comb += iserdes.ce[1].eq(1) m.d.comb += iserdes.clk.eq(ClockSignal("serdes_4x")) m.d.comb += iserdes.clkb.eq(~ClockSignal("serdes_4x")) m.d.comb += iserdes.rst.eq(ResetSignal("serdes")) m.d.comb += iserdes.clkdiv.eq(ClockSignal("serdes")) from_iserdes = Signal(8) m.d.comb += from_iserdes.eq(Cat(iserdes.q[i] for i in range(1, 9))) ## check logic last_received = StatusSignal(8, name="last_received") current_state = StatusSignal(32, name="current_state") training_cycles = StatusSignal(32, name="training_cycles") slipped_bits = StatusSignal(32, name="slipped_bits") error_cnt = StatusSignal(32, name="error_cnt") success_cnt = StatusSignal(32, name="success_cnt") last_current_out = StatusSignal(24, name="last_current_out") test_pattern = ControlSignal(8, name="test_patern") with m.FSM(domain="serdes"): with m.State("TRAINING"): m.d.comb += current_state.eq(0) # start the link with correcting for the bitslip training_pattern = 0b00001111 m.d.serdes += to_oserdes.eq(training_pattern) since_bitslip = Signal(2) m.d.serdes += training_cycles.eq(training_cycles + 1) with m.If(iserdes.bitslip == 1): m.d.serdes += iserdes.bitslip.eq(0) m.d.serdes += since_bitslip.eq(0) with m.Elif(since_bitslip < 3): m.d.serdes += since_bitslip.eq(since_bitslip + 1) with m.Elif(from_iserdes != training_pattern): m.d.serdes += iserdes.bitslip.eq(1) m.d.serdes += slipped_bits.eq(slipped_bits + 1) with m.Else(): m.d.serdes += to_oserdes.eq(0x00) m.next = "RUNNING" with m.State("RUNNING"): m.d.comb += current_state.eq(1) with m.If(test_pattern): m.d.serdes += to_oserdes.eq(test_pattern) with m.If(from_iserdes == test_pattern): m.d.serdes += success_cnt.eq(success_cnt + 1) with m.Else(): m.d.serdes += error_cnt.eq(error_cnt + 1) with m.Else(): m.d.serdes += to_oserdes.eq(to_oserdes + 1) with m.If(from_iserdes == (last_received + 1)[0:8]): m.d.serdes += success_cnt.eq(success_cnt + 1) with m.Else(): m.d.serdes += error_cnt.eq(error_cnt + 1) m.d.serdes += last_received.eq(from_iserdes) m.d.comb += last_current_out.eq( Cat(last_received, from_iserdes, to_oserdes)) return m
class AsyncStreamFifo(Elaboratable): def __init__(self, input, depth, r_domain, w_domain, buffered=True, exact_depth=False): assert input.is_sink is False self.input = input self.output = StreamEndpoint.like(input, name="stream_fifo_output") self.r_domain = r_domain self.w_domain = w_domain self.depth = depth self.exact_depth = exact_depth self.buffered = buffered self.overflow_cnt = StatusSignal(32) self.underrun_cnt = StatusSignal(32) self.r_level = StatusSignal(range(depth + 1)) self.w_level = StatusSignal(range(depth + 1)) def elaborate(self, platform): m = Module() input_sink = StreamEndpoint.like(self.input, is_sink=True, name="stream_fifo_input") m.d.comb += input_sink.connect(self.input) if input_sink.has_last: fifo_data = Cat(input_sink.payload, input_sink.last) else: fifo_data = input_sink.payload fifo_type = AsyncFIFOBuffered if self.buffered else AsyncFIFO fifo = m.submodules.fifo = fifo_type(width=len(fifo_data), depth=self.depth, r_domain=self.r_domain, w_domain=self.w_domain, exact_depth=self.exact_depth) m.d.comb += self.r_level.eq(fifo.r_level) m.d.comb += self.w_level.eq(fifo.w_level) m.d.comb += input_sink.ready.eq(fifo.w_rdy) m.d.comb += fifo.w_data.eq(fifo_data) m.d.comb += fifo.w_en.eq(input_sink.valid) with m.If(input_sink.valid & (~input_sink.ready)): m.d[self.w_domain] += self.overflow_cnt.eq(self.overflow_cnt + 1) with m.If(self.output.ready & (~self.output.valid)): m.d[self.r_domain] += self.underrun_cnt.eq(self.underrun_cnt + 1) if self.output.has_last: m.d.comb += Cat(self.output.payload, self.output.last).eq(fifo.r_data) else: m.d.comb += self.output.payload.eq(fifo.r_data) m.d.comb += self.output.valid.eq(fifo.r_rdy) m.d.comb += fifo.r_en.eq(self.output.ready) return m
class Pll(Elaboratable): vco_multipliers = list(range(2, 64)) vco_dividers = list(range(1, 56)) output_dividers = list(range(1, 128)) @staticmethod def is_valid_vco_conf(input_freq, mul, div, exception=False): if not mul in Pll.vco_multipliers: if exception: raise ValueError return False if not div in Pll.vco_dividers: if exception: raise ValueError return False vco_freq = input_freq * mul / div if 800e6 > vco_freq: if exception: raise ValueError(vco_freq) return False if 1600e6 < vco_freq: if exception: raise ValueError(vco_freq) return False return True def __init__(self, input_freq, vco_mul, vco_div, input_domain="sync"): Pll.is_valid_vco_conf(input_freq, vco_mul, vco_div, exception=True) self._pll = RawPll( clkin1_period=1 / input_freq * 1e9, clkfbout_mult=vco_mul, divclk_divide=vco_div, ) m = self.m = Module() m.d.comb += self._pll.clk.fbin.eq(self._pll.clk.fbout) m.d.comb += self._pll.clk.in_[1].eq(ClockSignal(input_domain)) m.d.comb += self._pll.clk.insel.eq(1) # HIGH for clkin1 self.locked = StatusSignal() self._input_domain = input_domain self._input_freq = input_freq self._vco = Clock(input_freq * vco_mul / vco_div) self._clock_constraints = {} def output_domain(self, domain_name, divisor, number=None, bufg=True): if number is None: number = next(x for x in range(6) if x not in self._clock_constraints.keys()) assert number not in self._clock_constraints.keys( ), "port {} is already taken".format(number) assert divisor in Mmcm.output_dividers self._pll.parameters["CLKOUT{}_DIVIDE".format(number)] = divisor self._pll.parameters["CLKOUT{}_PHASE".format(number)] = 0.0 m = self.m clock_signal = Signal(name="pll_out_{}".format(number), attrs={"KEEP": "TRUE"}) m.d.comb += clock_signal.eq(self._pll.clk.out[number]) if bufg: # TODO: seems to not change anything bufg = m.submodules["bufg_{}".format(number)] = Bufg(clock_signal) output = bufg.o else: output = clock_signal m.domains += ClockDomain(domain_name) m.d.comb += ClockSignal(domain_name).eq(output) m.d.comb += ResetSignal(domain_name).eq(~self.locked) frequency = self._vco.frequency / divisor self._clock_constraints[number] = (clock_signal, frequency) return Clock(frequency) def elaborate(self, platform): m = Module() m.submodules.pll_block = self._pll m.submodules.connections = self.m for i, (clock_signal, frequency) in self._clock_constraints.items(): platform.add_clock_constraint(clock_signal, frequency) m.d.comb += self.locked.eq(self._pll.locked) m.d.comb += self._pll.rst.eq(ResetSignal(self._input_domain)) if isinstance(platform, SocPlatform): m.submodules.drp_bridge = DrpBridge( DrpInterface(self._pll.dwe, self._pll.den, self._pll.daddr, self._pll.di, self._pll.do, self._pll.drdy, self._pll.dclk)) return m
class Mmcm(Elaboratable): vco_multipliers = list(decimal_range(2, 64, 0.125)) vco_dividers = list(range(1, 106)) output_0_dividers = list(decimal_range(1, 128, 0.125)) output_dividers = list(range(1, 128)) @staticmethod def is_valid_vco_conf(input_freq, mul, div, exception=False): if not mul in Mmcm.vco_multipliers: if exception: raise ValueError return False if not div in Mmcm.vco_dividers: if exception: raise ValueError return False vco_freq = input_freq * mul / div if 600e6 > vco_freq: if exception: raise ValueError return False if 1200e6 < vco_freq: if exception: raise ValueError return False return True def __init__(self, input_clock, vco_mul, vco_div, input_domain="sync"): Mmcm.is_valid_vco_conf(input_clock, vco_mul, vco_div, exception=True) self._mmcm = InstanceHelper("+/xilinx/cells_xtra.v", "MMCME2_ADV")( clkin1_period=1 / input_clock * 1e9, clkfbout_mult_f=vco_mul, divclk_divide=vco_div, ) m = self.m = Module() m.d.comb += self._mmcm.clk.fbin.eq(self._mmcm.clk.fbout) m.d.comb += self._mmcm.clk.in_[1].eq(ClockSignal(input_domain)) m.d.comb += self._mmcm.clk.ins.el.eq(1) # HIGH for clkin1 self.locked = StatusSignal() self._input_domain = input_domain self._input_clock = input_clock self._vco = Clock(input_clock * vco_mul / vco_div) self._clock_constraints = {} def output_domain(self, domain_name, divisor, number=None, bufg=True): if number is None: number = next(x for x in range(7) if x not in self._clock_constraints.keys()) assert number not in self._clock_constraints.keys( ), "port {} is already taken".format(number) assert divisor in (Mmcm.output_dividers if number != 0 else Mmcm.output_0_dividers) divide_param = "CLKOUT{}_DIVIDE{}".format(number, "_f" if number == 0 else "") self._mmcm.parameters[divide_param] = divisor self._mmcm.parameters["CLKOUT{}_PHASE".format(number)] = 0.0 m = self.m clock_signal = Signal(name="mmcm_out_{}".format(number), attrs={"KEEP": "TRUE"}) m.d.comb += clock_signal.eq(self._mmcm.clk.out[number]) if bufg: # TODO: seems to not change anything bufg = m.submodules["bufg_{}".format(number)] = Bufg(clock_signal) output = bufg.o else: output = clock_signal m.domains += ClockDomain(domain_name) m.d.comb += ClockSignal(domain_name).eq(output) m.d.comb += ResetSignal(domain_name).eq(~self.locked) frequency = self._vco.frequency / divisor self._clock_constraints[number] = (clock_signal, frequency) return Clock(frequency) def elaborate(self, platform): m = Module() m.submodules.mmcm_block = self._mmcm m.submodules.connections = self.m for i, (clock_signal, frequency) in self._clock_constraints.items(): platform.add_clock_constraint(clock_signal, frequency) m.d.comb += self.locked.eq(self._mmcm.locked) m.d.comb += self._mmcm.rst.eq(ResetSignal(self._input_domain)) if isinstance(platform, SocPlatform): m.submodules.drp_bridge = DrpBridge( DrpInterface(self._mmcm.dwe, self._mmcm.den, self._mmcm.daddr, self._mmcm.di, self._mmcm.do, self._mmcm.drdy, self._mmcm.dclk)) return m
def __init__(self): self.counter = StatusSignal(32) self.test_reg = ControlSignal(32)
def __init__(self, buffer_size, n, base_address=0x0f80_0000): super().__init__() self.buffer_size = buffer_size self.buffer_base_list = Array([base_address + buffer_size * i for i in range(n)]) self.current_write_buffer = StatusSignal(range(n))
class HispiPhy(Elaboratable): def __init__(self, num_lanes=4, bits=12): assert bits == 12 self.hispi_clk = Signal() self.hispi_lanes = Signal(num_lanes) self.bitslip = [Signal() for _ in range(num_lanes)] self.out = [Signal(12) for _ in range(num_lanes)] self.hispi_x6_in_domain_counter = StatusSignal(32) def elaborate(self, platform): m = Module() m.domains += ClockDomain("hispi_x6_in") m.d.comb += ClockSignal("hispi_x6_in").eq(self.hispi_clk) m.d.hispi_x6_in += self.hispi_x6_in_domain_counter.eq( self.hispi_x6_in_domain_counter + 1) mul = 3 pll = m.submodules.pll = Mmcm(300e6, mul, 1, input_domain="hispi_x6_in") pll.output_domain("hispi_x6", mul * 1) pll.output_domain("hispi_x3", mul * 2) pll.output_domain("hispi_x2", mul * 3) pll.output_domain("hispi", mul * 6) for i in range(0, len(self.hispi_lanes)): iserdes = m.submodules["hispi_iserdes_" + str(i)] = Iserdes( data_width=6, data_rate="ddr", serdes_mode="master", interface_type="networking", num_ce=1, iobDelay="none", ) m.d.comb += iserdes.d.eq(self.hispi_lanes[i]) m.d.comb += iserdes.ce[1].eq(1) m.d.comb += iserdes.clk.eq(ClockSignal("hispi_x6")) m.d.comb += iserdes.clkb.eq(~ClockSignal("hispi_x6")) m.d.comb += iserdes.rst.eq(ResetSignal("hispi_x6")) m.d.comb += iserdes.clkdiv.eq(ClockSignal("hispi_x2")) real_bitslip = Signal() with m.If(self.bitslip[i]): m.d.hispi += real_bitslip.eq(~real_bitslip) m.d.comb += iserdes.bitslip.eq(self.bitslip[i] & real_bitslip) iserdes_output = Cat(iserdes.q[j] for j in reversed(range(1, 7))) # iserdes_output = Cat(iserdes.q[j] for j in range(1, 7)) with m.FSM(domain="hispi_x2"): with m.State("lower"): m.d.hispi_x2 += self.out[i][0:6].eq(iserdes_output) with m.If(real_bitslip & self.bitslip[i]): m.next = "lower" with m.Else(): m.next = "upper" with m.State("upper"): m.d.hispi_x2 += self.out[i][6:12].eq(iserdes_output) with m.If(real_bitslip & self.bitslip[i]): m.next = "upper" with m.Else(): m.next = "lower" return m