From 3f609ae8dd54efcaa76f48c27dff335b31d67f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Thu, 24 Oct 2024 15:24:01 +0200 Subject: [PATCH 1/2] phy: sdr: improve phy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit improve sdr phy Signed-off-by: Fin Maaß --- litespi/phy/generic_sdr.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/litespi/phy/generic_sdr.py b/litespi/phy/generic_sdr.py index f6706ca..166018c 100644 --- a/litespi/phy/generic_sdr.py +++ b/litespi/phy/generic_sdr.py @@ -96,11 +96,10 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay) cs_enable = Signal() self.comb += cs_timer.wait.eq(self.cs) self.comb += cs_enable.eq(cs_timer.done) - self.comb += pads.cs_n.eq(~cs_enable) - - # I/Os. - data_bits = 32 - cmd_bits = 8 + self.specials += SDROutput( + i = ~cs_enable, + o = pads.cs_n + ) if hasattr(pads, "mosi"): dq_o = Signal() @@ -115,9 +114,9 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay) o = dq_i[1] ) else: - dq_o = Signal(len(pads.dq)) - dq_i = Signal(len(pads.dq)) - dq_oe = Signal(len(pads.dq)) + dq_o = Signal().like(pads.dq) + dq_i = Signal().like(pads.dq) + dq_oe = Signal().like(pads.dq) for i in range(len(pads.dq)): self.specials += SDRTristate( io = pads.dq[i], @@ -130,13 +129,12 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay) sr_cnt = Signal(8, reset_less=True) sr_out_load = Signal() sr_out_shift = Signal() - sr_out = Signal(len(sink.data), reset_less=True) + sr_out = Signal().like(sink.data) sr_in_shift = Signal() - sr_in = Signal(len(sink.data), reset_less=True) + sr_in = Signal().like(sink.data) # Data Out Generation/Load/Shift. self.comb += [ - dq_oe.eq(sink.mask), Case(sink.width, { 1 : dq_o.eq(sr_out[-1:]), 2 : dq_o.eq(sr_out[-2:]), @@ -145,15 +143,11 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay) }) ] self.sync += If(sr_out_load, - sr_out.eq(sink.data << (len(sink.data) - sink.len)) + sr_out.eq(sink.data << (len(sink.data) - sink.len)), + sr_in.eq(0), ) self.sync += If(sr_out_shift, - Case(sink.width, { - 1 : sr_out.eq(Cat(Signal(1), sr_out)), - 2 : sr_out.eq(Cat(Signal(2), sr_out)), - 4 : sr_out.eq(Cat(Signal(4), sr_out)), - 8 : sr_out.eq(Cat(Signal(8), sr_out)), - }) + sr_out.eq(sr_out << sink.width), ) # Data In Shift. @@ -173,6 +167,7 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay) If(cs_enable & sink.valid, # Load Shift Register Count/Data Out. NextValue(sr_cnt, sink.len - sink.width), + NextValue(dq_oe, sink.mask), sr_out_load.eq(1), # Start XFER. NextState("XFER"), @@ -214,6 +209,7 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay) # Send Data In to Core and return to WAIT when accepted. source.valid.eq(1), source.last.eq(1), + NextValue(dq_oe, 0), If(source.ready, NextState("WAIT-CMD-DATA"), ) From 66cb9cc146806a893be6e32e1582ca143877511f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Thu, 24 Oct 2024 17:55:43 +0200 Subject: [PATCH 2/2] support multiple cs_n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit support multiple cs_n Signed-off-by: Fin Maaß --- litespi/__init__.py | 15 ++++++++++----- litespi/core/mmap.py | 7 +++++-- litespi/crossbar.py | 6 +++--- litespi/phy/generic_ddr.py | 12 ++++++++---- litespi/phy/generic_sdr.py | 11 ++++++----- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/litespi/__init__.py b/litespi/__init__.py index 27797fd..63fda54 100644 --- a/litespi/__init__.py +++ b/litespi/__init__.py @@ -71,17 +71,21 @@ class LiteSPI(LiteXModule): def __init__(self, phy, clock_domain="sys", with_mmap=True, mmap_endianness="big", with_master=True, master_tx_fifo_depth=1, master_rx_fifo_depth=1, - with_csr=True, with_mmap_write=False): + with_csr=True, with_mmap_write=False, mmap_cs_mask=1): - self.crossbar = crossbar = LiteSPICrossbar(clock_domain) + cs_width=len(phy.cs) + + self.crossbar = crossbar = LiteSPICrossbar(clock_domain, cs_width) self.comb += phy.cs.eq(crossbar.cs) if with_mmap: self.mmap = mmap = LiteSPIMMAP(flash=phy.flash, endianness=mmap_endianness, with_csr=with_csr, - with_write=with_mmap_write) - port_mmap = crossbar.get_port(mmap.cs) + with_write=with_mmap_write, + cs_width=cs_width, + cs_mask=mmap_cs_mask) + port_mmap = crossbar.get_port(mmap.cs, mmap.request) self.bus = mmap.bus self.comb += [ port_mmap.source.connect(mmap.sink), @@ -92,7 +96,8 @@ def __init__(self, phy, clock_domain="sys", if with_master: self.master = master = LiteSPIMaster( tx_fifo_depth = master_tx_fifo_depth, - rx_fifo_depth = master_rx_fifo_depth) + rx_fifo_depth = master_rx_fifo_depth, + cs_width = cs_width) port_master = crossbar.get_port(master.cs) self.comb += [ port_master.source.connect(master.sink), diff --git a/litespi/core/mmap.py b/litespi/core/mmap.py index eccd6e3..1b2ec48 100644 --- a/litespi/core/mmap.py +++ b/litespi/core/mmap.py @@ -75,11 +75,12 @@ class LiteSPIMMAP(LiteXModule): write_config : CSRStorage Optional register holding configuration bits for the write mode. """ - def __init__(self, flash, clock_domain="sys", endianness="big", with_csr=True, with_write=False): + def __init__(self, flash, clock_domain="sys", endianness="big", with_csr=True, with_write=False, cs_width=1, cs_mask=1): self.source = source = stream.Endpoint(spi_core2phy_layout) self.sink = sink = stream.Endpoint(spi_phy2core_layout) self.bus = bus = wishbone.Interface() - self.cs = cs = Signal() + self.cs = Signal(cs_width) + self.request = cs = Signal() self.offset = offset = Signal(len(bus.adr)) # Burst Control. @@ -123,6 +124,8 @@ def __init__(self, flash, clock_domain="sys", endianness="big", with_csr=True, w self.byte_count = byte_count = Signal(2, reset_less=True) self.data_write = Signal(32) + self.comb += If(self.request, self.cs.eq(cs_mask)) + # FSM. self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", diff --git a/litespi/crossbar.py b/litespi/crossbar.py index 206297a..679fa0e 100644 --- a/litespi/crossbar.py +++ b/litespi/crossbar.py @@ -27,7 +27,7 @@ def __init__(self): class LiteSPICrossbar(Module): - def __init__(self, cd): + def __init__(self, cd, cs_width=1): self.cd = cd self.users = [] self.master = LiteSPIMasterPort() @@ -41,7 +41,7 @@ def __init__(self, cd): self.master.source.connect(self.tx_cdc.sink), ] - self.cs = Signal() + self.cs = Signal(cs_width) self.user_cs = [] self.user_request = [] @@ -59,7 +59,7 @@ def get_port(self, cs, request = None): if request is None: request = Signal() - self.comb += request.eq(cs) + self.comb += request.eq(cs != 0) self.users.append(internal_port) self.user_cs.append(self.cs.eq(cs)) diff --git a/litespi/phy/generic_ddr.py b/litespi/phy/generic_ddr.py index b440161..7d4dfd0 100644 --- a/litespi/phy/generic_ddr.py +++ b/litespi/phy/generic_ddr.py @@ -15,7 +15,7 @@ from litex.soc.interconnect import stream -from litex.build.io import DDRTristate +from litex.build.io import DDRTristate, SDROutput # LiteSPI DDR PHY Core ----------------------------------------------------------------------------- @@ -54,7 +54,7 @@ class LiteSPIDDRPHYCore(LiteXModule): def __init__(self, pads, flash, cs_delay, extra_latency=0): self.source = source = stream.Endpoint(spi_phy2core_layout) self.sink = sink = stream.Endpoint(spi_core2phy_layout) - self.cs = Signal() + self.cs = Signal().like(pads.cs_n) if hasattr(pads, "miso"): bus_width = 1 @@ -75,9 +75,13 @@ def __init__(self, pads, flash, cs_delay, extra_latency=0): # CS control. self.cs_timer = cs_timer = WaitTimer(cs_delay + 1) # Ensure cs_delay cycles between XFers. cs_enable = Signal() - self.comb += cs_timer.wait.eq(self.cs) + self.comb += cs_timer.wait.eq(self.cs != 0) self.comb += cs_enable.eq(cs_timer.done) - self.comb += pads.cs_n.eq(~cs_enable) + for i in range(len(pads.cs_n)): + self.specials += SDROutput( + i = ~(cs_enable & self.cs[i]), + o = pads.cs_n[i] + ) # I/Os. data_bits = 32 diff --git a/litespi/phy/generic_sdr.py b/litespi/phy/generic_sdr.py index 166018c..de1a0a6 100644 --- a/litespi/phy/generic_sdr.py +++ b/litespi/phy/generic_sdr.py @@ -63,7 +63,7 @@ class LiteSPISDRPHYCore(LiteXModule): def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay): self.source = source = stream.Endpoint(spi_phy2core_layout) self.sink = sink = stream.Endpoint(spi_core2phy_layout) - self.cs = Signal() + self.cs = Signal().like(pads.cs_n) self._spi_clk_divisor = spi_clk_divisor = Signal(8) self._default_divisor = default_divisor @@ -94,11 +94,12 @@ def __init__(self, pads, flash, device, clock_domain, default_divisor, cs_delay) # CS control. self.cs_timer = cs_timer = WaitTimer(cs_delay + 1) # Ensure cs_delay cycles between XFers. cs_enable = Signal() - self.comb += cs_timer.wait.eq(self.cs) + self.comb += cs_timer.wait.eq(self.cs != 0) self.comb += cs_enable.eq(cs_timer.done) - self.specials += SDROutput( - i = ~cs_enable, - o = pads.cs_n + for i in range(len(pads.cs_n)): + self.specials += SDROutput( + i = ~(cs_enable & self.cs[i]), + o = pads.cs_n[i] ) if hasattr(pads, "mosi"):