From 2384d6fbd41912273060d3c41a7630b26e6e801b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 11 Apr 2024 17:51:47 +0200 Subject: [PATCH 01/18] cores/hyperbus: Add initial HyperRAM Register access over CSRs. Will be used to get HyperRAM characteristics and also to configure latency and enable varialble latency. Untested yet. --- litex/soc/cores/hyperbus.py | 126 ++++++++++++++++++++++++++++++++---- 1 file changed, 114 insertions(+), 12 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index da8c03d2b..e1cd421b6 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -1,7 +1,7 @@ # -# This file is part of LiteHyperBus +# This file is part of LiteX. # -# Copyright (c) 2019-2022 Florent Kermarrec +# Copyright (c) 2019-2024 Florent Kermarrec # Copyright (c) 2019 Antti Lukats # Copyright (c) 2021 Franck Jullien # SPDX-License-Identifier: BSD-2-Clause @@ -11,6 +11,9 @@ from migen import * from litex.gen import * from litex.gen.genlib.misc import WaitTimer +from litex.soc.interconnect.csr import * +from litex.soc.interconnect import stream + from litex.build.io import DifferentialOutput from litex.soc.interconnect import wishbone @@ -31,6 +34,24 @@ class HyperRAM(LiteXModule): self.pads = pads self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + # Register Access CSRs. + self.reg_control = CSRStorage(fields=[ + CSRField("write", offset=0, size=1, pulse=True, description="Issue Register Write."), + CSRField("read", offset=1, size=1, pulse=True, description="Issue Register Read."), + CSRField("reg", offset=8, size=4, values=[ + ("``0``", "Identification Register 0 (Read Only)."), + ("``1``", "Identification Register 1 (Read Only)."), + ("``2``", "Configuration Register 0."), + ("``3``", "Configuration Register 1."), + ]), + ]) + self.reg_status = CSRStatus(fields=[ + CSRField("write_done", offset=0, size=1, description="Register Write Done."), + CSRField("read_done", offset=1, size=1, description="Register Read Done."), + ]) + self.reg_wdata = CSRStorage(16, description="Register Write Data.") + self.reg_rdata = CSRStatus( 16, description="Register Read Data.") + # # # clk = Signal() @@ -98,13 +119,55 @@ class HyperRAM(LiteXModule): ) ] + # Register Access/Buffer ------------------------------------------------------------------- + + reg_write_req = Signal() + reg_write_done = Signal() + reg_read_req = Signal() + reg_read_done = Signal() + + self.reg_buffer = reg_buffer = stream.SyncFIFO( + layout = [("write", 1), ("read", 1), ("reg", 4), ("data", 16)], + depth = 4, + ) + self.comb += [ + reg_buffer.sink.valid.eq(self.reg_control.fields.write | self.reg_control.fields.read), + reg_buffer.sink.write.eq(self.reg_control.fields.write), + reg_buffer.sink.read.eq(self.reg_control.fields.read), + reg_buffer.sink.reg.eq(self.reg_control.fields.reg), + reg_buffer.sink.data.eq(self.reg_wdata.storage), + reg_write_req.eq(reg_buffer.source.valid & reg_buffer.source.write), + reg_read_req.eq( reg_buffer.source.valid & reg_buffer.source.read), + ] + self.sync += If(reg_buffer.sink.valid, + reg_write_done.eq(0), + reg_read_done.eq(0), + ) + self.comb += [ + self.reg_status.fields.write_done.eq(reg_write_done), + self.reg_status.fields.read_done.eq(reg_read_done), + ] + # Command generation ----------------------------------------------------------------------- ashift = {8:1, 16:0}[dw] self.comb += [ - ca[47].eq(~bus.we), # R/W# - ca[45].eq(1), # Burst Type (Linear) - ca[16:45].eq(bus.adr[3-ashift:]), # Row & Upper Column Address - ca[ashift:3].eq(bus.adr), # Lower Column Address + If(reg_write_req | reg_read_req, + ca[47].eq(reg_buffer.source.read), # R/W# + ca[46].eq(1), # Register Space. + ca[45].eq(1), # Burst Type (Linear) + Case(reg_buffer.source.reg, { + 0 : ca[0:40].eq(0x00_00_00_00_00), # Identification Register 0 (Read Only). + 1 : ca[0:40].eq(0x00_00_00_00_01), # Identification Register 1 (Read Only). + 2 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 0. + 3 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 1. + }), + ).Else( + ca[47].eq(~bus.we), # R/W# + ca[46].eq(0), # Memory Space. + ca[45].eq(1), # Burst Type (Linear) + ca[16:45].eq(bus.adr[3-ashift:]), # Row & Upper Column Address + ca[ashift:3].eq(bus.adr), # Lower Column Address + ) ] # Latency count starts from the middle of the command (thus the -4). In fixed latency mode @@ -131,8 +194,8 @@ class HyperRAM(LiteXModule): self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(first, 1), - If(bus.cyc & bus.stb, - If(clk_phase == 0, + If(clk_phase == 0, + If((bus.cyc & bus.stb) | reg_write_req | reg_read_req, NextValue(sr, ca), NextState("SEND-COMMAND-ADDRESS") ) @@ -146,7 +209,37 @@ class HyperRAM(LiteXModule): dq.oe.eq(1), # Wait for 6*2 cycles... If(cycles == (6*2 - 1), - NextState("WAIT-LATENCY") + If(reg_write_req, + NextValue(sr, Cat(Signal(40), self.reg_wdata.storage[:8])), + NextState("REG-WRITE-0") + ).Else( + NextState("WAIT-LATENCY") + ) + ) + ) + fsm.act("REG-WRITE-0", + # Set CSn. + cs.eq(1), + # Send Reg on DQ. + ca_active.eq(1), + dq.oe.eq(1), + # Wait for 2 cycles... + If(cycles == (2 - 1), + NextValue(sr, Cat(Signal(40), self.reg_wdata.storage[8:])), + NextState("REG-WRITE-1") + ) + ) + fsm.act("REG-WRITE-1", + # Set CSn. + cs.eq(1), + # Send Reg on DQ. + ca_active.eq(1), + dq.oe.eq(1), + # Wait for 2 cycles... + If(cycles == (2 - 1), + reg_buffer.source.ready.eq(1), + NextValue(reg_write_done, 1), + NextState("IDLE") ) ) fsm.act("WAIT-LATENCY", @@ -157,7 +250,9 @@ class HyperRAM(LiteXModule): # Latch Bus. bus_latch.eq(1), # Early Write Ack (to allow bursting). - bus.ack.eq(bus.we), + If(~reg_read_req, + bus.ack.eq(bus.we), + ), NextState("READ-WRITE-DATA0") ) ) @@ -182,7 +277,7 @@ class HyperRAM(LiteXModule): If(n == (states - 1), NextValue(first, 0), # Continue burst when a consecutive access is ready. - If(bus.stb & bus.cyc & (bus.we == bus_we) & (bus.adr == (bus_adr + 1)) & (~burst_timer.done), + 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). @@ -194,7 +289,14 @@ class HyperRAM(LiteXModule): ), # Read Ack (when dat_r ready). If((n == 0) & ~first, - bus.ack.eq(~bus_we), + If(reg_read_req, + reg_buffer.source.valid.eq(1), + NextValue(reg_read_done, 1), + NextValue(self.reg_rdata.status, bus.dat_r), + NextState("IDLE"), + ).Else( + bus.ack.eq(~bus_we), + ) ) ) ) From 59756b43429423427d03edb5eb24a6f3ea8f72b3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 11 Apr 2024 18:29:48 +0200 Subject: [PATCH 02/18] cores/hyperbus: Test and fix HyperRAM register read accesses. Seems OK: Identification Register 0 : 00000e76 Identification Register 1 : 00000009 Configuration Register 0 : 00008f2f Configuration Register 1 : 0000ffc1 reg_control: 302 reg_status: 2 reg_debug: 8 --- litex/soc/cores/hyperbus.py | 14 +++++++++++-- litex/soc/software/bios/main.c | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index e1cd421b6..1a456c000 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -52,6 +52,8 @@ class HyperRAM(LiteXModule): self.reg_wdata = CSRStorage(16, description="Register Write Data.") self.reg_rdata = CSRStatus( 16, description="Register Read Data.") + self.reg_debug = CSRStatus(32) + # # # clk = Signal() @@ -148,6 +150,13 @@ class HyperRAM(LiteXModule): self.reg_status.fields.read_done.eq(reg_read_done), ] + self.comb += [ + self.reg_debug.status[0].eq(reg_write_req), + self.reg_debug.status[1].eq(reg_write_done), + self.reg_debug.status[2].eq(reg_read_req), + self.reg_debug.status[3].eq(reg_read_done), + ] + # Command generation ----------------------------------------------------------------------- ashift = {8:1, 16:0}[dw] self.comb += [ @@ -159,7 +168,7 @@ class HyperRAM(LiteXModule): 0 : ca[0:40].eq(0x00_00_00_00_00), # Identification Register 0 (Read Only). 1 : ca[0:40].eq(0x00_00_00_00_01), # Identification Register 1 (Read Only). 2 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 0. - 3 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 1. + 3 : ca[0:40].eq(0x00_01_00_00_01), # Configuration Register 1. }), ).Else( ca[47].eq(~bus.we), # R/W# @@ -263,6 +272,7 @@ class HyperRAM(LiteXModule): burst_timer.wait.eq(1), # Set CSn. cs.eq(1), + ca_active.eq(reg_read_req), # Send Data on DQ/RWDS (for write). If(bus_we, dq.oe.eq(1), @@ -290,7 +300,7 @@ class HyperRAM(LiteXModule): # Read Ack (when dat_r ready). If((n == 0) & ~first, If(reg_read_req, - reg_buffer.source.valid.eq(1), + reg_buffer.source.ready.eq(1), NextValue(reg_read_done, 1), NextValue(self.reg_rdata.status, bus.dat_r), NextState("IDLE"), diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 67ca3d590..0f5931ae3 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -175,6 +175,44 @@ __attribute__((__used__)) int main(int i, char **c) sdr_ok = 1; + /* HyperRAM Register access test */ + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 0 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + printf("Identification Register 0 : %08lx\n", hyperram_reg_rdata_read()); + + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + printf("Identification Register 1 : %08lx\n", hyperram_reg_rdata_read()); + + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 2 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + printf("Configuration Register 0 : %08lx\n", hyperram_reg_rdata_read()); + + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 3 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + printf("Configuration Register 1 : %08lx\n", hyperram_reg_rdata_read()); + + printf("reg_control: %x\n", hyperram_reg_control_read()); + printf("reg_status: %x\n", hyperram_reg_status_read()); + printf("reg_debug: %x\n", hyperram_reg_debug_read()); + + #if defined(CSR_ETHMAC_BASE) || defined(MAIN_RAM_BASE) || defined(CSR_SPIFLASH_CORE_BASE) printf("--========== \e[1mInitialization\e[0m ============--\n"); #ifdef CSR_ETHMAC_BASE From 441d05ee36337069fdc0892f09f3dd5bf7d5f4b6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 11 Apr 2024 18:39:48 +0200 Subject: [PATCH 03/18] core/hyperbus: Start testing Register writes. --- litex/soc/software/bios/main.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 0f5931ae3..0293f6acd 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -175,6 +175,8 @@ __attribute__((__used__)) int main(int i, char **c) sdr_ok = 1; + uint16_t config_reg_0; + /* HyperRAM Register access test */ hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | @@ -199,6 +201,7 @@ __attribute__((__used__)) int main(int i, char **c) ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); printf("Configuration Register 0 : %08lx\n", hyperram_reg_rdata_read()); + config_reg_0 = hyperram_reg_rdata_read(); hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | @@ -208,10 +211,36 @@ __attribute__((__used__)) int main(int i, char **c) while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); printf("Configuration Register 1 : %08lx\n", hyperram_reg_rdata_read()); + config_reg_0 &= ~(1 << 3); /* Enable Variable Latency */ + printf("New config_reg_0: %08lx\n", config_reg_0); + hyperram_reg_wdata_write(config_reg_0); + hyperram_reg_control_write( + 1 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 0 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 2 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0); + printf("reg_control: %x\n", hyperram_reg_control_read()); printf("reg_status: %x\n", hyperram_reg_status_read()); printf("reg_debug: %x\n", hyperram_reg_debug_read()); + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 2 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + printf("Configuration Register 0 after update : %08lx\n", hyperram_reg_rdata_read()); + + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 3 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + printf("Configuration Register 1 : %08lx\n", hyperram_reg_rdata_read()); + #if defined(CSR_ETHMAC_BASE) || defined(MAIN_RAM_BASE) || defined(CSR_SPIFLASH_CORE_BASE) printf("--========== \e[1mInitialization\e[0m ============--\n"); From a32db7abadee8e8eaf2135c0fabecbab77a7c5e8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 12 Apr 2024 15:21:32 +0200 Subject: [PATCH 04/18] cores/hyperbus: Add with_csr parameter to make Register interface optional. --- litex/soc/cores/hyperbus.py | 85 ++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 1a456c000..ff24c56bf 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -30,27 +30,19 @@ class HyperRAM(LiteXModule): This core favors portability and ease of use over performance. """ - def __init__(self, pads, latency=6, sys_clk_freq=None): + def __init__(self, pads, latency=6, sys_clk_freq=None, with_csr=True): self.pads = pads self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - # Register Access CSRs. - self.reg_control = CSRStorage(fields=[ - CSRField("write", offset=0, size=1, pulse=True, description="Issue Register Write."), - CSRField("read", offset=1, size=1, pulse=True, description="Issue Register Read."), - CSRField("reg", offset=8, size=4, values=[ - ("``0``", "Identification Register 0 (Read Only)."), - ("``1``", "Identification Register 1 (Read Only)."), - ("``2``", "Configuration Register 0."), - ("``3``", "Configuration Register 1."), - ]), - ]) - self.reg_status = CSRStatus(fields=[ - CSRField("write_done", offset=0, size=1, description="Register Write Done."), - CSRField("read_done", offset=1, size=1, description="Register Read Done."), - ]) - self.reg_wdata = CSRStorage(16, description="Register Write Data.") - self.reg_rdata = CSRStatus( 16, description="Register Read Data.") + # Reg Interface. + # -------------- + 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) self.reg_debug = CSRStatus(32) @@ -129,15 +121,15 @@ class HyperRAM(LiteXModule): reg_read_done = Signal() self.reg_buffer = reg_buffer = stream.SyncFIFO( - layout = [("write", 1), ("read", 1), ("reg", 4), ("data", 16)], + layout = [("write", 1), ("read", 1), ("addr", 4), ("data", 16)], depth = 4, ) self.comb += [ - reg_buffer.sink.valid.eq(self.reg_control.fields.write | self.reg_control.fields.read), - reg_buffer.sink.write.eq(self.reg_control.fields.write), - reg_buffer.sink.read.eq(self.reg_control.fields.read), - reg_buffer.sink.reg.eq(self.reg_control.fields.reg), - reg_buffer.sink.data.eq(self.reg_wdata.storage), + reg_buffer.sink.valid.eq(self.reg_write | self.reg_read), + reg_buffer.sink.write.eq(self.reg_write), + reg_buffer.sink.read.eq(self.reg_read), + reg_buffer.sink.addr.eq(self.reg_addr), + reg_buffer.sink.data.eq(self.reg_write_data), reg_write_req.eq(reg_buffer.source.valid & reg_buffer.source.write), reg_read_req.eq( reg_buffer.source.valid & reg_buffer.source.read), ] @@ -146,8 +138,8 @@ class HyperRAM(LiteXModule): reg_read_done.eq(0), ) self.comb += [ - self.reg_status.fields.write_done.eq(reg_write_done), - self.reg_status.fields.read_done.eq(reg_read_done), + self.reg_write_done.eq(reg_write_done), + self.reg_read_done.eq(reg_read_done), ] self.comb += [ @@ -164,7 +156,7 @@ class HyperRAM(LiteXModule): ca[47].eq(reg_buffer.source.read), # R/W# ca[46].eq(1), # Register Space. ca[45].eq(1), # Burst Type (Linear) - Case(reg_buffer.source.reg, { + Case(reg_buffer.source.addr, { 0 : ca[0:40].eq(0x00_00_00_00_00), # Identification Register 0 (Read Only). 1 : ca[0:40].eq(0x00_00_00_00_01), # Identification Register 1 (Read Only). 2 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 0. @@ -219,7 +211,7 @@ class HyperRAM(LiteXModule): # Wait for 6*2 cycles... If(cycles == (6*2 - 1), If(reg_write_req, - NextValue(sr, Cat(Signal(40), self.reg_wdata.storage[:8])), + NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])), NextState("REG-WRITE-0") ).Else( NextState("WAIT-LATENCY") @@ -234,7 +226,7 @@ class HyperRAM(LiteXModule): dq.oe.eq(1), # Wait for 2 cycles... If(cycles == (2 - 1), - NextValue(sr, Cat(Signal(40), self.reg_wdata.storage[8:])), + NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), NextState("REG-WRITE-1") ) ) @@ -302,7 +294,7 @@ class HyperRAM(LiteXModule): If(reg_read_req, reg_buffer.source.ready.eq(1), NextValue(reg_read_done, 1), - NextValue(self.reg_rdata.status, bus.dat_r), + NextValue(self.reg_read_data, bus.dat_r), NextState("IDLE"), ).Else( bus.ack.eq(~bus_we), @@ -318,3 +310,36 @@ class HyperRAM(LiteXModule): t = TSTriple(len(pad)) self.specials += t.get_tristate(pad) return t + + def add_csr(self): + self.reg_control = CSRStorage(fields=[ + CSRField("write", offset=0, size=1, pulse=True, description="Issue Register Write."), + CSRField("read", offset=1, size=1, pulse=True, description="Issue Register Read."), + CSRField("reg", offset=8, size=4, values=[ + ("``0``", "Identification Register 0 (Read Only)."), + ("``1``", "Identification Register 1 (Read Only)."), + ("``2``", "Configuration Register 0."), + ("``3``", "Configuration Register 1."), + ]), + ]) + self.reg_status = CSRStatus(fields=[ + CSRField("write_done", offset=0, size=1, description="Register Write Done."), + CSRField("read_done", offset=1, size=1, description="Register Read Done."), + ]) + self.reg_wdata = CSRStorage(16, description="Register Write Data.") + self.reg_rdata = CSRStatus( 16, description="Register Read Data.") + + self.comb += [ + # Control. + self.reg_write.eq(self.reg_control.fields.write), + self.reg_read.eq( self.reg_control.fields.read), + self.reg_addr.eq( self.reg_control.fields.addr), + + # Status. + self.reg_status.fields.write_done.eq(self.reg_write_done), + self.reg_status.fields.read_done.eq( self.reg_read_done), + + # Data. + self.reg_write_data.eq(self.reg_wdata.storage), + self.reg_rdata.status.eq(self.reg_read_data), + ] From fb519ac260045304d4ae59ea918eb00fb039ae1b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 12 Apr 2024 15:21:57 +0200 Subject: [PATCH 05/18] test/test_hyperbus: Add test_hyperram_reg_write. --- test/test_hyperbus.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/test_hyperbus.py b/test/test_hyperbus.py index 8d3a59c9a..88822a4b2 100644 --- a/test/test_hyperbus.py +++ b/test/test_hyperbus.py @@ -86,3 +86,36 @@ class TestHyperBus(unittest.TestCase): dut = HyperRAM(HyperRamPads()) run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") + + + def test_hyperram_reg_write(self): + def fpga_gen(dut): + yield dut.reg_addr.eq(2) + yield dut.reg_write_data.eq(0x1234) + yield + yield dut.reg_write.eq(1) + yield + yield dut.reg_write.eq(0) + for i in range(128): + yield + + def hyperram_gen(dut): + clk = "___--__--__--__--___________" + cs_n = "--________________----------" + dq_oe = "__----------------__________" + dq_o = "0060000100000034120000000000" + rwds_oe = "____________________________" + rwds_o = "____________________________" + for i in range(3): + yield + 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)) + 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(), with_csr=False) + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") \ No newline at end of file From b1921038228b4e5104d5ff46aed64720e277ce11 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 12 Apr 2024 16:06:26 +0200 Subject: [PATCH 06/18] cores/hyperbus: Fix bytes order on register writes. --- litex/soc/cores/hyperbus.py | 9 ++++++--- test/test_hyperbus.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index ff24c56bf..528deade2 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -44,6 +44,9 @@ class HyperRAM(LiteXModule): self.reg_write_data = Signal(16) self.reg_read_data = Signal(16) + if with_csr: + self.add_csr() + self.reg_debug = CSRStatus(32) # # # @@ -211,7 +214,7 @@ class HyperRAM(LiteXModule): # Wait for 6*2 cycles... If(cycles == (6*2 - 1), If(reg_write_req, - NextValue(sr, Cat(Signal(40), self.reg_write_data[:8])), + NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), NextState("REG-WRITE-0") ).Else( NextState("WAIT-LATENCY") @@ -226,7 +229,7 @@ class HyperRAM(LiteXModule): dq.oe.eq(1), # Wait for 2 cycles... 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") ) ) @@ -315,7 +318,7 @@ class HyperRAM(LiteXModule): self.reg_control = CSRStorage(fields=[ CSRField("write", offset=0, size=1, pulse=True, description="Issue Register Write."), CSRField("read", offset=1, size=1, pulse=True, description="Issue Register Read."), - CSRField("reg", offset=8, size=4, values=[ + CSRField("addr", offset=8, size=4, values=[ ("``0``", "Identification Register 0 (Read Only)."), ("``1``", "Identification Register 1 (Read Only)."), ("``2``", "Configuration Register 0."), diff --git a/test/test_hyperbus.py b/test/test_hyperbus.py index 88822a4b2..922b4fc9e 100644 --- a/test/test_hyperbus.py +++ b/test/test_hyperbus.py @@ -103,7 +103,7 @@ class TestHyperBus(unittest.TestCase): clk = "___--__--__--__--___________" cs_n = "--________________----------" dq_oe = "__----------------__________" - dq_o = "0060000100000034120000000000" + dq_o = "0060000100000012340000000000" rwds_oe = "____________________________" rwds_o = "____________________________" for i in range(3): From f8c59c03e3b8a48aff17d56e38d10e3cc0dee526 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 12 Apr 2024 18:50:19 +0200 Subject: [PATCH 07/18] cores/hyperbus: Add variable latency support (working on ti60 f225). --- litex/soc/cores/hyperbus.py | 21 +++++++++++++++++---- litex/soc/software/bios/main.c | 24 ++++++------------------ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 528deade2..45286fc6a 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -176,7 +176,8 @@ class HyperRAM(LiteXModule): # Latency count starts from the middle of the command (thus the -4). In fixed latency mode # (default), latency is 2 x Latency count. We have 4 x sys_clk per RAM clock: - latency_cycles = (latency * 2 * 4) - 4 + latency_cycles_0 = latency * 4 + latency_cycles_1 = latency * 4 - 4 # Bus Latch -------------------------------------------------------------------------------- bus_adr = Signal(32) @@ -217,7 +218,11 @@ class HyperRAM(LiteXModule): NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), NextState("REG-WRITE-0") ).Else( - NextState("WAIT-LATENCY") + If(rwds.i, + NextState("WAIT-LATENCY-0") + ).Else( + NextState("WAIT-LATENCY-1") + ) ) ) ) @@ -246,11 +251,19 @@ class HyperRAM(LiteXModule): NextState("IDLE") ) ) - fsm.act("WAIT-LATENCY", + fsm.act("WAIT-LATENCY-0", # Set CSn. cs.eq(1), # Wait for Latency cycles... - If(cycles == (latency_cycles - 1), + If(cycles == (latency_cycles_0 - 1), + NextState("WAIT-LATENCY-1") + ) + ) + fsm.act("WAIT-LATENCY-1", + # Set CSn. + cs.eq(1), + # Wait for Latency cycles... + If(cycles == (latency_cycles_1 - 1), # Latch Bus. bus_latch.eq(1), # Early Write Ack (to allow bursting). diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 0293f6acd..f0db259bd 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -181,7 +181,7 @@ __attribute__((__used__)) int main(int i, char **c) hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 0 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + 0 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); printf("Identification Register 0 : %08lx\n", hyperram_reg_rdata_read()); @@ -189,7 +189,7 @@ __attribute__((__used__)) int main(int i, char **c) hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + 1 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); printf("Identification Register 1 : %08lx\n", hyperram_reg_rdata_read()); @@ -197,7 +197,7 @@ __attribute__((__used__)) int main(int i, char **c) hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); printf("Configuration Register 0 : %08lx\n", hyperram_reg_rdata_read()); @@ -206,7 +206,7 @@ __attribute__((__used__)) int main(int i, char **c) hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 3 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + 3 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); printf("Configuration Register 1 : %08lx\n", hyperram_reg_rdata_read()); @@ -217,30 +217,18 @@ __attribute__((__used__)) int main(int i, char **c) hyperram_reg_control_write( 1 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 0 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0); - printf("reg_control: %x\n", hyperram_reg_control_read()); - printf("reg_status: %x\n", hyperram_reg_status_read()); - printf("reg_debug: %x\n", hyperram_reg_debug_read()); - hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET + 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); printf("Configuration Register 0 after update : %08lx\n", hyperram_reg_rdata_read()); - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 3 << CSR_HYPERRAM_REG_CONTROL_REG_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - printf("Configuration Register 1 : %08lx\n", hyperram_reg_rdata_read()); - #if defined(CSR_ETHMAC_BASE) || defined(MAIN_RAM_BASE) || defined(CSR_SPIFLASH_CORE_BASE) printf("--========== \e[1mInitialization\e[0m ============--\n"); From 33a1fcda48658cfadbbea6190d1dfbc51922c010 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 12 Apr 2024 19:35:31 +0200 Subject: [PATCH 08/18] software/bios: Do minimal reconfiguration for variable latency and start testing latency cycles re-configuration. --- litex/soc/software/bios/main.c | 57 ++++++---------------------------- 1 file changed, 10 insertions(+), 47 deletions(-) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index f0db259bd..49cfb696c 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -175,44 +175,15 @@ __attribute__((__used__)) int main(int i, char **c) sdr_ok = 1; - uint16_t config_reg_0; - - /* HyperRAM Register access test */ - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 0 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - printf("Identification Register 0 : %08lx\n", hyperram_reg_rdata_read()); - - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - printf("Identification Register 1 : %08lx\n", hyperram_reg_rdata_read()); - - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - printf("Configuration Register 0 : %08lx\n", hyperram_reg_rdata_read()); - config_reg_0 = hyperram_reg_rdata_read(); - - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 3 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - printf("Configuration Register 1 : %08lx\n", hyperram_reg_rdata_read()); - - config_reg_0 &= ~(1 << 3); /* Enable Variable Latency */ - printf("New config_reg_0: %08lx\n", config_reg_0); +#ifdef CSR_HYPERRAM_BASE + /* HyperRAM Configuration */ + uint16_t config_reg_0 = 0x8f2f; + printf("Configuration Register 0 prev : %08lx\n", config_reg_0); + config_reg_0 &= ~(0b1 << 3); /* Enable Variable Latency */ + config_reg_0 &= ~(0b1111 << 4); /* Clear Initial Latency */ + config_reg_0 |= (0b0010 << 4); /* Initial Latency of 7 */ + //config_reg_0 |= (0b111 << 12); /* 19 ohm */ + printf("Configuration Register 0 new : %08lx\n", config_reg_0); hyperram_reg_wdata_write(config_reg_0); hyperram_reg_control_write( 1 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | @@ -220,15 +191,7 @@ __attribute__((__used__)) int main(int i, char **c) 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0); - - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - printf("Configuration Register 0 after update : %08lx\n", hyperram_reg_rdata_read()); - +#endif #if defined(CSR_ETHMAC_BASE) || defined(MAIN_RAM_BASE) || defined(CSR_SPIFLASH_CORE_BASE) printf("--========== \e[1mInitialization\e[0m ============--\n"); From 6216bd4e992d6594cd51eef1946bc6e335e56a56 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 10:32:13 +0200 Subject: [PATCH 09/18] cores/hyperbus: Add latency_mode parameter and test different latencies/modes in simulation. --- litex/soc/cores/hyperbus.py | 8 +- test/test_hyperbus.py | 169 +++++++++++++++++++++++++++++++++++- 2 files changed, 171 insertions(+), 6 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 45286fc6a..dc3c7e25c 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -30,10 +30,14 @@ class HyperRAM(LiteXModule): This core favors portability and ease of use over performance. """ - def __init__(self, pads, latency=6, sys_clk_freq=None, with_csr=True): + def __init__(self, pads, latency=6, latency_mode="fixed", sys_clk_freq=None, with_csr=True): self.pads = pads self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + # Parameters. + # ----------- + assert latency_mode in ["fixed", "variable"] + # Reg Interface. # -------------- self.reg_write = Signal() @@ -218,7 +222,7 @@ class HyperRAM(LiteXModule): NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), NextState("REG-WRITE-0") ).Else( - If(rwds.i, + If((latency_mode in ["fixed"]) | rwds.i, NextState("WAIT-LATENCY-0") ).Else( NextState("WAIT-LATENCY-1") diff --git a/test/test_hyperbus.py b/test/test_hyperbus.py index 922b4fc9e..9a4bf5cfc 100644 --- a/test/test_hyperbus.py +++ b/test/test_hyperbus.py @@ -33,7 +33,33 @@ class TestHyperBus(unittest.TestCase): pads = Record([("clk_p", 1), ("clk_n", 1), ("cs_n", 1), ("dq", 8), ("rwds", 1)]) hyperram = HyperRAM(pads) - def test_hyperram_write(self): + def test_hyperram_write_latency_5_2x(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 = "002000048d0000000000000000000000000000000000000000deadbeef000000" + rwds_oe = "__________________________________________________--------______" + rwds_o = "____________________________________________________----________" + for i in range(3): + yield + 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)) + 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) + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], 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) yield @@ -56,10 +82,90 @@ class TestHyperBus(unittest.TestCase): self.assertEqual(c2bool(rwds_o[i]), (yield dut.pads.rwds.o)) yield - dut = HyperRAM(HyperRamPads()) + dut = HyperRAM(HyperRamPads(), latency=6) run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") - def test_hyperram_read(self): + def test_hyperram_write_latency_7_2x(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 = "002000048d00000000000000000000000000000000000000000000000000000000deadbeef000000" + rwds_oe = "__________________________________________________________________--------______" + rwds_o = "____________________________________________________________________----________" + for i in range(3): + yield + 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)) + 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=7) + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") + + def test_hyperram_write_latency_7_1x(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 = "002000048d0000000000000000000000000000deadbeef000000" + rwds_oe = "______________________________________--------______" + rwds_o = "________________________________________----________" + for i in range(3): + yield + 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)) + 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=7, latency_mode="variable") + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") + + def test_hyperram_read_latency_5_2x(self): + def fpga_gen(dut): + dat = yield from dut.bus.read(0x1234) + self.assertEqual(dat, 0xdeadbeef) + dat = yield from dut.bus.read(0x1235) + self.assertEqual(dat, 0xcafefade) + + def hyperram_gen(dut): + clk = "___--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--_" + cs_n = "--________________________________________________________________________" + dq_oe = "__------------____________________________________________________________" + dq_o = "00a000048d0000000000000000000000000000000000000000000000000000000000000000" + dq_i = "00000000000000000000000000000000000000000000000000deadbeefcafefade00000000" + rwds_oe = "__________________________________________________________________________" + for i in range(3): + yield + 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)) + 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) + 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): dat = yield from dut.bus.read(0x1234) self.assertEqual(dat, 0xdeadbeef) @@ -84,9 +190,64 @@ class TestHyperBus(unittest.TestCase): self.assertEqual(c2bool(rwds_oe[i]), (yield dut.pads.rwds.oe)) yield - dut = HyperRAM(HyperRamPads()) + dut = HyperRAM(HyperRamPads(), latency=6) run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") + def test_hyperram_read_latency_7_2x(self): + def fpga_gen(dut): + dat = yield from dut.bus.read(0x1234) + self.assertEqual(dat, 0xdeadbeef) + dat = yield from dut.bus.read(0x1235) + self.assertEqual(dat, 0xcafefade) + + def hyperram_gen(dut): + clk = "___--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--_" + cs_n = "--________________________________________________________________________________________" + dq_oe = "__------------____________________________________________________________________________" + dq_o = "00a000048d00000000000000000000000000000000000000000000000000000000000000000000000000000000" + dq_i = "000000000000000000000000000000000000000000000000000000000000000000deadbeefcafefade00000000" + rwds_oe = "__________________________________________________________________________________________" + for i in range(3): + yield + 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)) + 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=7) + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") + + def test_hyperram_read_latency_7_1x(self): + def fpga_gen(dut): + dat = yield from dut.bus.read(0x1234) + self.assertEqual(dat, 0xdeadbeef) + dat = yield from dut.bus.read(0x1235) + self.assertEqual(dat, 0xcafefade) + + def hyperram_gen(dut): + clk = "___--__--__--__--__--__--__--__--__--__--__--__--__--__--__--_" + cs_n = "--____________________________________________________________" + dq_oe = "__------------________________________________________________" + dq_o = "00a000048d0000000000000000000000000000000000000000000000000000" + dq_i = "00000000000000000000000000000000000000deadbeefcafefade00000000" + rwds_oe = "______________________________________________________________" + for i in range(3): + yield + 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)) + 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=7, latency_mode="variable") + run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)], vcd_name="sim.vcd") def test_hyperram_reg_write(self): def fpga_gen(dut): From a95f1b8486afdc9d5d10bdb71dcbd60d1e7d9cb3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 12:06:11 +0200 Subject: [PATCH 10/18] cores/hyperbus: Make latency dynamically configurable. --- litex/soc/cores/hyperbus.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index dc3c7e25c..2ebd9979f 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -37,6 +37,7 @@ class HyperRAM(LiteXModule): # Parameters. # ----------- assert latency_mode in ["fixed", "variable"] + self.latency = Signal(8, reset=latency) # Reg Interface. # -------------- @@ -49,7 +50,7 @@ class HyperRAM(LiteXModule): self.reg_read_data = Signal(16) if with_csr: - self.add_csr() + self.add_csr(default_latency=latency) self.reg_debug = CSRStatus(32) @@ -180,8 +181,8 @@ class HyperRAM(LiteXModule): # Latency count starts from the middle of the command (thus the -4). In fixed latency mode # (default), latency is 2 x Latency count. We have 4 x sys_clk per RAM clock: - latency_cycles_0 = latency * 4 - latency_cycles_1 = latency * 4 - 4 + latency_cycles_0 = (self.latency * 4) + latency_cycles_1 = (self.latency * 4) - 4 # Bus Latch -------------------------------------------------------------------------------- bus_adr = Signal(32) @@ -331,7 +332,9 @@ class HyperRAM(LiteXModule): self.specials += t.get_tristate(pad) return t - def add_csr(self): + def add_csr(self, default_latency=6): + self._latency = CSRStorage(8, reset=default_latency) + self.comb += self.latency.eq(self._latency.storage) self.reg_control = CSRStorage(fields=[ CSRField("write", offset=0, size=1, pulse=True, description="Issue Register Write."), CSRField("read", offset=1, size=1, pulse=True, description="Issue Register Read."), From 93f76ede95e97a73613b39fa0cf2da537e346ac4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 12:06:49 +0200 Subject: [PATCH 11/18] bios/main: Test down to latency = 3, working. --- litex/soc/software/bios/main.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 49cfb696c..485f067d6 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -177,13 +177,25 @@ __attribute__((__used__)) int main(int i, char **c) #ifdef CSR_HYPERRAM_BASE /* HyperRAM Configuration */ - uint16_t config_reg_0 = 0x8f2f; + + uint16_t config_reg_0; + hyperram_latency_write(7); + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + config_reg_0 = hyperram_reg_rdata_read(); printf("Configuration Register 0 prev : %08lx\n", config_reg_0); config_reg_0 &= ~(0b1 << 3); /* Enable Variable Latency */ config_reg_0 &= ~(0b1111 << 4); /* Clear Initial Latency */ - config_reg_0 |= (0b0010 << 4); /* Initial Latency of 7 */ - //config_reg_0 |= (0b111 << 12); /* 19 ohm */ - printf("Configuration Register 0 new : %08lx\n", config_reg_0); + //config_reg_0 |= (0b0010 << 4); /* Initial Latency of 7 */ + //config_reg_0 |= (0b0001 << 4); /* Initial Latency of 6 */ + //config_reg_0 |= (0b0000 << 4); /* Initial Latency of 5 */ + //config_reg_0 |= (0b1111 << 4); /* Initial Latency of 4 */ + config_reg_0 |= (0b1110 << 4); /* Initial Latency of 3 */ + printf("Configuration Register 0 update : %08lx\n", config_reg_0); hyperram_reg_wdata_write(config_reg_0); hyperram_reg_control_write( 1 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | @@ -191,6 +203,20 @@ __attribute__((__used__)) int main(int i, char **c) 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0); + //hyperram_latency_write(7); + //hyperram_latency_write(6); + //hyperram_latency_write(5); + //hyperram_latency_write(4); + hyperram_latency_write(3); + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET + ); + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + config_reg_0 = hyperram_reg_rdata_read(); + printf("Configuration Register 0 new : %08lx\n", config_reg_0); + #endif #if defined(CSR_ETHMAC_BASE) || defined(MAIN_RAM_BASE) || defined(CSR_SPIFLASH_CORE_BASE) From 6e00cfa9d08d21ab52df6593dde599340b6171bd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 14:05:39 +0200 Subject: [PATCH 12/18] cores/hyperbus: Cleanup fixed/variable latency support. --- litex/soc/cores/hyperbus.py | 42 +++++++++---------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 2ebd9979f..3da7691e0 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -52,8 +52,6 @@ class HyperRAM(LiteXModule): if with_csr: self.add_csr(default_latency=latency) - self.reg_debug = CSRStatus(32) - # # # clk = Signal() @@ -150,13 +148,6 @@ class HyperRAM(LiteXModule): self.reg_read_done.eq(reg_read_done), ] - self.comb += [ - self.reg_debug.status[0].eq(reg_write_req), - self.reg_debug.status[1].eq(reg_write_done), - self.reg_debug.status[2].eq(reg_read_req), - self.reg_debug.status[3].eq(reg_read_done), - ] - # Command generation ----------------------------------------------------------------------- ashift = {8:1, 16:0}[dw] self.comb += [ @@ -179,11 +170,6 @@ class HyperRAM(LiteXModule): ) ] - # Latency count starts from the middle of the command (thus the -4). In fixed latency mode - # (default), latency is 2 x Latency count. We have 4 x sys_clk per RAM clock: - latency_cycles_0 = (self.latency * 4) - latency_cycles_1 = (self.latency * 4) - 4 - # Bus Latch -------------------------------------------------------------------------------- bus_adr = Signal(32) bus_we = Signal() @@ -199,8 +185,9 @@ class HyperRAM(LiteXModule): ) # FSM (Sequencer) -------------------------------------------------------------------------- - cycles = Signal(8) - first = Signal() + cycles = Signal(8) + first = Signal() + refresh = Signal() self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(first, 1), @@ -223,11 +210,9 @@ class HyperRAM(LiteXModule): NextValue(sr, Cat(Signal(40), self.reg_write_data[8:])), NextState("REG-WRITE-0") ).Else( - If((latency_mode in ["fixed"]) | rwds.i, - NextState("WAIT-LATENCY-0") - ).Else( - NextState("WAIT-LATENCY-1") - ) + # Sample RWDS to know if 1X/2X Latency should be used (Refresh). + NextValue(refresh, rwds.i | (latency_mode in ["fixed"])), + NextState("WAIT-LATENCY") ) ) ) @@ -256,19 +241,12 @@ class HyperRAM(LiteXModule): NextState("IDLE") ) ) - fsm.act("WAIT-LATENCY-0", + fsm.act("WAIT-LATENCY", # Set CSn. cs.eq(1), - # Wait for Latency cycles... - If(cycles == (latency_cycles_0 - 1), - NextState("WAIT-LATENCY-1") - ) - ) - fsm.act("WAIT-LATENCY-1", - # Set CSn. - cs.eq(1), - # Wait for Latency cycles... - If(cycles == (latency_cycles_1 - 1), + # Wait for 1X or 2X Latency cycles... (-4 since count start in the middle of the command). + If(((cycles == 2*(self.latency * 4) - 4 - 1) & refresh) | # 2X Latency (No DRAM refresh required). + ((cycles == 1*(self.latency * 4) - 4 - 1) & ~refresh) , # 1X Latency ( DRAM refresh required). # Latch Bus. bus_latch.eq(1), # Early Write Ack (to allow bursting). From 8e48d0d3302ef1a062fa79c0c621a14f37871b24 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 14:33:41 +0200 Subject: [PATCH 13/18] cores/hyperbus: Cleanup/Improve Config/Reg Interfaces. --- litex/soc/cores/hyperbus.py | 47 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 3da7691e0..8fa84bea6 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -34,13 +34,10 @@ class HyperRAM(LiteXModule): self.pads = pads self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - # Parameters. - # ----------- - assert latency_mode in ["fixed", "variable"] - self.latency = Signal(8, reset=latency) - - # Reg Interface. - # -------------- + # Config/Reg Interface. + # --------------------- + self.conf_rst = Signal() + self.conf_latency = Signal(8, reset=latency) self.reg_write = Signal() self.reg_read = Signal() self.reg_addr = Signal(2) @@ -48,12 +45,17 @@ class HyperRAM(LiteXModule): 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. + # ----------- + assert latency_mode in ["fixed", "variable"] + + # Internal Signals. + # ----------------- clk = Signal() clk_phase = Signal(2) cs = Signal() @@ -71,7 +73,7 @@ class HyperRAM(LiteXModule): # Rst. if hasattr(pads, "rst_n"): - self.comb += pads.rst_n.eq(1) + self.comb += pads.rst_n.eq(1 & ~self.conf_rst) # CSn. self.comb += pads.cs_n[0].eq(~cs) @@ -245,8 +247,8 @@ class HyperRAM(LiteXModule): # Set CSn. cs.eq(1), # Wait for 1X or 2X Latency cycles... (-4 since count start in the middle of the command). - If(((cycles == 2*(self.latency * 4) - 4 - 1) & refresh) | # 2X Latency (No DRAM refresh required). - ((cycles == 1*(self.latency * 4) - 4 - 1) & ~refresh) , # 1X Latency ( DRAM refresh required). + 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). @@ -311,16 +313,27 @@ class HyperRAM(LiteXModule): return t def add_csr(self, default_latency=6): - self._latency = CSRStorage(8, reset=default_latency) - self.comb += self.latency.eq(self._latency.storage) + # Config Interface. + # ----------------- + self.config = CSRStorage(fields=[ + CSRField("rst", offset=0, size=1, pulse=True, description="HyperRAM Rst."), + CSRField("latency", offset=8, size=8, description="HyperRAM Latency (X1).", reset=default_latency), + ]) + self.comb += [ + self.conf_rst.eq( self.config.fields.rst), + self.conf_latency.eq(self.config.fields.latency), + ] + + # Reg Interface. + # -------------- self.reg_control = CSRStorage(fields=[ CSRField("write", offset=0, size=1, pulse=True, description="Issue Register Write."), CSRField("read", offset=1, size=1, pulse=True, description="Issue Register Read."), CSRField("addr", offset=8, size=4, values=[ - ("``0``", "Identification Register 0 (Read Only)."), - ("``1``", "Identification Register 1 (Read Only)."), - ("``2``", "Configuration Register 0."), - ("``3``", "Configuration Register 1."), + ("``0b00``", "Identification Register 0 (Read Only)."), + ("``0b01``", "Identification Register 1 (Read Only)."), + ("``0b10``", "Configuration Register 0."), + ("``0b11``", "Configuration Register 1."), ]), ]) self.reg_status = CSRStatus(fields=[ From 1597791fb6d30c0f6f9b21c5d6ce5c60a53eacce Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 14:43:15 +0200 Subject: [PATCH 14/18] cores/hyperbus: Simplify reg_write/read_done. --- litex/soc/cores/hyperbus.py | 46 ++++++++++++++-------------------- litex/soc/software/bios/main.c | 12 ++++----- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 8fa84bea6..59e0a9ef8 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -122,42 +122,34 @@ class HyperRAM(LiteXModule): ] # Register Access/Buffer ------------------------------------------------------------------- - - reg_write_req = Signal() - reg_write_done = Signal() - reg_read_req = Signal() - reg_read_done = Signal() - - self.reg_buffer = reg_buffer = stream.SyncFIFO( + reg_write_req = Signal() + reg_read_req = Signal() + self.reg_buf = reg_buf = stream.SyncFIFO( layout = [("write", 1), ("read", 1), ("addr", 4), ("data", 16)], depth = 4, ) self.comb += [ - reg_buffer.sink.valid.eq(self.reg_write | self.reg_read), - reg_buffer.sink.write.eq(self.reg_write), - reg_buffer.sink.read.eq(self.reg_read), - reg_buffer.sink.addr.eq(self.reg_addr), - reg_buffer.sink.data.eq(self.reg_write_data), - reg_write_req.eq(reg_buffer.source.valid & reg_buffer.source.write), - reg_read_req.eq( reg_buffer.source.valid & reg_buffer.source.read), + reg_buf.sink.valid.eq(self.reg_write | self.reg_read), + reg_buf.sink.write.eq(self.reg_write), + reg_buf.sink.read.eq(self.reg_read), + reg_buf.sink.addr.eq(self.reg_addr), + reg_buf.sink.data.eq(self.reg_write_data), + reg_write_req.eq(reg_buf.source.valid & reg_buf.source.write), + reg_read_req.eq( reg_buf.source.valid & reg_buf.source.read), ] - self.sync += If(reg_buffer.sink.valid, - reg_write_done.eq(0), - reg_read_done.eq(0), + self.sync += If(reg_buf.sink.valid, + self.reg_write_done.eq(0), + self.reg_read_done.eq(0), ) - self.comb += [ - self.reg_write_done.eq(reg_write_done), - self.reg_read_done.eq(reg_read_done), - ] # Command generation ----------------------------------------------------------------------- ashift = {8:1, 16:0}[dw] self.comb += [ If(reg_write_req | reg_read_req, - ca[47].eq(reg_buffer.source.read), # R/W# + ca[47].eq(reg_buf.source.read), # R/W# ca[46].eq(1), # Register Space. ca[45].eq(1), # Burst Type (Linear) - Case(reg_buffer.source.addr, { + Case(reg_buf.source.addr, { 0 : ca[0:40].eq(0x00_00_00_00_00), # Identification Register 0 (Read Only). 1 : ca[0:40].eq(0x00_00_00_00_01), # Identification Register 1 (Read Only). 2 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 0. @@ -238,8 +230,8 @@ class HyperRAM(LiteXModule): dq.oe.eq(1), # Wait for 2 cycles... If(cycles == (2 - 1), - reg_buffer.source.ready.eq(1), - NextValue(reg_write_done, 1), + reg_buf.source.ready.eq(1), + NextValue(self.reg_write_done, 1), NextState("IDLE") ) ) @@ -293,8 +285,8 @@ class HyperRAM(LiteXModule): # Read Ack (when dat_r ready). If((n == 0) & ~first, If(reg_read_req, - reg_buffer.source.ready.eq(1), - NextValue(reg_read_done, 1), + reg_buf.source.ready.eq(1), + NextValue(self.reg_read_done, 1), NextValue(self.reg_read_data, bus.dat_r), NextState("IDLE"), ).Else( diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 485f067d6..4476aa372 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -179,7 +179,7 @@ __attribute__((__used__)) int main(int i, char **c) /* HyperRAM Configuration */ uint16_t config_reg_0; - hyperram_latency_write(7); + hyperram_config_write(7 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | @@ -203,11 +203,11 @@ __attribute__((__used__)) int main(int i, char **c) 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET ); while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0); - //hyperram_latency_write(7); - //hyperram_latency_write(6); - //hyperram_latency_write(5); - //hyperram_latency_write(4); - hyperram_latency_write(3); + //hyperram_config_write(7 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); + //hyperram_config_write(6 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); + //hyperram_config_write(5 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); + //hyperram_config_write(4 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); + hyperram_config_write(3 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); hyperram_reg_control_write( 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | From 2100a6bd8c3ec0b742c11faa4024ed1eee79038d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 14:48:38 +0200 Subject: [PATCH 15/18] cores/hyperbus: reg_buf.source -> reg_ep. --- litex/soc/cores/hyperbus.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 59e0a9ef8..8b1959cb6 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -128,14 +128,15 @@ class HyperRAM(LiteXModule): layout = [("write", 1), ("read", 1), ("addr", 4), ("data", 16)], depth = 4, ) + reg_ep = reg_buf.source self.comb += [ reg_buf.sink.valid.eq(self.reg_write | self.reg_read), reg_buf.sink.write.eq(self.reg_write), reg_buf.sink.read.eq(self.reg_read), reg_buf.sink.addr.eq(self.reg_addr), reg_buf.sink.data.eq(self.reg_write_data), - reg_write_req.eq(reg_buf.source.valid & reg_buf.source.write), - reg_read_req.eq( reg_buf.source.valid & reg_buf.source.read), + reg_write_req.eq(reg_ep.valid & reg_ep.write), + reg_read_req.eq( reg_ep.valid & reg_ep.read), ] self.sync += If(reg_buf.sink.valid, self.reg_write_done.eq(0), @@ -146,10 +147,10 @@ class HyperRAM(LiteXModule): ashift = {8:1, 16:0}[dw] self.comb += [ If(reg_write_req | reg_read_req, - ca[47].eq(reg_buf.source.read), # R/W# - ca[46].eq(1), # Register Space. - ca[45].eq(1), # Burst Type (Linear) - Case(reg_buf.source.addr, { + ca[47].eq(reg_ep.read), # R/W# + ca[46].eq(1), # Register Space. + ca[45].eq(1), # Burst Type (Linear) + Case(reg_ep.addr, { 0 : ca[0:40].eq(0x00_00_00_00_00), # Identification Register 0 (Read Only). 1 : ca[0:40].eq(0x00_00_00_00_01), # Identification Register 1 (Read Only). 2 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 0. @@ -230,7 +231,7 @@ class HyperRAM(LiteXModule): dq.oe.eq(1), # Wait for 2 cycles... If(cycles == (2 - 1), - reg_buf.source.ready.eq(1), + reg_ep.ready.eq(1), NextValue(self.reg_write_done, 1), NextState("IDLE") ) @@ -285,7 +286,7 @@ class HyperRAM(LiteXModule): # Read Ack (when dat_r ready). If((n == 0) & ~first, If(reg_read_req, - reg_buf.source.ready.eq(1), + reg_ep.ready.eq(1), NextValue(self.reg_read_done, 1), NextValue(self.reg_read_data, bus.dat_r), NextState("IDLE"), From d25fd85f554a42a66d1b9a9c9b0c9efb60d208c7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 14:56:08 +0200 Subject: [PATCH 16/18] cores/hyperbus: More cleanups. --- litex/soc/cores/hyperbus.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 8b1959cb6..321162f77 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -62,7 +62,7 @@ class HyperRAM(LiteXModule): ca = Signal(48) ca_active = Signal() sr = Signal(48) - sr_new = Signal(48) + sr_next = Signal(48) dq = self.add_tristate(pads.dq) if not hasattr(pads.dq, "oe") else pads.dq rwds = self.add_tristate(pads.rwds) if not hasattr(pads.rwds, "oe") else pads.rwds dw = len(pads.dq) if not hasattr(pads.dq, "oe") else len(pads.dq.o) @@ -103,16 +103,16 @@ class HyperRAM(LiteXModule): dqi = Signal(dw) self.sync += dqi.eq(dq.i) # Sample on 90° and 270° self.comb += [ - sr_new.eq(Cat(dqi, sr[:-dw])), + sr_next.eq(Cat(dqi, sr[:-dw])), If(ca_active, - sr_new.eq(Cat(dqi[:8], sr[:-8])) # Only 8-bit during Command/Address. + sr_next.eq(Cat(dqi[:8], sr[:-8])) # Only 8-bit during Command/Address. ) ] - self.sync += If(clk_phase[0] == 0, sr.eq(sr_new)) # Shift on 0° and 180° + self.sync += If(clk_phase[0] == 0, sr.eq(sr_next)) # Shift on 0° and 180° # Data Shift-Out Register ------------------------------------------------------------------ self.comb += [ - bus.dat_r.eq(sr_new), + bus.dat_r.eq(sr_next), If(dq.oe, dq.o.eq(sr[-dw:]), If(ca_active, @@ -146,6 +146,7 @@ class HyperRAM(LiteXModule): # Command generation ----------------------------------------------------------------------- ashift = {8:1, 16:0}[dw] self.comb += [ + # Register Command Generation. If(reg_write_req | reg_read_req, ca[47].eq(reg_ep.read), # R/W# ca[46].eq(1), # Register Space. @@ -156,6 +157,7 @@ class HyperRAM(LiteXModule): 2 : ca[0:40].eq(0x00_01_00_00_00), # Configuration Register 0. 3 : ca[0:40].eq(0x00_01_00_00_01), # Configuration Register 1. }), + # Wishbone Command Generation. ).Else( ca[47].eq(~bus.we), # R/W# ca[46].eq(0), # Memory Space. @@ -171,9 +173,7 @@ class HyperRAM(LiteXModule): bus_sel = Signal(4) bus_latch = Signal() self.sync += If(bus_latch, - If(bus.we, - sr.eq(Cat(Signal(16), bus.dat_w)), - ), + If(bus.we, sr.eq(Cat(Signal(16), bus.dat_w))), bus_we.eq(bus.we), bus_sel.eq(bus.sel), bus_adr.eq(bus.adr) From 67586e8a24d89a3cc0ad9da910d801eb45d859bb Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 15:05:58 +0200 Subject: [PATCH 17/18] cores/hyperbus: Update docstring. --- litex/soc/cores/hyperbus.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 321162f77..9587b747f 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -24,12 +24,23 @@ class HyperRAM(LiteXModule): tCSM = 4e-6 """HyperRAM - Provides a very simple/minimal HyperRAM core that should work with all FPGA/HyperRam chips: - - FPGA vendor agnostic. - - no setup/chip configuration (use default latency). + Provides a very simple/minimal HyperRAM core with a Wishbone Interface that can work with all + FPGA/HyperRam chips: + - Vendor agnostic. + - Fixed/Variable latency. + - Latency/Registers (re-)configuration. - This core favors portability and ease of use over performance. - """ + Parameters: + pads (Record) : Interface to the HyperRAM connection pads. + latency (int, optional) : Initial latency setting, defaults to 6. + latency_mode (str, optional) : Specifies the latency mode ('fixed' or 'variable'), defaults to 'fixed'. + sys_clk_freq (float, optional) : System clock frequency in Hz. + with_csr (bool, optional) : Enables CSR interface for Latency/Registers configuration, defaults to True. + + Attributes: + pads (Record) : Platform pads of HyperRAM. + bus (wishbone.Interface) : Wishbone Interface. +""" def __init__(self, pads, latency=6, latency_mode="fixed", sys_clk_freq=None, with_csr=True): self.pads = pads self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") From ebabe82c7084a3561e6eb97df6e8f4fee011a590 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Apr 2024 16:03:55 +0200 Subject: [PATCH 18/18] software/bios/main: Rewrite HyperRAM init/config. --- litex/soc/software/bios/main.c | 117 ++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 40 deletions(-) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 4476aa372..87b4219df 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -175,48 +175,85 @@ __attribute__((__used__)) int main(int i, char **c) sdr_ok = 1; -#ifdef CSR_HYPERRAM_BASE - /* HyperRAM Configuration */ +#ifdef CSR_HYPERRAM_BASE /* FIXME: Move to libbase/hyperram.h/c? */ + /* Helper Functions */ - uint16_t config_reg_0; - hyperram_config_write(7 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - config_reg_0 = hyperram_reg_rdata_read(); - printf("Configuration Register 0 prev : %08lx\n", config_reg_0); - config_reg_0 &= ~(0b1 << 3); /* Enable Variable Latency */ - config_reg_0 &= ~(0b1111 << 4); /* Clear Initial Latency */ - //config_reg_0 |= (0b0010 << 4); /* Initial Latency of 7 */ - //config_reg_0 |= (0b0001 << 4); /* Initial Latency of 6 */ - //config_reg_0 |= (0b0000 << 4); /* Initial Latency of 5 */ - //config_reg_0 |= (0b1111 << 4); /* Initial Latency of 4 */ - config_reg_0 |= (0b1110 << 4); /* Initial Latency of 3 */ - printf("Configuration Register 0 update : %08lx\n", config_reg_0); - hyperram_reg_wdata_write(config_reg_0); - hyperram_reg_control_write( - 1 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 0 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0); - //hyperram_config_write(7 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); - //hyperram_config_write(6 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); - //hyperram_config_write(5 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); - //hyperram_config_write(4 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); - hyperram_config_write(3 << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); - hyperram_reg_control_write( - 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | - 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | - 2 << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET - ); - while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); - config_reg_0 = hyperram_reg_rdata_read(); - printf("Configuration Register 0 new : %08lx\n", config_reg_0); + printf("HyperRAM init...\n"); + void hyperram_write_reg(uint16_t reg_addr, uint16_t data) { + /* Write data to the register */ + hyperram_reg_wdata_write(data); + hyperram_reg_control_write( + 1 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 0 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + reg_addr << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET + ); + /* Wait for write to complete */ + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0); + } + uint16_t hyperram_read_reg(uint16_t reg_addr) { + /* Read data from the register */ + hyperram_reg_control_write( + 0 << CSR_HYPERRAM_REG_CONTROL_WRITE_OFFSET | + 1 << CSR_HYPERRAM_REG_CONTROL_READ_OFFSET | + reg_addr << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET + ); + /* Wait for read to complete */ + while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0); + return hyperram_reg_rdata_read(); + } + + /* Configuration and Utility Functions */ + + uint16_t hyperram_get_core_latency_setting(uint32_t clk_freq) { + /* Raw clock latency settings for the HyperRAM core */ + if (clk_freq <= 85000000) return 3; /* 3 Clock Latency */ + if (clk_freq <= 104000000) return 4; /* 4 Clock Latency */ + if (clk_freq <= 133000000) return 5; /* 5 Clock Latency */ + if (clk_freq <= 166000000) return 6; /* 6 Clock Latency */ + if (clk_freq <= 250000000) return 7; /* 7 Clock Latency */ + return 7; /* Default to highest latency for safety */ + } + + uint16_t hyperram_get_chip_latency_setting(uint32_t clk_freq) { + /* LUT/Translated settings for the HyperRAM chip */ + if (clk_freq <= 85000000) return 0b1110; /* 3 Clock Latency */ + if (clk_freq <= 104000000) return 0b1111; /* 4 Clock Latency */ + if (clk_freq <= 133000000) return 0b0000; /* 5 Clock Latency */ + if (clk_freq <= 166000000) return 0b0001; /* 6 Clock Latency */ + if (clk_freq <= 250000000) return 0b0010; /* 7 Clock Latency */ + return 0b0010; /* Default to highest latency for safety */ + } + + void hyperram_configure_latency(void) { + uint16_t config_reg_0 = 0x8f2f; + 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); + + /* Write Latency to HyperRAM Core */ + printf("HyperRAM Core Latency: %d CK (X1).\n", core_latency_setting); + hyperram_config_write(core_latency_setting << CSR_HYPERRAM_CONFIG_LATENCY_OFFSET); + + /* Enable Variable Latency on HyperRAM Chip */ + config_reg_0 &= ~(0b1 << 3); /* Enable Variable Latency */ + + /* Update Latency on HyperRAM Chip */ + config_reg_0 &= ~(0b1111 << 4); + config_reg_0 |= chip_latency_setting << 4; + + /* Write Configuration Register 0 to HyperRAM Chip */ + hyperram_write_reg(2, config_reg_0); + + /* Read current configuration */ + config_reg_0 = hyperram_read_reg(2); + printf("HyperRAM Configuration Register 0: %08x\n", config_reg_0); + } + hyperram_configure_latency(); + printf("\n"); #endif #if defined(CSR_ETHMAC_BASE) || defined(MAIN_RAM_BASE) || defined(CSR_SPIFLASH_CORE_BASE)