Merge pull request #2046 from enjoy-digital/hyperbus_2x
HyperRAM: Add 2:1 ratio support in addition of 4:1 ratio.
This commit is contained in:
commit
6d0ae25d65
|
@ -44,10 +44,27 @@ class HyperRAM(LiteXModule):
|
||||||
pads (Record) : Platform pads of HyperRAM.
|
pads (Record) : Platform pads of HyperRAM.
|
||||||
bus (wishbone.Interface) : Wishbone Interface.
|
bus (wishbone.Interface) : Wishbone Interface.
|
||||||
"""
|
"""
|
||||||
def __init__(self, pads, latency=6, latency_mode="variable", sys_clk_freq=10e6, with_csr=True):
|
def __init__(self, pads, latency=6, latency_mode="variable", sys_clk_freq=10e6, clk_ratio="4:1", with_csr=True):
|
||||||
self.pads = pads
|
self.pads = pads
|
||||||
self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word")
|
self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word")
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
# Parameters.
|
||||||
|
# -----------
|
||||||
|
dw = len(pads.dq) if not hasattr(pads.dq, "oe") else len(pads.dq.o)
|
||||||
|
assert dw in [8, 16]
|
||||||
|
assert latency_mode in ["fixed", "variable"]
|
||||||
|
assert clk_ratio in [
|
||||||
|
"4:1", # HyperRAM Clk = Sys Clk/4.
|
||||||
|
"2:1", # HyperRAM Clk = Sys Clk/2.
|
||||||
|
]
|
||||||
|
self.cd_io = cd_io = {
|
||||||
|
"4:1": "sys",
|
||||||
|
"2:1": "sys2x"
|
||||||
|
}[clk_ratio]
|
||||||
|
self.sync_io = sync_io = getattr(self.sync, cd_io)
|
||||||
|
|
||||||
# Config/Reg Interface.
|
# Config/Reg Interface.
|
||||||
# ---------------------
|
# ---------------------
|
||||||
self.conf_rst = Signal()
|
self.conf_rst = Signal()
|
||||||
|
@ -63,14 +80,6 @@ class HyperRAM(LiteXModule):
|
||||||
if with_csr:
|
if with_csr:
|
||||||
self.add_csr(default_latency=latency)
|
self.add_csr(default_latency=latency)
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
# Parameters.
|
|
||||||
# -----------
|
|
||||||
dw = len(pads.dq) if not hasattr(pads.dq, "oe") else len(pads.dq.o)
|
|
||||||
assert dw in [8, 16]
|
|
||||||
assert latency_mode in ["fixed", "variable"]
|
|
||||||
|
|
||||||
# Internal Signals.
|
# Internal Signals.
|
||||||
# -----------------
|
# -----------------
|
||||||
clk = Signal()
|
clk = Signal()
|
||||||
|
@ -100,7 +109,7 @@ class HyperRAM(LiteXModule):
|
||||||
rwds.o.eq( rwds_o),
|
rwds.o.eq( rwds_o),
|
||||||
rwds.oe.eq(rwds_oe),
|
rwds.oe.eq(rwds_oe),
|
||||||
]
|
]
|
||||||
self.sync += [
|
self.sync_io += [
|
||||||
# DQ.
|
# DQ.
|
||||||
dq_i.eq(dq.i),
|
dq_i.eq(dq.i),
|
||||||
|
|
||||||
|
@ -112,15 +121,15 @@ class HyperRAM(LiteXModule):
|
||||||
|
|
||||||
# Rst.
|
# Rst.
|
||||||
if hasattr(pads, "rst_n"):
|
if hasattr(pads, "rst_n"):
|
||||||
self.sync += pads.rst_n.eq(1 & ~self.conf_rst)
|
self.sync_io += pads.rst_n.eq(1 & ~self.conf_rst)
|
||||||
|
|
||||||
# CSn.
|
# CSn.
|
||||||
pads.cs_n.reset = 2**len(pads.cs_n) - 1
|
pads.cs_n.reset = 2**len(pads.cs_n) - 1
|
||||||
self.sync += pads.cs_n[0].eq(~cs) # Only supporting 1 CS.
|
self.sync_io += pads.cs_n[0].eq(~cs) # Only supporting 1 CS.
|
||||||
|
|
||||||
# Clk.
|
# Clk.
|
||||||
pads_clk = Signal()
|
pads_clk = Signal()
|
||||||
self.sync += pads_clk.eq(clk)
|
self.sync_io += pads_clk.eq(clk)
|
||||||
if hasattr(pads, "clk"):
|
if hasattr(pads, "clk"):
|
||||||
# Single Ended Clk.
|
# Single Ended Clk.
|
||||||
self.comb += pads.clk.eq(pads_clk)
|
self.comb += pads.clk.eq(pads_clk)
|
||||||
|
@ -133,14 +142,11 @@ class HyperRAM(LiteXModule):
|
||||||
# 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)
|
||||||
|
|
||||||
# Clock Generation (sys_clk/4) -------------------------------------------------------------
|
# Clk Generation ---------------------------------------------------------------------------
|
||||||
self.sync += [
|
self.sync_io += [
|
||||||
|
clk_phase.eq(0b00),
|
||||||
If(cs,
|
If(cs,
|
||||||
# Increment Clk Phase on CS.
|
|
||||||
clk_phase.eq(clk_phase + 1)
|
clk_phase.eq(clk_phase + 1)
|
||||||
).Else(
|
|
||||||
# Else set Clk Phase to default value.
|
|
||||||
clk_phase.eq(0b00)
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
cases = {
|
cases = {
|
||||||
|
@ -149,7 +155,10 @@ class HyperRAM(LiteXModule):
|
||||||
0b10 : clk.eq(cs), # 180°
|
0b10 : clk.eq(cs), # 180°
|
||||||
0b11 : clk.eq(0), # 270° / Clr Clk.
|
0b11 : clk.eq(0), # 270° / Clr Clk.
|
||||||
}
|
}
|
||||||
self.comb += Case(clk_phase, cases)
|
if clk_ratio in ["4:1"]:
|
||||||
|
self.comb += Case(clk_phase, cases)
|
||||||
|
if clk_ratio in ["2:1"]:
|
||||||
|
self.sync_io += Case(clk_phase, cases)
|
||||||
|
|
||||||
# Data Shift-In Register -------------------------------------------------------------------
|
# Data Shift-In Register -------------------------------------------------------------------
|
||||||
self.comb += [
|
self.comb += [
|
||||||
|
@ -162,7 +171,10 @@ class HyperRAM(LiteXModule):
|
||||||
sr_next[dw:].eq(sr),
|
sr_next[dw:].eq(sr),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
self.sync += If(clk_phase[0] == 0, sr.eq(sr_next)) # Shift on 0°/180° (and sampled on 90°/270°).
|
if clk_ratio in ["4:1"]:
|
||||||
|
self.sync += If(clk_phase[0] == 0, sr.eq(sr_next))
|
||||||
|
if clk_ratio in ["2:1"]:
|
||||||
|
self.sync += sr.eq(sr_next)
|
||||||
|
|
||||||
# Data Shift-Out Register ------------------------------------------------------------------
|
# Data Shift-Out Register ------------------------------------------------------------------
|
||||||
self.comb += bus.dat_r.eq(sr_next)
|
self.comb += bus.dat_r.eq(sr_next)
|
||||||
|
@ -250,7 +262,7 @@ class HyperRAM(LiteXModule):
|
||||||
# Send Command on DQ.
|
# Send Command on DQ.
|
||||||
ca_oe.eq(1),
|
ca_oe.eq(1),
|
||||||
dq_oe.eq(1),
|
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,
|
||||||
NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])),
|
NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])),
|
||||||
|
@ -266,7 +278,7 @@ class HyperRAM(LiteXModule):
|
||||||
# Send Reg on DQ.
|
# Send Reg on DQ.
|
||||||
ca_oe.eq(1),
|
ca_oe.eq(1),
|
||||||
dq_oe.eq(1),
|
dq_oe.eq(1),
|
||||||
# Wait for 2 cycles...
|
# Wait for 2 cycles.
|
||||||
If(cycles == (2 - 1),
|
If(cycles == (2 - 1),
|
||||||
NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])),
|
NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])),
|
||||||
NextState("REG-WRITE-1")
|
NextState("REG-WRITE-1")
|
||||||
|
@ -276,7 +288,7 @@ class HyperRAM(LiteXModule):
|
||||||
# Send Reg on DQ.
|
# Send Reg on DQ.
|
||||||
ca_oe.eq(1),
|
ca_oe.eq(1),
|
||||||
dq_oe.eq(1),
|
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),
|
||||||
NextValue(self.reg_write_done, 1),
|
NextValue(self.reg_write_done, 1),
|
||||||
|
@ -308,7 +320,7 @@ class HyperRAM(LiteXModule):
|
||||||
rwds_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)],
|
*[rwds_o[dw//8-1-i].eq(~bus_sel[4-1-n*dw//8-i]) for i in range(dw//8)],
|
||||||
),
|
),
|
||||||
# Wait for 2 cycles (since HyperRAM's Clk = sys_clk/4).
|
# Wait for 2 cycles.
|
||||||
If(cycles == (2 - 1),
|
If(cycles == (2 - 1),
|
||||||
# Set next default state (with rollover for bursts).
|
# Set next default state (with rollover for bursts).
|
||||||
NextState(f"READ-WRITE-DATA{(n + 1)%states}"),
|
NextState(f"READ-WRITE-DATA{(n + 1)%states}"),
|
||||||
|
@ -347,8 +359,16 @@ class HyperRAM(LiteXModule):
|
||||||
|
|
||||||
# FSM Cycles -------------------------------------------------------------------------------
|
# FSM Cycles -------------------------------------------------------------------------------
|
||||||
fsm.finalize()
|
fsm.finalize()
|
||||||
self.sync += cycles.eq(cycles + 1)
|
cycles_rst = {
|
||||||
self.sync += If(fsm.next_state != fsm.state, cycles.eq(0))
|
"4:1" : 0,
|
||||||
|
"2:1" : 1,
|
||||||
|
}[clk_ratio]
|
||||||
|
cycles_inc = {
|
||||||
|
"4:1" : 1,
|
||||||
|
"2:1" : 2,
|
||||||
|
}[clk_ratio]
|
||||||
|
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):
|
def add_tristate(self, pad, register=False):
|
||||||
class TristatePads:
|
class TristatePads:
|
||||||
|
@ -363,7 +383,7 @@ class HyperRAM(LiteXModule):
|
||||||
o = t.o[n],
|
o = t.o[n],
|
||||||
oe = t.oe,
|
oe = t.oe,
|
||||||
i = t.i[n],
|
i = t.i[n],
|
||||||
clk = ClockSignal("sys"),
|
clk = ClockSignal(cd_io),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.specials += Tristate(pad,
|
self.specials += Tristate(pad,
|
||||||
|
@ -388,9 +408,19 @@ class HyperRAM(LiteXModule):
|
||||||
CSRField("latency_mode", offset=0, size=1, values=[
|
CSRField("latency_mode", offset=0, size=1, values=[
|
||||||
("``0b0``", "Fixed Latency."),
|
("``0b0``", "Fixed Latency."),
|
||||||
("``0b1``", "Variable Latency."),
|
("``0b1``", "Variable Latency."),
|
||||||
])
|
]),
|
||||||
|
CSRField("clk_ratio", offset=1, size=4, values=[
|
||||||
|
("``4``", "HyperRAM Clk = Sys Clk/4."),
|
||||||
|
("``2``", "HyperRAM Clk = Sys Clk/2."),
|
||||||
|
]),
|
||||||
])
|
])
|
||||||
self.comb += self.status.fields.latency_mode.eq(self.stat_latency_mode)
|
self.comb += [
|
||||||
|
self.status.fields.latency_mode.eq(self.stat_latency_mode),
|
||||||
|
self.status.fields.clk_ratio.eq({
|
||||||
|
"sys" : 4,
|
||||||
|
"sys2x": 2,
|
||||||
|
}[self.cd_io]),
|
||||||
|
]
|
||||||
|
|
||||||
# Reg Interface.
|
# Reg Interface.
|
||||||
# --------------
|
# --------------
|
||||||
|
|
|
@ -57,12 +57,15 @@ static uint16_t hyperram_get_chip_latency_setting(uint32_t clk_freq) {
|
||||||
|
|
||||||
static void hyperram_configure_latency(void) {
|
static void hyperram_configure_latency(void) {
|
||||||
uint16_t config_reg_0 = 0x8f2f;
|
uint16_t config_reg_0 = 0x8f2f;
|
||||||
|
uint8_t core_clk_ratio;
|
||||||
uint16_t core_latency_setting;
|
uint16_t core_latency_setting;
|
||||||
uint16_t chip_latency_setting;
|
uint16_t chip_latency_setting;
|
||||||
|
|
||||||
/* Compute Latency settings */
|
/* Compute Latency settings */
|
||||||
core_latency_setting = hyperram_get_core_latency_setting(CONFIG_CLOCK_FREQUENCY/4);
|
core_clk_ratio = (hyperram_status_read() >> CSR_HYPERRAM_STATUS_CLK_RATIO_OFFSET & 0xf);
|
||||||
chip_latency_setting = hyperram_get_chip_latency_setting(CONFIG_CLOCK_FREQUENCY/4);
|
printf("HyperRAM Clk Ratio %d:1.\n", core_clk_ratio);
|
||||||
|
core_latency_setting = hyperram_get_core_latency_setting(CONFIG_CLOCK_FREQUENCY/core_clk_ratio);
|
||||||
|
chip_latency_setting = hyperram_get_chip_latency_setting(CONFIG_CLOCK_FREQUENCY/core_clk_ratio);
|
||||||
|
|
||||||
/* Write Latency to HyperRAM Core */
|
/* Write Latency to HyperRAM Core */
|
||||||
printf("HyperRAM Core Latency: %d CK (X1).\n", core_latency_setting);
|
printf("HyperRAM Core Latency: %d CK (X1).\n", core_latency_setting);
|
||||||
|
|
|
@ -58,6 +58,39 @@ class TestHyperBus(unittest.TestCase):
|
||||||
dut = HyperRAM(HyperRamPads(), latency=5, latency_mode="fixed")
|
dut = HyperRAM(HyperRamPads(), latency=5, latency_mode="fixed")
|
||||||
run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd")
|
run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd")
|
||||||
|
|
||||||
|
def test_hyperram_write_latency_5_2x_sys2x(self):
|
||||||
|
def fpga_gen(dut):
|
||||||
|
yield from dut.bus.write(0x1234, 0xdeadbeef, sel=0b1001)
|
||||||
|
yield
|
||||||
|
|
||||||
|
def hyperram_gen(dut):
|
||||||
|
clk = "____--__--__--__--__--__--__--__--__--__--__--__--__--__--_______"
|
||||||
|
cs_n = "--________________________________________________________-------"
|
||||||
|
dq_oe = "___------------____________________________________--------______"
|
||||||
|
dq_o = "0002000048d0000000000000000000000000000000000000000deadbeef000000"
|
||||||
|
rwds_oe = "___________________________________________________--------______"
|
||||||
|
rwds_o = "_____________________________________________________----________"
|
||||||
|
for i in range(len(clk)):
|
||||||
|
self.assertEqual(c2bool(clk[i]), (yield dut.pads.clk))
|
||||||
|
self.assertEqual(c2bool(cs_n[i]), (yield dut.pads.cs_n))
|
||||||
|
self.assertEqual(c2bool(dq_oe[i]), (yield dut.pads.dq.oe))
|
||||||
|
#if (yield dut.pads.dq.oe):
|
||||||
|
# self.assertEqual(int(dq_o[2*(i//2):2*(i//2)+2], 16), (yield dut.pads.dq.o))
|
||||||
|
self.assertEqual(c2bool(rwds_oe[i]), (yield dut.pads.rwds.oe))
|
||||||
|
self.assertEqual(c2bool(rwds_o[i]), (yield dut.pads.rwds.o))
|
||||||
|
yield
|
||||||
|
|
||||||
|
dut = HyperRAM(HyperRamPads(), latency=5, latency_mode="fixed", clk_ratio="2:1")
|
||||||
|
generators = {
|
||||||
|
"sys" : fpga_gen(dut),
|
||||||
|
"sys2x" : hyperram_gen(dut),
|
||||||
|
}
|
||||||
|
clocks = {
|
||||||
|
"sys" : 4,
|
||||||
|
"sys2x" : 2,
|
||||||
|
}
|
||||||
|
run_simulation(dut, generators, clocks, vcd_name="sim.vcd")
|
||||||
|
|
||||||
def test_hyperram_write_latency_6_2x(self):
|
def test_hyperram_write_latency_6_2x(self):
|
||||||
def fpga_gen(dut):
|
def fpga_gen(dut):
|
||||||
yield from dut.bus.write(0x1234, 0xdeadbeef, sel=0b1001)
|
yield from dut.bus.write(0x1234, 0xdeadbeef, sel=0b1001)
|
||||||
|
|
Loading…
Reference in New Issue