From 03a0a6fd9bfabd77ee51df9dea1d54e09b5ddc5f Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Fri, 24 May 2024 11:57:53 +0000 Subject: [PATCH 1/4] soc: add add_spi_ram function Signed-off-by: Matthias Breithaupt --- litex/soc/integration/soc.py | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 6c286355f..bfad679cb 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -2092,6 +2092,48 @@ class LiteXSoC(SoC): self.add_module(name=f"{name}_core", module=spiflash_core) spiflash_region = SoCRegion(origin=self.mem_map.get(name, None), size=module.total_size) self.bus.add_slave(name=name, slave=spiflash_core.bus, region=spiflash_region) + self.comb += spiflash_core.mmap.offset.eq(self.bus.regions.get(name, None).origin) + + # Constants. + self.add_constant(f"{name}_PHY_FREQUENCY", clk_freq) + self.add_constant(f"{name}_MODULE_NAME", module.name) + self.add_constant(f"{name}_MODULE_TOTAL_SIZE", module.total_size) + self.add_constant(f"{name}_MODULE_PAGE_SIZE", module.page_size) + if mode in [ "4x" ]: + if SpiNorFlashOpCodes.READ_1_1_4 in module.supported_opcodes: + self.add_constant(f"{name}_MODULE_QUAD_CAPABLE") + if SpiNorFlashOpCodes.READ_4_4_4 in module.supported_opcodes: + self.add_constant(f"{name}_MODULE_QPI_CAPABLE") + if software_debug: + self.add_constant(f"{name}_DEBUG") + + # Add SPI RAM -------------------------------------------------------------------------------- + def add_spi_ram(self, name="spiram", mode="4x", clk_freq=20e6, module=None, phy=None, rate="1:1", software_debug=False, **kwargs): + # Imports. + from litespi import LiteSPI + from litespi.phy.generic import LiteSPIPHY + from litespi.opcodes import SpiNorFlashOpCodes + + # Checks/Parameters. + assert mode in ["1x", "4x"] + default_divisor = math.ceil(self.sys_clk_freq/(2*clk_freq)) - 1 + clk_freq = int(self.sys_clk_freq/(2*(default_divisor + 1))) + + # PHY. + spiram_phy = phy + if spiram_phy is None: + self.check_if_exists(f"{name}_phy") + spiram_pads = self.platform.request(name if mode == "1x" else name + mode) + spiram_phy = LiteSPIPHY(spiram_pads, module, device=self.platform.device, default_divisor=default_divisor, rate=rate) + self.add_module(name=f"{name}_phy", module=spiram_phy) + + # Core. + self.check_if_exists(f"{name}_mmap") + spiram_core = LiteSPI(spiram_phy, mmap_endianness=self.cpu.endianness, with_mmap_write=True, **kwargs) + self.add_module(name=f"{name}_core", module=spiram_core) + spiram_region = SoCRegion(origin=self.mem_map.get(name, None), size=module.total_size) + self.bus.add_slave(name=name, slave=spiram_core.bus, region=spiram_region) + self.comb += spiram_core.mmap.offset.eq(self.bus.regions.get(name, None).origin) # Constants. self.add_constant(f"{name}_PHY_FREQUENCY", clk_freq) From 41b346d141d9a873b6e8304fe4bcf10ece668e96 Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Tue, 4 Jun 2024 10:45:01 +0200 Subject: [PATCH 2/4] bios: mem_read: reduce number of reads on mapped registers (only supports 32-bit aligned addresses) Instead of reading each individual byte, causing multiple 4-byte requests to each address, this change results in a single read for each address. Signed-off-by: Matthias Breithaupt --- litex/soc/software/bios/helpers.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/litex/soc/software/bios/helpers.c b/litex/soc/software/bios/helpers.c index 0f8e9bfab..6b384ec0e 100644 --- a/litex/soc/software/bios/helpers.c +++ b/litex/soc/software/bios/helpers.c @@ -18,18 +18,24 @@ extern unsigned int _ftext, _edata_rom; #define NUMBER_OF_BYTES_ON_A_LINE 16 void dump_bytes(unsigned int *ptr, int count, unsigned long addr) { - char *data = (char *)ptr; + uint32_t *dptr = (uint32_t *)ptr; + char data[NUMBER_OF_BYTES_ON_A_LINE]; int line_bytes = 0, i = 0; + fputs("Memory dump:", stdout); while (count > 0) { line_bytes = (count > NUMBER_OF_BYTES_ON_A_LINE)? NUMBER_OF_BYTES_ON_A_LINE : count; + for (i = 0; i < line_bytes; i+=4){ + *((uint32_t*)&data[i]) = *(dptr++); + } + printf("\n0x%08lx ", addr); for (i = 0; i < line_bytes; i++) - printf("%02x ", *(unsigned char *)(data+i)); + printf("%02x ", (unsigned char)data[i]); for (; i < NUMBER_OF_BYTES_ON_A_LINE; i++) printf(" "); @@ -37,16 +43,15 @@ void dump_bytes(unsigned int *ptr, int count, unsigned long addr) printf(" "); for (i = 0; i 0x7e)) + if ((data[i] < 0x20) || (data[i] > 0x7e)) printf("."); else - printf("%c", *(data+i)); + printf("%c", data[i]); } for (; i < NUMBER_OF_BYTES_ON_A_LINE; i++) printf(" "); - data += (char)line_bytes; count -= line_bytes; addr += line_bytes; } From e29dc39377a4660983ebf6dc369683c1de4b4399 Mon Sep 17 00:00:00 2001 From: Matthias Breithaupt Date: Wed, 5 Jun 2024 10:44:30 +0200 Subject: [PATCH 3/4] openocd/jtagspi: Allow users to specify additional init commands This change makes it possible to e.g. use flahs chips that would not be correctly detected by OpenOCD. All that has to be done is to add `init_commands=["jtagspi set 0 \"name\" {size} {pagesize} {read_cmd} 0 {pprg_cmd} {mass_erase_cmd} {sector_size} {sector_erase_cmd}"]`. Signed-off-by: Matthias Breithaupt --- litex/build/openocd.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/build/openocd.py b/litex/build/openocd.py index c9160c51c..62644da5f 100644 --- a/litex/build/openocd.py +++ b/litex/build/openocd.py @@ -27,12 +27,13 @@ class OpenOCD(GenericProgrammer): ]) self.call(["openocd", "-f", config, "-c", script]) - def flash(self, address, data, set_qe=False): + def flash(self, address, data, set_qe=False, init_commands=[]): config = self.find_config() flash_proxy = self.find_flash_proxy() script = "; ".join([ "init", - "jtagspi_init 0 {{{}}}".format(flash_proxy), + "jtagspi_init 0 {{{}}}".format(flash_proxy) + ] + init_commands + [ "jtagspi set_qe 0 1" if set_qe else "", "jtagspi_program {{{}}} 0x{:x}".format(data, address), "fpga_program", From cd457c98092b74147c171b71b08eb2d07fbd4598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fin=20Maa=C3=9F?= Date: Tue, 2 Jul 2024 10:50:34 +0200 Subject: [PATCH 4/4] soc: add l2 cache to spi_ram MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fin Maaß --- litex/soc/integration/soc.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index bfad679cb..11e6d06b9 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -2108,7 +2108,11 @@ class LiteXSoC(SoC): self.add_constant(f"{name}_DEBUG") # Add SPI RAM -------------------------------------------------------------------------------- - def add_spi_ram(self, name="spiram", mode="4x", clk_freq=20e6, module=None, phy=None, rate="1:1", software_debug=False, **kwargs): + def add_spi_ram(self, name="spiram", mode="4x", clk_freq=20e6, module=None, phy=None, rate="1:1", software_debug=False, + l2_cache_size = 8192, + l2_cache_reverse = False, + l2_cache_full_memory_we = True, + **kwargs): # Imports. from litespi import LiteSPI from litespi.phy.generic import LiteSPIPHY @@ -2132,8 +2136,28 @@ class LiteXSoC(SoC): spiram_core = LiteSPI(spiram_phy, mmap_endianness=self.cpu.endianness, with_mmap_write=True, **kwargs) self.add_module(name=f"{name}_core", module=spiram_core) spiram_region = SoCRegion(origin=self.mem_map.get(name, None), size=module.total_size) - self.bus.add_slave(name=name, slave=spiram_core.bus, region=spiram_region) + + # Create Wishbone Slave. + wb_spiram = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.bus.add_slave(name=name, slave=wb_spiram, region=spiram_region) self.comb += spiram_core.mmap.offset.eq(self.bus.regions.get(name, None).origin) + + # L2 Cache + if l2_cache_size != 0: + # Insert L2 cache inbetween Wishbone bus and LiteSPI + l2_cache_size = max(l2_cache_size, int(2*32/8)) # Use minimal size if lower + l2_cache_size = 2**int(log2(l2_cache_size)) # Round to nearest power of 2 + l2_cache = wishbone.Cache( + cachesize = l2_cache_size//4, + master = wb_spiram, + slave = spiram_core.bus, + reverse = l2_cache_reverse) + if l2_cache_full_memory_we: + l2_cache = FullMemoryWE()(l2_cache) + self.l2_cache = l2_cache + self.add_config("L2_SIZE", l2_cache_size) + else: + self.submodules += wishbone.Converter(wb_spiram, spiram_core.bus) # Constants. self.add_constant(f"{name}_PHY_FREQUENCY", clk_freq)