soc/cores/hyperbus: Add HyperRAMPHY and move related logic to it.
This commit is contained in:
parent
f54ecfa5ff
commit
4f0efc2b25
|
@ -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.
|
||||||
# ------------------------
|
# ------------------------
|
||||||
|
|
Loading…
Reference in New Issue