From 50f0a1057c469df050398c50b40c6dc4f9e257f8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 10:57:36 +0200 Subject: [PATCH 1/9] soc/cores/hyperbus: Do some tests with sys_2x, seems working. --- litex/soc/cores/hyperbus.py | 95 ++++++++++++--------------- litex/soc/software/libbase/hyperram.c | 4 +- test/test_hyperbus.py | 37 ++++++----- 3 files changed, 65 insertions(+), 71 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 5918c910f..8277caf89 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -100,7 +100,7 @@ class HyperRAM(LiteXModule): rwds.o.eq( rwds_o), rwds.oe.eq(rwds_oe), ] - self.sync += [ + self.sync.sys_2x += [ # DQ. dq_i.eq(dq.i), @@ -116,11 +116,11 @@ class HyperRAM(LiteXModule): # 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.sys += pads.cs_n[0].eq(~cs) # Only supporting 1 CS. # Clk. pads_clk = Signal() - self.sync += pads_clk.eq(clk) + self.sync.sys_2x += pads_clk.eq(clk) if hasattr(pads, "clk"): # Single Ended Clk. self.comb += pads.clk.eq(pads_clk) @@ -134,7 +134,7 @@ class HyperRAM(LiteXModule): self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM) # Clock Generation (sys_clk/4) ------------------------------------------------------------- - self.sync += [ + self.sync.sys_2x += [ If(cs, # Increment Clk Phase on CS. clk_phase.eq(clk_phase + 1) @@ -145,11 +145,11 @@ class HyperRAM(LiteXModule): ] cases = { 0b00 : clk.eq(0), # 0° - 0b01 : clk.eq(cs), # 90° / Set Clk. + 0b01 : clk.eq(cs), # 90° 0b10 : clk.eq(cs), # 180° - 0b11 : clk.eq(0), # 270° / Clr Clk. + 0b11 : clk.eq(0), # 270° } - self.comb += Case(clk_phase, cases) + self.sync.sys_2x += Case(clk_phase, cases) # Data Shift-In Register ------------------------------------------------------------------- self.comb += [ @@ -162,7 +162,7 @@ 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°). + self.sync += sr.eq(sr_next) # Data Shift-Out Register ------------------------------------------------------------------ self.comb += bus.dat_r.eq(sr_next) @@ -250,8 +250,8 @@ class HyperRAM(LiteXModule): # Send Command on DQ. ca_oe.eq(1), dq_oe.eq(1), - # Wait for 6*2 cycles... - If(cycles == (6*2 - 1), + # Wait for 6 cycles... + If(cycles == (6 - 1), If(reg_write_req, NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), NextState("REG-WRITE-0") @@ -266,27 +266,21 @@ class HyperRAM(LiteXModule): # Send Reg on DQ. ca_oe.eq(1), dq_oe.eq(1), - # Wait for 2 cycles... - If(cycles == (2 - 1), - NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])), - NextState("REG-WRITE-1") - ) + NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])), + NextState("REG-WRITE-1") ) fsm.act("REG-WRITE-1", # Send Reg on DQ. ca_oe.eq(1), dq_oe.eq(1), - # Wait for 2 cycles... - If(cycles == (2 - 1), - reg_ep.ready.eq(1), - NextValue(self.reg_write_done, 1), - NextState("IDLE") - ) + reg_ep.ready.eq(1), + NextValue(self.reg_write_done, 1), + NextState("IDLE") ) fsm.act("WAIT-LATENCY", - # Wait for 1X or 2X Latency cycles... (-4 since count start in the middle of the command). - If(((cycles == 2*(self.conf_latency * 4) - 4 - 1) & refresh) | # 2X Latency (No DRAM refresh required). - ((cycles == 1*(self.conf_latency * 4) - 4 - 1) & ~refresh) , # 1X Latency ( DRAM refresh required). + # Wait for 1X or 2X Latency cycles... (-2 since count start in the middle of the command). + If(((cycles == 2*(self.conf_latency * 2) - 2 - 1) & refresh) | # 2X Latency (No DRAM refresh required). + ((cycles == 1*(self.conf_latency * 2) - 2 - 1) & ~refresh) , # 1X Latency ( DRAM refresh required). # Latch Bus. bus_latch.eq(1), # Early Write Ack (to allow bursting). @@ -308,34 +302,31 @@ 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). - If(cycles == (2 - 1), - # Set next default state (with rollover for bursts). - NextState(f"READ-WRITE-DATA{(n + 1)%states}"), - # On last state, see if we can continue the burst or if we should end it. - If(n == (states - 1), - NextValue(first, 0), - # Continue burst when a consecutive access is ready. - If(~reg_read_req & bus.stb & bus.cyc & (bus.we == bus_we) & (bus.adr == (bus_adr + 1)) & (~burst_timer.done), - # Latch Bus. - bus_latch.eq(1), - # Early Write Ack (to allow bursting). - bus.ack.eq(bus.we) - # Else end the burst. - ).Elif(bus_we | (~first) | burst_timer.done, - NextState("IDLE") - ) - ), - # Read Ack (when dat_r ready). - If((n == 0) & ~first, - If(reg_read_req, - reg_ep.ready.eq(1), - NextValue(self.reg_read_done, 1), - NextValue(self.reg_read_data, bus.dat_r), - NextState("IDLE"), - ).Else( - bus.ack.eq(~bus_we), - ) + # Set next default state (with rollover for bursts). + NextState(f"READ-WRITE-DATA{(n + 1)%states}"), + # On last state, see if we can continue the burst or if we should end it. + If(n == (states - 1), + NextValue(first, 0), + # Continue burst when a consecutive access is ready. + If(~reg_read_req & bus.stb & bus.cyc & (bus.we == bus_we) & (bus.adr == (bus_adr + 1)) & (~burst_timer.done), + # Latch Bus. + bus_latch.eq(1), + # Early Write Ack (to allow bursting). + bus.ack.eq(bus.we) + # Else end the burst. + ).Elif(bus_we | (~first) | burst_timer.done, + NextState("IDLE") + ) + ), + # Read Ack (when dat_r ready). + If((n == 0) & ~first, + If(reg_read_req, + reg_ep.ready.eq(1), + NextValue(self.reg_read_done, 1), + NextValue(self.reg_read_data, bus.dat_r), + NextState("IDLE"), + ).Else( + bus.ack.eq(~bus_we), ) ) ) diff --git a/litex/soc/software/libbase/hyperram.c b/litex/soc/software/libbase/hyperram.c index dc8a3e09c..30d075643 100644 --- a/litex/soc/software/libbase/hyperram.c +++ b/litex/soc/software/libbase/hyperram.c @@ -61,8 +61,8 @@ static void hyperram_configure_latency(void) { 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_latency_setting = hyperram_get_core_latency_setting(CONFIG_CLOCK_FREQUENCY/2); + chip_latency_setting = hyperram_get_chip_latency_setting(CONFIG_CLOCK_FREQUENCY/2); /* 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..ffcacf8cd 100644 --- a/test/test_hyperbus.py +++ b/test/test_hyperbus.py @@ -4,6 +4,9 @@ # Copyright (c) 2019-2022 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause +# python3 -m unittest test.test_hyperbus.TestHyperBus.test_hyperram_write_latency_5_2x +# python3 -m unittest test.test_hyperbus.TestHyperBus.test_hyperram_read_latency_5_2x + import unittest from migen import * @@ -46,17 +49,17 @@ class TestHyperBus(unittest.TestCase): 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)) + #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") - run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], {"sys": 4, "sys_2x": 2}, vcd_name="sim.vcd") def test_hyperram_write_latency_6_2x(self): def fpga_gen(dut): @@ -136,9 +139,9 @@ class TestHyperBus(unittest.TestCase): def test_hyperram_read_latency_5_2x(self): def fpga_gen(dut): dat = yield from dut.bus.read(0x1234) - self.assertEqual(dat, 0xdeadbeef) + #self.assertEqual(dat, 0xdeadbeef) dat = yield from dut.bus.read(0x1235) - self.assertEqual(dat, 0xcafefade) + #self.assertEqual(dat, 0xcafefade) def hyperram_gen(dut): clk = "___--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--_" @@ -149,16 +152,16 @@ class TestHyperBus(unittest.TestCase): rwds_oe = "__________________________________________________________________________" for i in range(len(clk)): yield dut.pads.dq.i.eq(int(dq_i[2*(i//2):2*(i//2)+2], 16)) - 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(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)) yield 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)], {"sys": 4, "sys_2x": 2}, vcd_name="sim.vcd") def test_hyperram_read_latency_6_2x(self): def fpga_gen(dut): From 22afa34a64532726bac27e5542d3e481e9ecfc96 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 11:17:55 +0200 Subject: [PATCH 2/9] soc/cores/hyperbus: WiP to make increase similarities between x1/x2 versions. --- litex/soc/cores/hyperbus.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 8277caf89..bf0cd318c 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -116,7 +116,7 @@ class HyperRAM(LiteXModule): # CSn. pads.cs_n.reset = 2**len(pads.cs_n) - 1 - self.sync.sys += pads.cs_n[0].eq(~cs) # Only supporting 1 CS. + self.sync += pads.cs_n[0].eq(~cs) # Only supporting 1 CS. # Clk. pads_clk = Signal() @@ -145,9 +145,9 @@ class HyperRAM(LiteXModule): ] cases = { 0b00 : clk.eq(0), # 0° - 0b01 : clk.eq(cs), # 90° + 0b01 : clk.eq(cs), # 90° / Set Clk. 0b10 : clk.eq(cs), # 180° - 0b11 : clk.eq(0), # 270° + 0b11 : clk.eq(0), # 270° / Clr Clk. } self.sync.sys_2x += Case(clk_phase, cases) From 43879b0f7351547aaedc878c0ba437b33e69ad2e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 11:41:13 +0200 Subject: [PATCH 3/9] soc/cores/hyperbus: Add clk_ratio support to support x1/x2. --- litex/soc/cores/hyperbus.py | 97 ++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 38 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index bf0cd318c..dd25b4563 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -44,7 +44,7 @@ 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="2:1", with_csr=True): self.pads = pads self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") @@ -70,6 +70,10 @@ class HyperRAM(LiteXModule): 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. + ] # Internal Signals. # ----------------- @@ -250,8 +254,8 @@ class HyperRAM(LiteXModule): # Send Command on DQ. ca_oe.eq(1), dq_oe.eq(1), - # Wait for 6 cycles... - If(cycles == (6 - 1), + # Wait for 6*2 cycles. + If(cycles == (6*2 - 1), If(reg_write_req, NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), NextState("REG-WRITE-0") @@ -266,21 +270,27 @@ class HyperRAM(LiteXModule): # Send Reg on DQ. ca_oe.eq(1), dq_oe.eq(1), - NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])), - NextState("REG-WRITE-1") + # Wait for 2 cycles. + If(cycles == (2 - 1), + NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])), + NextState("REG-WRITE-1") + ) ) fsm.act("REG-WRITE-1", # Send Reg on DQ. ca_oe.eq(1), dq_oe.eq(1), - reg_ep.ready.eq(1), - NextValue(self.reg_write_done, 1), - NextState("IDLE") + # Wait for 2 cycles. + If(cycles == (2 - 1), + reg_ep.ready.eq(1), + NextValue(self.reg_write_done, 1), + NextState("IDLE") + ) ) fsm.act("WAIT-LATENCY", - # Wait for 1X or 2X Latency cycles... (-2 since count start in the middle of the command). - If(((cycles == 2*(self.conf_latency * 2) - 2 - 1) & refresh) | # 2X Latency (No DRAM refresh required). - ((cycles == 1*(self.conf_latency * 2) - 2 - 1) & ~refresh) , # 1X Latency ( DRAM refresh required). + # Wait for 1X or 2X Latency cycles... (-4 since count start in the middle of the command). + If(((cycles == 2*(self.conf_latency * 4) - 4 - 1) & refresh) | # 2X Latency (No DRAM refresh required). + ((cycles == 1*(self.conf_latency * 4) - 4 - 1) & ~refresh) , # 1X Latency ( DRAM refresh required). # Latch Bus. bus_latch.eq(1), # Early Write Ack (to allow bursting). @@ -302,31 +312,34 @@ 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)], ), - # Set next default state (with rollover for bursts). - NextState(f"READ-WRITE-DATA{(n + 1)%states}"), - # On last state, see if we can continue the burst or if we should end it. - If(n == (states - 1), - NextValue(first, 0), - # Continue burst when a consecutive access is ready. - If(~reg_read_req & bus.stb & bus.cyc & (bus.we == bus_we) & (bus.adr == (bus_adr + 1)) & (~burst_timer.done), - # Latch Bus. - bus_latch.eq(1), - # Early Write Ack (to allow bursting). - bus.ack.eq(bus.we) - # Else end the burst. - ).Elif(bus_we | (~first) | burst_timer.done, - NextState("IDLE") - ) - ), - # Read Ack (when dat_r ready). - If((n == 0) & ~first, - If(reg_read_req, - reg_ep.ready.eq(1), - NextValue(self.reg_read_done, 1), - NextValue(self.reg_read_data, bus.dat_r), - NextState("IDLE"), - ).Else( - bus.ack.eq(~bus_we), + # Wait for 2 cycles. + If(cycles == (2 - 1), + # Set next default state (with rollover for bursts). + NextState(f"READ-WRITE-DATA{(n + 1)%states}"), + # On last state, see if we can continue the burst or if we should end it. + If(n == (states - 1), + NextValue(first, 0), + # Continue burst when a consecutive access is ready. + If(~reg_read_req & bus.stb & bus.cyc & (bus.we == bus_we) & (bus.adr == (bus_adr + 1)) & (~burst_timer.done), + # Latch Bus. + bus_latch.eq(1), + # Early Write Ack (to allow bursting). + bus.ack.eq(bus.we) + # Else end the burst. + ).Elif(bus_we | (~first) | burst_timer.done, + NextState("IDLE") + ) + ), + # Read Ack (when dat_r ready). + If((n == 0) & ~first, + If(reg_read_req, + reg_ep.ready.eq(1), + NextValue(self.reg_read_done, 1), + NextValue(self.reg_read_data, bus.dat_r), + NextState("IDLE"), + ).Else( + bus.ack.eq(~bus_we), + ) ) ) ) @@ -338,8 +351,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: From f6de6e755efc20c23b1183f011f3eb2368674dd3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 11:50:46 +0200 Subject: [PATCH 4/9] soc/cores/hyperbus: Add cd_io/sync_io. --- litex/soc/cores/hyperbus.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index dd25b4563..13f404769 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -74,6 +74,11 @@ class HyperRAM(LiteXModule): "4:1", # HyperRAM Clk = Sys Clk/4. "2:1", # HyperRAM Clk = Sys Clk/2. ] + self.cd_io = cd_io = { + "4:1": "sys", + "2:1": "sys_2x" + }[clk_ratio] + self.sync_io = sync_io = getattr(self.sync, cd_io) # Internal Signals. # ----------------- @@ -104,7 +109,7 @@ class HyperRAM(LiteXModule): rwds.o.eq( rwds_o), rwds.oe.eq(rwds_oe), ] - self.sync.sys_2x += [ + self.sync_io += [ # DQ. dq_i.eq(dq.i), @@ -116,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.sys_2x += 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) @@ -138,7 +143,7 @@ class HyperRAM(LiteXModule): self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM) # Clock Generation (sys_clk/4) ------------------------------------------------------------- - self.sync.sys_2x += [ + self.sync_io += [ If(cs, # Increment Clk Phase on CS. clk_phase.eq(clk_phase + 1) @@ -153,7 +158,7 @@ class HyperRAM(LiteXModule): 0b10 : clk.eq(cs), # 180° 0b11 : clk.eq(0), # 270° / Clr Clk. } - self.sync.sys_2x += Case(clk_phase, cases) + self.sync_io += Case(clk_phase, cases) # Data Shift-In Register ------------------------------------------------------------------- self.comb += [ @@ -375,7 +380,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, From d22669cf053278beff91b4630406225259fcff00 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 12:07:55 +0200 Subject: [PATCH 5/9] soc/cores/hyperbus: Handle 4:1/2:1 specific cases separately, default to 4:1 mode (as before). --- litex/soc/cores/hyperbus.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 13f404769..ea6241e6d 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -44,7 +44,7 @@ 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, clk_ratio="2:1", 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") @@ -76,7 +76,7 @@ class HyperRAM(LiteXModule): ] self.cd_io = cd_io = { "4:1": "sys", - "2:1": "sys_2x" + "2:1": "sys2x" }[clk_ratio] self.sync_io = sync_io = getattr(self.sync, cd_io) @@ -158,7 +158,10 @@ class HyperRAM(LiteXModule): 0b10 : clk.eq(cs), # 180° 0b11 : clk.eq(0), # 270° / Clr Clk. } - self.sync_io += 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 += [ @@ -171,7 +174,10 @@ class HyperRAM(LiteXModule): sr_next[dw:].eq(sr), ) ] - self.sync += sr.eq(sr_next) + 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) From 5587f5954de2a028c09fcaae6f0d5bb6e22ec1b6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 15:00:11 +0200 Subject: [PATCH 6/9] test/test_hyperbus: Add 2:1 test. --- test/test_hyperbus.py | 64 +++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/test/test_hyperbus.py b/test/test_hyperbus.py index ffcacf8cd..b2adafa50 100644 --- a/test/test_hyperbus.py +++ b/test/test_hyperbus.py @@ -4,9 +4,6 @@ # Copyright (c) 2019-2022 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause -# python3 -m unittest test.test_hyperbus.TestHyperBus.test_hyperram_write_latency_5_2x -# python3 -m unittest test.test_hyperbus.TestHyperBus.test_hyperram_read_latency_5_2x - import unittest from migen import * @@ -49,17 +46,50 @@ class TestHyperBus(unittest.TestCase): 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)) + 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") - run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], {"sys": 4, "sys_2x": 2}, 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 fpga_gen(dut): @@ -152,12 +182,12 @@ class TestHyperBus(unittest.TestCase): rwds_oe = "__________________________________________________________________________" for i in range(len(clk)): yield dut.pads.dq.i.eq(int(dq_i[2*(i//2):2*(i//2)+2], 16)) - #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(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)) yield dut = HyperRAM(HyperRamPads(), latency=5, latency_mode="fixed") From ecd9eee5a4dafa5f60578705f11fdd1d2d4fa979 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 15:35:21 +0200 Subject: [PATCH 7/9] soc/core/hyperbus: Report Clk Ratio on Status register and use it in software to configure latency. --- litex/soc/cores/hyperbus.py | 44 ++++++++++++++++----------- litex/soc/software/libbase/hyperram.c | 7 +++-- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index ea6241e6d..16dc8affe 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -48,21 +48,6 @@ class HyperRAM(LiteXModule): self.pads = pads self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - # Config/Reg Interface. - # --------------------- - self.conf_rst = Signal() - self.conf_latency = Signal(8, reset=latency) - self.stat_latency_mode = Signal(reset={"fixed": 0, "variable": 1}[latency_mode]) - self.reg_write = Signal() - self.reg_read = Signal() - self.reg_addr = Signal(2) - self.reg_write_done = Signal() - self.reg_read_done = Signal() - self.reg_write_data = Signal(16) - self.reg_read_data = Signal(16) - if with_csr: - self.add_csr(default_latency=latency) - # # # # Parameters. @@ -80,6 +65,21 @@ class HyperRAM(LiteXModule): }[clk_ratio] self.sync_io = sync_io = getattr(self.sync, cd_io) + # Config/Reg Interface. + # --------------------- + self.conf_rst = Signal() + self.conf_latency = Signal(8, reset=latency) + self.stat_latency_mode = Signal(reset={"fixed": 0, "variable": 1}[latency_mode]) + self.reg_write = Signal() + self.reg_read = Signal() + self.reg_addr = Signal(2) + self.reg_write_done = Signal() + self.reg_read_done = Signal() + self.reg_write_data = Signal(16) + self.reg_read_data = Signal(16) + if with_csr: + self.add_csr(default_latency=latency) + # Internal Signals. # ----------------- clk = Signal() @@ -411,9 +411,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 30d075643..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/2); - chip_latency_setting = hyperram_get_chip_latency_setting(CONFIG_CLOCK_FREQUENCY/2); + 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); From 37823e34b66954d401038fd7d8678e2052dfe963 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 17:10:36 +0200 Subject: [PATCH 8/9] soc/cores/hyperbus: Simplify Clk Generation. --- litex/soc/cores/hyperbus.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 16dc8affe..3725c33f8 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -142,14 +142,11 @@ class HyperRAM(LiteXModule): # Burst Timer ------------------------------------------------------------------------------ self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM) - # Clock Generation (sys_clk/4) ------------------------------------------------------------- + # 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 = { From a88cee70c808255eb690e1b99362d2d4ae415c89 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Aug 2024 17:10:44 +0200 Subject: [PATCH 9/9] test/test_hyperbus: Update. --- test/test_hyperbus.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_hyperbus.py b/test/test_hyperbus.py index b2adafa50..6f0d655ed 100644 --- a/test/test_hyperbus.py +++ b/test/test_hyperbus.py @@ -169,9 +169,9 @@ class TestHyperBus(unittest.TestCase): def test_hyperram_read_latency_5_2x(self): def fpga_gen(dut): dat = yield from dut.bus.read(0x1234) - #self.assertEqual(dat, 0xdeadbeef) + self.assertEqual(dat, 0xdeadbeef) dat = yield from dut.bus.read(0x1235) - #self.assertEqual(dat, 0xcafefade) + self.assertEqual(dat, 0xcafefade) def hyperram_gen(dut): clk = "___--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--_" @@ -191,7 +191,7 @@ class TestHyperBus(unittest.TestCase): yield dut = HyperRAM(HyperRamPads(), latency=5, latency_mode="fixed") - run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], {"sys": 4, "sys_2x": 2}, vcd_name="sim.vcd") + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") def test_hyperram_read_latency_6_2x(self): def fpga_gen(dut):