From 4f0efc2b25a5a40c74048c6fbb489d6e3a201dd9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 22 Aug 2024 15:16:33 +0200 Subject: [PATCH] soc/cores/hyperbus: Add HyperRAMPHY and move related logic to it. --- litex/soc/cores/hyperbus.py | 202 +++++++++++++++++++----------------- 1 file changed, 107 insertions(+), 95 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 0fb6dd7dc..db662334e 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -9,8 +9,6 @@ from migen import * from migen.fhdl.specials import Tristate -from litex.build.io import SDRTristate - from litex.gen import * from litex.gen.genlib.misc import WaitTimer @@ -21,6 +19,80 @@ from litex.build.io import DifferentialOutput from litex.soc.interconnect import wishbone +# HyperRAMPHY -------------------------------------------------------------------------------------- + +class HyperRAMPHY(LiteXModule): + def __init__(self, pads, data_width, clk_domain="sys"): + self.rst = Signal() # i. + self.cs = Signal() # i. + self.clk = Signal() # i. + self.dq_o = Signal(data_width) # i. + self.dq_oe = Signal() # i. + self.dq_i = Signal(data_width) # o. + self.rwds_o = Signal(data_width//8) # i. + self.rwds_oe = Signal() # i. + self.rwds_i = Signal(data_width//8) # o. + + # # # + + _sync = getattr(self.sync, clk_domain) + + # Rst. + # ---- + if hasattr(pads, "rst_n"): + _sync += pads.rst_n.eq(~self.rst) + + # CS_n. + # ----- + pads.cs_n.reset = 2**len(pads.cs_n) - 1 + _sync += pads.cs_n[0].eq(~self.cs) # Only supporting one Chip. + + # Clk. + # ---- + clk = Signal() + _sync += clk.eq(self.clk) + + # Single Ended Clk. + if hasattr(pads, "clk"): + self.comb += pads.clk.eq(clk) + # Differential Clk. + elif hasattr(pads, "clk_p"): + self.specials += DifferentialOutput(clk, pads.clk_p, pads.clk_n) + else: + raise ValueError + + # DQ. + # --- + dq = pads.dq + if not hasattr(dq, "oe"): + dq = self.add_tristate(dq) + self.comb += dq.o.eq( self.dq_o) + self.comb += dq.oe.eq(self.dq_oe) + _sync += self.dq_i.eq(dq.i) # FIXME: Use phase-shifted Clk? + + # RWDS. + # ----- + rwds = pads.rwds + if not hasattr(rwds, "oe"): + rwds = self.add_tristate(pads.rwds) + self.comb += rwds.o.eq( self.rwds_o) + self.comb += rwds.oe.eq( self.rwds_oe) + _sync += self.rwds_i.eq(rwds.i) # FIXME: Use phase-shifted Clk? + + def add_tristate(self, pad): + class TristatePads: + def __init__(self, width=1): + self.o = Signal(width) + self.oe = Signal() + self.i = Signal(width) + t = TristatePads(width=len(pad)) + self.specials += Tristate(pad, + o = t.o, + oe = t.oe, + i = t.i, + ) + return t + # HyperRAM ----------------------------------------------------------------------------------------- class HyperRAM(LiteXModule): @@ -52,8 +124,8 @@ class HyperRAM(LiteXModule): # Parameters. # ----------- - dw = len(pads.dq) if not hasattr(pads.dq, "oe") else len(pads.dq.o) - assert dw in [8, 16] + data_width = len(pads.dq) if not hasattr(pads.dq, "oe") else len(pads.dq.o) + assert data_width in [8, 16] assert latency_mode in ["fixed", "variable"] assert clk_ratio in [ "4:1", # HyperRAM Clk = Sys Clk/4. @@ -82,64 +154,27 @@ class HyperRAM(LiteXModule): # Internal Signals. # ----------------- - clk = Signal() - clk_phase = Signal(2) - cs = Signal() - ca = Signal(48) - ca_oe = Signal() - sr_load = Signal() + clk = Signal() + clk_phase = Signal(2) + cs = Signal() + ca = Signal(48) + ca_oe = Signal() + sr_load = Signal() sr_load_value = Signal(48) - sr = Signal(48) - sr_next = Signal(48) - dq_o = Signal(dw) - dq_oe = Signal() - dq_i = Signal(dw) - rwds_o = Signal(dw//8) - rwds_oe = Signal() - rwds_i = Signal(dw//8) + sr = Signal(48) + sr_next = Signal(48) - # Tristates. - # ---------- - dq = self.add_tristate(pads.dq, register=False) if not hasattr(pads.dq, "oe") else pads.dq - rwds = self.add_tristate(pads.rwds, register=False) if not hasattr(pads.rwds, "oe") else pads.rwds - self.comb += [ # FIXME: Try to move to sync to allow switching to SDRTristate. - # DQ. - dq.o.eq( dq_o), - dq.oe.eq(dq_oe), - - # RWDS. - rwds.o.eq( rwds_o), - rwds.oe.eq(rwds_oe), - ] - self.sync_io += [ - # DQ. - dq_i.eq(dq.i), - - # RWDS. - rwds_i.eq(rwds.i) - ] + # PHY. + # ---- + self.phy = phy = HyperRAMPHY(pads=pads, data_width=data_width, clk_domain=cd_io) # Drive Control Signals -------------------------------------------------------------------- - # Rst. - if hasattr(pads, "rst_n"): - self.sync_io += pads.rst_n.eq(1 & ~self.conf_rst) - - # CSn. - pads.cs_n.reset = 2**len(pads.cs_n) - 1 - self.sync_io += pads.cs_n[0].eq(~cs) # Only supporting 1 CS. - - # Clk. - pads_clk = Signal() - self.sync_io += pads_clk.eq(clk) - if hasattr(pads, "clk"): - # Single Ended Clk. - self.comb += pads.clk.eq(pads_clk) - elif hasattr(pads, "clk_p"): - # Differential Clk. - self.specials += DifferentialOutput(pads_clk, pads.clk_p, pads.clk_n) - else: - raise ValueError + self.comb += [ + phy.rst.eq(self.conf_rst), + phy.cs.eq(cs), + phy.clk.eq(clk), + ] # Burst Timer ------------------------------------------------------------------------------ self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM) @@ -167,10 +202,10 @@ class HyperRAM(LiteXModule): # Command/Address: On 8-bit, so 8-bit shift and no input. If(ca_oe, sr_next[8:].eq(sr), - # Data: On dw-bit, so dw-bit shift. + # Data: On data_width-bit, so data_width-bit shift. ).Else( - sr_next[:dw].eq(dq_i), - sr_next[dw:].eq(sr), + sr_next[:data_width].eq(phy.dq_i), + sr_next[data_width:].eq(sr), ) ] if clk_ratio in ["4:1"]: @@ -186,10 +221,10 @@ class HyperRAM(LiteXModule): self.comb += [ # Command/Address: 8-bit. If(ca_oe, - dq_o.eq(sr[-8:]) - # Data: dw-bit. + phy.dq_o.eq(sr[-8:]) + # Data: data_width-bit. ).Else( - dq_o.eq(sr[-dw:]) + phy.dq_o.eq(sr[-data_width:]) ) ] @@ -216,7 +251,7 @@ class HyperRAM(LiteXModule): ) # Command generation ----------------------------------------------------------------------- - ashift = {8:1, 16:0}[dw] + ashift = {8:1, 16:0}[data_width] self.comb += [ # Register Command Generation. If(reg_write_req | reg_read_req, @@ -270,7 +305,7 @@ class HyperRAM(LiteXModule): fsm.act("SEND-COMMAND-ADDRESS", # Send Command on DQ. ca_oe.eq(1), - dq_oe.eq(1), + phy.dq_oe.eq(1), # Wait for 6*2 cycles. If(cycles == (6*2 - 1), If(reg_write_req, @@ -279,7 +314,7 @@ class HyperRAM(LiteXModule): NextState("REG-WRITE-0") ).Else( # Sample RWDS to know if 1X/2X Latency should be used (Refresh). - NextValue(refresh, rwds_i | (latency_mode in ["fixed"])), + NextValue(refresh, phy.rwds_i | (latency_mode in ["fixed"])), NextState("WAIT-LATENCY") ) ) @@ -287,7 +322,7 @@ class HyperRAM(LiteXModule): fsm.act("REG-WRITE-0", # Send Reg on DQ. ca_oe.eq(1), - dq_oe.eq(1), + phy.dq_oe.eq(1), # Wait for 2 cycles. If(cycles == (2 - 1), sr_load.eq(1), @@ -298,7 +333,7 @@ class HyperRAM(LiteXModule): fsm.act("REG-WRITE-1", # Send Reg on DQ. ca_oe.eq(1), - dq_oe.eq(1), + phy.dq_oe.eq(1), # Wait for 2 cycles. If(cycles == (2 - 1), reg_ep.ready.eq(1), @@ -319,7 +354,7 @@ class HyperRAM(LiteXModule): NextState("READ-WRITE-DATA0") ) ) - states = {8:4, 16:2}[dw] + states = {8:4, 16:2}[data_width] for n in range(states): fsm.act(f"READ-WRITE-DATA{n}", # Enable Burst Timer. @@ -327,9 +362,9 @@ class HyperRAM(LiteXModule): ca_oe.eq(reg_read_req), # Send Data on DQ/RWDS (for write). If(bus_we, - dq_oe.eq(1), - rwds_oe.eq(1), - *[rwds_o[dw//8-1-i].eq(~bus_sel[4-1-n*dw//8-i]) for i in range(dw//8)], + phy.dq_oe.eq(1), + phy.rwds_oe.eq(1), + *[phy.rwds_o[data_width//8-1-i].eq(~bus_sel[4-1-n*data_width//8-i]) for i in range(data_width//8)], ), # Wait for 2 cycles. If(cycles == (2 - 1), @@ -381,29 +416,6 @@ class HyperRAM(LiteXModule): self.sync += cycles.eq(cycles + cycles_inc) self.sync += If(fsm.next_state != fsm.state, cycles.eq(cycles_rst)) - def add_tristate(self, pad, register=False): - class TristatePads: - def __init__(self, width): - self.o = Signal(len(pad)) - self.oe = Signal() - self.i = Signal(len(pad)) - t = TristatePads(len(pad)) - if register: - for n in range(len(pad)): - self.specials += SDRTristate(pad[n], - o = t.o[n], - oe = t.oe, - i = t.i[n], - clk = ClockSignal(cd_io), - ) - else: - self.specials += Tristate(pad, - o = t.o, - oe = t.oe, - i = t.i, - ) - return t - def add_csr(self, default_latency=6): # Config/Status Interface. # ------------------------