soc/cores/hyperbus: Add HyperRAMPHY and move related logic to it.

This commit is contained in:
Florent Kermarrec 2024-08-22 15:16:33 +02:00
parent f54ecfa5ff
commit 4f0efc2b25
1 changed files with 107 additions and 95 deletions

View File

@ -9,8 +9,6 @@
from migen import * from migen import *
from migen.fhdl.specials import Tristate from migen.fhdl.specials import Tristate
from litex.build.io import SDRTristate
from litex.gen import * from litex.gen import *
from litex.gen.genlib.misc import WaitTimer from litex.gen.genlib.misc import WaitTimer
@ -21,6 +19,80 @@ from litex.build.io import DifferentialOutput
from litex.soc.interconnect import wishbone 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 ----------------------------------------------------------------------------------------- # HyperRAM -----------------------------------------------------------------------------------------
class HyperRAM(LiteXModule): class HyperRAM(LiteXModule):
@ -52,8 +124,8 @@ class HyperRAM(LiteXModule):
# Parameters. # Parameters.
# ----------- # -----------
dw = len(pads.dq) if not hasattr(pads.dq, "oe") else len(pads.dq.o) data_width = len(pads.dq) if not hasattr(pads.dq, "oe") else len(pads.dq.o)
assert dw in [8, 16] assert data_width in [8, 16]
assert latency_mode in ["fixed", "variable"] assert latency_mode in ["fixed", "variable"]
assert clk_ratio in [ assert clk_ratio in [
"4:1", # HyperRAM Clk = Sys Clk/4. "4:1", # HyperRAM Clk = Sys Clk/4.
@ -82,64 +154,27 @@ class HyperRAM(LiteXModule):
# Internal Signals. # Internal Signals.
# ----------------- # -----------------
clk = Signal() clk = Signal()
clk_phase = Signal(2) clk_phase = Signal(2)
cs = Signal() cs = Signal()
ca = Signal(48) ca = Signal(48)
ca_oe = Signal() ca_oe = Signal()
sr_load = Signal() sr_load = Signal()
sr_load_value = Signal(48) sr_load_value = Signal(48)
sr = Signal(48) sr = Signal(48)
sr_next = 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)
# Tristates. # PHY.
# ---------- # ----
dq = self.add_tristate(pads.dq, register=False) if not hasattr(pads.dq, "oe") else pads.dq self.phy = phy = HyperRAMPHY(pads=pads, data_width=data_width, clk_domain=cd_io)
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)
]
# Drive Control Signals -------------------------------------------------------------------- # Drive Control Signals --------------------------------------------------------------------
# Rst. self.comb += [
if hasattr(pads, "rst_n"): phy.rst.eq(self.conf_rst),
self.sync_io += pads.rst_n.eq(1 & ~self.conf_rst) phy.cs.eq(cs),
phy.clk.eq(clk),
# 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
# Burst Timer ------------------------------------------------------------------------------ # Burst Timer ------------------------------------------------------------------------------
self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM) 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. # Command/Address: On 8-bit, so 8-bit shift and no input.
If(ca_oe, If(ca_oe,
sr_next[8:].eq(sr), sr_next[8:].eq(sr),
# Data: On dw-bit, so dw-bit shift. # Data: On data_width-bit, so data_width-bit shift.
).Else( ).Else(
sr_next[:dw].eq(dq_i), sr_next[:data_width].eq(phy.dq_i),
sr_next[dw:].eq(sr), sr_next[data_width:].eq(sr),
) )
] ]
if clk_ratio in ["4:1"]: if clk_ratio in ["4:1"]:
@ -186,10 +221,10 @@ class HyperRAM(LiteXModule):
self.comb += [ self.comb += [
# Command/Address: 8-bit. # Command/Address: 8-bit.
If(ca_oe, If(ca_oe,
dq_o.eq(sr[-8:]) phy.dq_o.eq(sr[-8:])
# Data: dw-bit. # Data: data_width-bit.
).Else( ).Else(
dq_o.eq(sr[-dw:]) phy.dq_o.eq(sr[-data_width:])
) )
] ]
@ -216,7 +251,7 @@ class HyperRAM(LiteXModule):
) )
# Command generation ----------------------------------------------------------------------- # Command generation -----------------------------------------------------------------------
ashift = {8:1, 16:0}[dw] ashift = {8:1, 16:0}[data_width]
self.comb += [ self.comb += [
# Register Command Generation. # Register Command Generation.
If(reg_write_req | reg_read_req, If(reg_write_req | reg_read_req,
@ -270,7 +305,7 @@ class HyperRAM(LiteXModule):
fsm.act("SEND-COMMAND-ADDRESS", fsm.act("SEND-COMMAND-ADDRESS",
# Send Command on DQ. # Send Command on DQ.
ca_oe.eq(1), ca_oe.eq(1),
dq_oe.eq(1), phy.dq_oe.eq(1),
# Wait for 6*2 cycles. # Wait for 6*2 cycles.
If(cycles == (6*2 - 1), If(cycles == (6*2 - 1),
If(reg_write_req, If(reg_write_req,
@ -279,7 +314,7 @@ class HyperRAM(LiteXModule):
NextState("REG-WRITE-0") NextState("REG-WRITE-0")
).Else( ).Else(
# Sample RWDS to know if 1X/2X Latency should be used (Refresh). # 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") NextState("WAIT-LATENCY")
) )
) )
@ -287,7 +322,7 @@ class HyperRAM(LiteXModule):
fsm.act("REG-WRITE-0", fsm.act("REG-WRITE-0",
# Send Reg on DQ. # Send Reg on DQ.
ca_oe.eq(1), ca_oe.eq(1),
dq_oe.eq(1), phy.dq_oe.eq(1),
# Wait for 2 cycles. # Wait for 2 cycles.
If(cycles == (2 - 1), If(cycles == (2 - 1),
sr_load.eq(1), sr_load.eq(1),
@ -298,7 +333,7 @@ class HyperRAM(LiteXModule):
fsm.act("REG-WRITE-1", fsm.act("REG-WRITE-1",
# Send Reg on DQ. # Send Reg on DQ.
ca_oe.eq(1), ca_oe.eq(1),
dq_oe.eq(1), phy.dq_oe.eq(1),
# Wait for 2 cycles. # Wait for 2 cycles.
If(cycles == (2 - 1), If(cycles == (2 - 1),
reg_ep.ready.eq(1), reg_ep.ready.eq(1),
@ -319,7 +354,7 @@ class HyperRAM(LiteXModule):
NextState("READ-WRITE-DATA0") NextState("READ-WRITE-DATA0")
) )
) )
states = {8:4, 16:2}[dw] states = {8:4, 16:2}[data_width]
for n in range(states): for n in range(states):
fsm.act(f"READ-WRITE-DATA{n}", fsm.act(f"READ-WRITE-DATA{n}",
# Enable Burst Timer. # Enable Burst Timer.
@ -327,9 +362,9 @@ class HyperRAM(LiteXModule):
ca_oe.eq(reg_read_req), ca_oe.eq(reg_read_req),
# Send Data on DQ/RWDS (for write). # Send Data on DQ/RWDS (for write).
If(bus_we, If(bus_we,
dq_oe.eq(1), phy.dq_oe.eq(1),
rwds_oe.eq(1), phy.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.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. # Wait for 2 cycles.
If(cycles == (2 - 1), If(cycles == (2 - 1),
@ -381,29 +416,6 @@ class HyperRAM(LiteXModule):
self.sync += cycles.eq(cycles + cycles_inc) self.sync += cycles.eq(cycles + cycles_inc)
self.sync += If(fsm.next_state != fsm.state, cycles.eq(cycles_rst)) 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): def add_csr(self, default_latency=6):
# Config/Status Interface. # Config/Status Interface.
# ------------------------ # ------------------------