diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 5918c910f..3725c33f8 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -44,10 +44,27 @@ class HyperRAM(LiteXModule): pads (Record) : Platform pads of HyperRAM. 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.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. # --------------------- self.conf_rst = Signal() @@ -63,14 +80,6 @@ class HyperRAM(LiteXModule): if with_csr: 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. # ----------------- clk = Signal() @@ -100,7 +109,7 @@ class HyperRAM(LiteXModule): rwds.o.eq( rwds_o), rwds.oe.eq(rwds_oe), ] - self.sync += [ + self.sync_io += [ # DQ. dq_i.eq(dq.i), @@ -112,15 +121,15 @@ class HyperRAM(LiteXModule): # Rst. 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. 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. pads_clk = Signal() - self.sync += pads_clk.eq(clk) + self.sync_io += pads_clk.eq(clk) if hasattr(pads, "clk"): # Single Ended Clk. self.comb += pads.clk.eq(pads_clk) @@ -133,14 +142,11 @@ class HyperRAM(LiteXModule): # Burst Timer ------------------------------------------------------------------------------ self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM) - # Clock Generation (sys_clk/4) ------------------------------------------------------------- - self.sync += [ + # Clk Generation --------------------------------------------------------------------------- + self.sync_io += [ + clk_phase.eq(0b00), If(cs, - # Increment Clk Phase on CS. clk_phase.eq(clk_phase + 1) - ).Else( - # Else set Clk Phase to default value. - clk_phase.eq(0b00) ) ] cases = { @@ -149,7 +155,10 @@ class HyperRAM(LiteXModule): 0b10 : clk.eq(cs), # 180° 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 ------------------------------------------------------------------- self.comb += [ @@ -162,7 +171,10 @@ class HyperRAM(LiteXModule): 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 ------------------------------------------------------------------ self.comb += bus.dat_r.eq(sr_next) @@ -250,7 +262,7 @@ class HyperRAM(LiteXModule): # Send Command on DQ. ca_oe.eq(1), dq_oe.eq(1), - # Wait for 6*2 cycles... + # Wait for 6*2 cycles. If(cycles == (6*2 - 1), If(reg_write_req, NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), @@ -266,7 +278,7 @@ class HyperRAM(LiteXModule): # Send Reg on DQ. ca_oe.eq(1), dq_oe.eq(1), - # Wait for 2 cycles... + # Wait for 2 cycles. If(cycles == (2 - 1), NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])), NextState("REG-WRITE-1") @@ -276,7 +288,7 @@ class HyperRAM(LiteXModule): # Send Reg on DQ. ca_oe.eq(1), dq_oe.eq(1), - # Wait for 2 cycles... + # Wait for 2 cycles. If(cycles == (2 - 1), reg_ep.ready.eq(1), NextValue(self.reg_write_done, 1), @@ -308,7 +320,7 @@ class HyperRAM(LiteXModule): 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)], ), - # Wait for 2 cycles (since HyperRAM's Clk = sys_clk/4). + # Wait for 2 cycles. If(cycles == (2 - 1), # Set next default state (with rollover for bursts). NextState(f"READ-WRITE-DATA{(n + 1)%states}"), @@ -347,8 +359,16 @@ class HyperRAM(LiteXModule): # FSM Cycles ------------------------------------------------------------------------------- fsm.finalize() - self.sync += cycles.eq(cycles + 1) - self.sync += If(fsm.next_state != fsm.state, cycles.eq(0)) + cycles_rst = { + "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): class TristatePads: @@ -363,7 +383,7 @@ class HyperRAM(LiteXModule): o = t.o[n], oe = t.oe, i = t.i[n], - clk = ClockSignal("sys"), + clk = ClockSignal(cd_io), ) else: self.specials += Tristate(pad, @@ -388,9 +408,19 @@ class HyperRAM(LiteXModule): CSRField("latency_mode", offset=0, size=1, values=[ ("``0b0``", "Fixed 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. # -------------- diff --git a/litex/soc/software/libbase/hyperram.c b/litex/soc/software/libbase/hyperram.c index dc8a3e09c..9dccd581c 100644 --- a/litex/soc/software/libbase/hyperram.c +++ b/litex/soc/software/libbase/hyperram.c @@ -57,12 +57,15 @@ static uint16_t hyperram_get_chip_latency_setting(uint32_t clk_freq) { static void hyperram_configure_latency(void) { uint16_t config_reg_0 = 0x8f2f; + uint8_t core_clk_ratio; uint16_t core_latency_setting; uint16_t chip_latency_setting; /* Compute Latency settings */ - core_latency_setting = hyperram_get_core_latency_setting(CONFIG_CLOCK_FREQUENCY/4); - chip_latency_setting = hyperram_get_chip_latency_setting(CONFIG_CLOCK_FREQUENCY/4); + core_clk_ratio = (hyperram_status_read() >> CSR_HYPERRAM_STATUS_CLK_RATIO_OFFSET & 0xf); + 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 */ printf("HyperRAM Core Latency: %d CK (X1).\n", core_latency_setting); diff --git a/test/test_hyperbus.py b/test/test_hyperbus.py index 93c55a68f..6f0d655ed 100644 --- a/test/test_hyperbus.py +++ b/test/test_hyperbus.py @@ -58,6 +58,39 @@ class TestHyperBus(unittest.TestCase): dut = HyperRAM(HyperRamPads(), latency=5, latency_mode="fixed") 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 fpga_gen(dut): yield from dut.bus.write(0x1234, 0xdeadbeef, sel=0b1001)