From 5b524485e8bd9794a337283147bf11f7c219ee04 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Sat, 17 Sep 2022 17:56:56 -0500 Subject: [PATCH 001/454] increase jtaguart speed using large transfers in openocd --- litex/build/openocd.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/litex/build/openocd.py b/litex/build/openocd.py index 0a2c8004d..5e0cc2d94 100644 --- a/litex/build/openocd.py +++ b/litex/build/openocd.py @@ -139,12 +139,8 @@ def stream(self, port=20000, chain=1): proc jtagstream_rxtx {tap client is_poll} { if {![$client eof]} { - if {!$is_poll} { - set tx [$client read 1] - } else { - set tx "" - } - set rx [jtagstream_drain $tap $tx 64 4096] + set tx [$client read 512] + set rx [jtagstream_drain $tap $tx 512 4096] if {[string length $rx]} { #echo [string length $rx] $client puts -nonewline $rx @@ -162,6 +158,7 @@ def stream(self, port=20000, chain=1): proc jtagstream_client {tap sock} { set client [$sock accept] fconfigure $client -buffering none + fconfigure $client -blocking 0 $client readable [list jtagstream_rxtx $tap $client 0] $client onexception [list $client close] after 1 [list jtagstream_rxtx $tap $client 1] From b107d4a6fed9d0a7a77a857f31c8f1e0e6ec15c8 Mon Sep 17 00:00:00 2001 From: Vamsi Vytla Date: Thu, 3 Nov 2022 21:26:28 -0700 Subject: [PATCH 002/454] Make keep attribute for add_period_constraint optional. Vivado 2019 barfs upon IDELAYCTRL automatically replicated and it's refclk set to dont_touch. --- litex/build/generic_toolchain.py | 5 +++-- litex/build/xilinx/platform.py | 4 ++-- litex/build/xilinx/vivado.py | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/build/generic_toolchain.py b/litex/build/generic_toolchain.py index f7b832ad8..987268744 100644 --- a/litex/build/generic_toolchain.py +++ b/litex/build/generic_toolchain.py @@ -157,8 +157,9 @@ def build(self, platform, fragment, return v_output.ns - def add_period_constraint(self, platform, clk, period): - clk.attr.add("keep") + def add_period_constraint(self, platform, clk, period, keep=True): + if keep: + clk.attr.add("keep") period = math.floor(period*1e3)/1e3 # Round to lowest picosecond. if clk in self.clocks: if period != self.clocks[clk]: diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index 14f6092bb..b3bfb1029 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -72,11 +72,11 @@ def get_edif(self, fragment, **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period): + def add_period_constraint(self, clk, period, keep=True): if clk is None: return if hasattr(clk, "p"): clk = clk.p - self.toolchain.add_period_constraint(self, clk, period) + self.toolchain.add_period_constraint(self, clk, period, keep=keep) def add_false_path_constraint(self, from_, to): if hasattr(from_, "p"): diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 8535d2948..21400e7b4 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -384,7 +384,6 @@ def run_script(self, script): if tools.subprocess_call_filtered(shell + [script], common.colors) != 0: raise OSError("Error occured during Vivado's script execution.") - def vivado_build_args(parser): toolchain_group = parser.add_argument_group(title="Toolchain options") toolchain_group.add_argument("--synth-mode", default="vivado", help="Synthesis mode (vivado or yosys).") From 11dc5b049b83994603dc7eae3b921a0781cd934d Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 20 Apr 2023 18:35:56 +0800 Subject: [PATCH 003/454] Working clam shell topology --- litex/soc/software/liblitedram/sdram.c | 46 ++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index 51805d11e..cdae0ae13 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -254,10 +254,28 @@ void sdram_software_control_off(void) { /* Mode Register */ /*-----------------------------------------------------------------------*/ +int swap_bit(int num, int a, int b) { + if (((num >> a) & 1) != ((num >> b) & 1)) { + num ^= (1 << a); + num ^= (1 << b); + } + return num; +} + void sdram_mode_register_write(char reg, int value) { sdram_dfii_pi0_address_write(value); sdram_dfii_pi0_baddress_write(reg); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); + + value = swap_bit(value, 3, 4); + value = swap_bit(value, 5, 6); + value = swap_bit(value, 7, 8); + value = swap_bit(value, 11, 13); + reg = swap_bit(reg, 0, 1); + + sdram_dfii_pi0_address_write(value); + sdram_dfii_pi0_baddress_write(reg); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); } #ifdef CSR_DDRPHY_BASE @@ -543,7 +561,18 @@ static void sdram_write_leveling_on(void) { // Flip write leveling bit in the Mode Register, as it is disabled by default sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)); sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); + + int addr = DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT); + int baddr = DDRX_MR_WRLVL_ADDRESS; + addr = swap_bit(addr, 3, 4); + addr = swap_bit(addr, 5, 6); + addr = swap_bit(addr, 7, 8); + addr = swap_bit(addr, 11, 13); + baddr = swap_bit(baddr, 0, 1); + sdram_dfii_pi0_address_write(addr); + sdram_dfii_pi0_baddress_write(baddr); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); #ifdef SDRAM_PHY_DDR4_RDIMM sdram_dfii_pi0_address_write((DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)) ^ 0x2BF8) ; @@ -557,7 +586,18 @@ static void sdram_write_leveling_on(void) { static void sdram_write_leveling_off(void) { sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET); sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); + + int addr = DDRX_MR_WRLVL_RESET; + int baddr = DDRX_MR_WRLVL_ADDRESS; + addr = swap_bit(addr, 3, 4); + addr = swap_bit(addr, 5, 6); + addr = swap_bit(addr, 7, 8); + addr = swap_bit(addr, 11, 13); + baddr = swap_bit(baddr, 0, 1); + sdram_dfii_pi0_address_write(addr); + sdram_dfii_pi0_baddress_write(baddr); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); #ifdef SDRAM_PHY_DDR4_RDIMM sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ 0x2BF8); From 89396c758616f551a359c42977a1fdbb1960992b Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 20 Apr 2023 18:45:12 +0800 Subject: [PATCH 004/454] Add SDRAM_PHY_CLAM_SHELL guard --- litex/soc/software/liblitedram/sdram.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index cdae0ae13..f4ea33fe3 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -263,6 +263,11 @@ int swap_bit(int num, int a, int b) { } void sdram_mode_register_write(char reg, int value) { +#ifndef SDRAM_PHY_CLAM_SHELL + sdram_dfii_pi0_address_write(value); + sdram_dfii_pi0_baddress_write(reg); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); +#else sdram_dfii_pi0_address_write(value); sdram_dfii_pi0_baddress_write(reg); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); @@ -276,6 +281,7 @@ void sdram_mode_register_write(char reg, int value) { sdram_dfii_pi0_address_write(value); sdram_dfii_pi0_baddress_write(reg); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); +#endif } #ifdef CSR_DDRPHY_BASE @@ -559,6 +565,11 @@ int _sdram_write_leveling_cdly_range_end = -1; static void sdram_write_leveling_on(void) { // Flip write leveling bit in the Mode Register, as it is disabled by default +#ifndef SDRAM_PHY_CLAM_SHELL + sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)); + sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); +#else sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)); sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); @@ -573,6 +584,7 @@ static void sdram_write_leveling_on(void) { sdram_dfii_pi0_address_write(addr); sdram_dfii_pi0_baddress_write(baddr); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); +#endif #ifdef SDRAM_PHY_DDR4_RDIMM sdram_dfii_pi0_address_write((DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)) ^ 0x2BF8) ; From 4731aa65220d361ed85fa691f53b46839a8b65ed Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 20 Apr 2023 18:46:50 +0800 Subject: [PATCH 005/454] Add missing ifdef check --- litex/soc/software/liblitedram/sdram.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index f4ea33fe3..ad583bb4e 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -596,6 +596,11 @@ static void sdram_write_leveling_on(void) { } static void sdram_write_leveling_off(void) { +#ifndef SDRAM_PHY_CLAM_SHELL + sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET); + sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); +#else sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET); sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); @@ -610,6 +615,7 @@ static void sdram_write_leveling_off(void) { sdram_dfii_pi0_address_write(addr); sdram_dfii_pi0_baddress_write(baddr); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); +#endif #ifdef SDRAM_PHY_DDR4_RDIMM sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ 0x2BF8); From 0976c5aa54a45101d8036209969710f92b33da4f Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Thu, 20 Apr 2023 19:00:26 +0800 Subject: [PATCH 006/454] Refactor code --- litex/soc/software/liblitedram/sdram.c | 42 ++------------------------ 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index ad583bb4e..0a00ed5fa 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -565,26 +565,7 @@ int _sdram_write_leveling_cdly_range_end = -1; static void sdram_write_leveling_on(void) { // Flip write leveling bit in the Mode Register, as it is disabled by default -#ifndef SDRAM_PHY_CLAM_SHELL - sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)); - sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); -#else - sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)); - sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); - - int addr = DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT); - int baddr = DDRX_MR_WRLVL_ADDRESS; - addr = swap_bit(addr, 3, 4); - addr = swap_bit(addr, 5, 6); - addr = swap_bit(addr, 7, 8); - addr = swap_bit(addr, 11, 13); - baddr = swap_bit(baddr, 0, 1); - sdram_dfii_pi0_address_write(addr); - sdram_dfii_pi0_baddress_write(baddr); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); -#endif + sdram_mode_register_write(DDRX_MR_WRLVL_ADDRESS, DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)); #ifdef SDRAM_PHY_DDR4_RDIMM sdram_dfii_pi0_address_write((DDRX_MR_WRLVL_RESET ^ (1 << DDRX_MR_WRLVL_BIT)) ^ 0x2BF8) ; @@ -596,26 +577,7 @@ static void sdram_write_leveling_on(void) { } static void sdram_write_leveling_off(void) { -#ifndef SDRAM_PHY_CLAM_SHELL - sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET); - sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); -#else - sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET); - sdram_dfii_pi0_baddress_write(DDRX_MR_WRLVL_ADDRESS); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_TOP); - - int addr = DDRX_MR_WRLVL_RESET; - int baddr = DDRX_MR_WRLVL_ADDRESS; - addr = swap_bit(addr, 3, 4); - addr = swap_bit(addr, 5, 6); - addr = swap_bit(addr, 7, 8); - addr = swap_bit(addr, 11, 13); - baddr = swap_bit(baddr, 0, 1); - sdram_dfii_pi0_address_write(addr); - sdram_dfii_pi0_baddress_write(baddr); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS_BOTTOM); -#endif + sdram_mode_register_write(DDRX_MR_WRLVL_ADDRESS, DDRX_MR_WRLVL_RESET); #ifdef SDRAM_PHY_DDR4_RDIMM sdram_dfii_pi0_address_write(DDRX_MR_WRLVL_RESET ^ 0x2BF8); From 309f012d2c670dffdc285fe49d15c3f8b29dfce4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 24 Apr 2023 10:31:47 +0200 Subject: [PATCH 007/454] cores/usb_ohci: Ensure self.usb_clk_freq is an integer (as a workaround to prevent build issue). --- litex/soc/cores/usb_ohci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/usb_ohci.py b/litex/soc/cores/usb_ohci.py index 3ed08c5ba..5948779ec 100644 --- a/litex/soc/cores/usb_ohci.py +++ b/litex/soc/cores/usb_ohci.py @@ -21,7 +21,7 @@ class USBOHCI(Module): def __init__(self, platform, pads, usb_clk_freq=48e6, dma_data_width=32): self.pads = pads - self.usb_clk_freq = usb_clk_freq + self.usb_clk_freq = int(usb_clk_freq) self.dma_data_width = dma_data_width self.wb_ctrl = wb_ctrl = wishbone.Interface(data_width=32) From 118dd6ed085c0a3a5e2f2dec2d6b20eac9dc5ac2 Mon Sep 17 00:00:00 2001 From: "Lukas F. Hartmann" Date: Tue, 25 Apr 2023 13:26:18 +0200 Subject: [PATCH 008/454] liblitespi/spiflash: add erase and write functions The code is based on norbert thiel's comment https://github.com/litex-hub/litespi/issues/52 But edited to work with W25Q128JVS flash used in MNT RKX7. --- litex/soc/software/liblitespi/spiflash.c | 129 +++++++++++++++++++++++ litex/soc/software/liblitespi/spiflash.h | 2 + 2 files changed, 131 insertions(+) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index cdc4552e1..e7f0cd12a 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -91,6 +91,135 @@ static void spiflash_master_write(uint32_t val, size_t len, size_t width, uint32 spiflash_core_master_cs_write(0); } +static volatile uint8_t w_buf[SPI_FLASH_BLOCK_SIZE + 4]; +static volatile uint8_t r_buf[SPI_FLASH_BLOCK_SIZE + 4]; + +static uint32_t transfer_byte(uint8_t b) +{ + /* wait for tx ready */ + while (!spiflash_core_master_status_tx_ready_read()); + + spiflash_core_master_rxtx_write((uint32_t)b); + + /* wait for rx ready */ + while (!spiflash_core_master_status_rx_ready_read()); + + return spiflash_core_master_rxtx_read(); +} + +static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len) +{ + spiflash_core_master_phyconfig_len_write(8); + spiflash_core_master_phyconfig_width_write(1); + spiflash_core_master_phyconfig_mask_write(1); + spiflash_core_master_cs_write(1); + + for (int i=0; i < len; i++) { + resp[i] = transfer_byte(bs[i]); + } + + spiflash_core_master_cs_write(0); +} + +static uint32_t spiflash_read_status_register(void) +{ + uint8_t buf[2]; + w_buf[0] = 0x05; + w_buf[1] = 0x00; + transfer_cmd(w_buf, buf, 2); + flush_cpu_dcache(); + + /* FIXME hack: sometimes, the result is in buf[0]. + * not sure why this happens. timing? */ + if (buf[1] == 0xff) return buf[0]; + return buf[1]; +} + +static void spiflash_write_enable(void) +{ + uint8_t buf[1]; + w_buf[0] = 0x06; + transfer_cmd(w_buf, buf, 1); +} + +static void page_program(uint32_t addr, uint8_t *data, int len) +{ + w_buf[0] = 0x02; + w_buf[1] = addr>>16; + w_buf[2] = addr>>8; + w_buf[3] = addr>>0; + memcpy(w_buf+4, data, len); + flush_cpu_dcache(); + transfer_cmd(w_buf, r_buf, len+4); +} + +static void spiflash_sector_erase(uint32_t addr) +{ + w_buf[0] = 0xd8; + w_buf[1] = addr>>16; + w_buf[2] = addr>>8; + w_buf[3] = addr>>0; + flush_cpu_dcache(); + transfer_cmd(w_buf, r_buf, 4); +} + +/* erase page size in bytes, check flash datasheet */ +#define SPI_FLASH_ERASE_SIZE (64*1024) + +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +void spiflash_erase_range(uint32_t addr, uint32_t len) +{ + uint32_t i = 0; + uint32_t j = 0; + for (i=0; i Date: Tue, 25 Apr 2023 13:30:07 +0200 Subject: [PATCH 009/454] bios/spiflash: bring back write and erase, add write from sdcard file cmd When shipping MNT RKX7, I pre-flash the SPI flash with a LiteX bitfile for testing. cmd_spiflash had regressed because of changed SPIFLASH defines and didn't offer the write functions anymore. This commit fixes that, and adds convenience functions: - flash_erase_range - flash_from_sdcard The latter reuses some boot code to copy the contents of the specified file from the boot FAT partition on the SD card to SPI flash (i.e. a bitstream). --- litex/soc/software/bios/cmds/cmd_spiflash.c | 111 ++++++++++++++++---- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/litex/soc/software/bios/cmds/cmd_spiflash.c b/litex/soc/software/bios/cmds/cmd_spiflash.c index 1038f7a79..7b1dacc62 100644 --- a/litex/soc/software/bios/cmds/cmd_spiflash.c +++ b/litex/soc/software/bios/cmds/cmd_spiflash.c @@ -8,23 +8,26 @@ #include "../command.h" #include "../helpers.h" +#include +#include +#include + /** * Command "flash_write" * * Write data from a memory buffer to SPI flash * */ -#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) +#if (defined CSR_SPIFLASH_CORE_MASTER_CS_ADDR) static void flash_write_handler(int nb_params, char **params) { char *c; unsigned int addr; - unsigned int value; + unsigned int mem_addr; unsigned int count; - unsigned int i; if (nb_params < 2) { - printf("flash_write [count]"); + printf("flash_write [count (bytes)]"); return; } @@ -34,9 +37,9 @@ static void flash_write_handler(int nb_params, char **params) return; } - value = strtoul(params[1], &c, 0); + mem_addr = strtoul(params[1], &c, 0); if (*c != 0) { - printf("Incorrect value"); + printf("Incorrect mem_addr"); return; } @@ -50,26 +53,92 @@ static void flash_write_handler(int nb_params, char **params) } } - for (i = 0; i < count; i++) - write_to_flash(addr + i * 4, (unsigned char *)&value, 4); + spiflash_write_stream(addr, (unsigned char *)mem_addr, count); } define_command(flash_write, flash_write_handler, "Write to flash", SPIFLASH_CMDS); -#endif -/** - * Command "flash_erase" - * - * Flash erase - * - */ -#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) -static void flash_erase_handler(int nb_params, char **params) +static void flash_from_sdcard_handler(int nb_params, char **params) { - erase_flash(); - printf("Flash erased\n"); + FRESULT fr; + FATFS fs; + FIL file; + uint32_t br; + uint32_t offset; + unsigned long length; + uint8_t buf[512]; + + if (nb_params < 1) { + printf("flash_from_sdcard "); + return; + } + + char* filename = params[0]; + + fr = f_mount(&fs, "", 1); + if (fr != FR_OK) + return; + fr = f_open(&file, filename, FA_READ); + if (fr != FR_OK) { + printf("%s file not found.\n", filename); + f_mount(0, "", 0); + return; + } + + length = f_size(&file); + printf("Copying %s to SPI flash (%ld bytes)...\n", filename, length); + init_progression_bar(length); + offset = 0; + for (;;) { + fr = f_read(&file, (void*) buf, 512, (UINT *)&br); + if (fr != FR_OK) { + printf("file read error.\n"); + f_close(&file); + f_mount(0, "", 0); + return; + } + if (br == 0) { + break; + } else { + spiflash_write_stream(offset, buf, br); + } + + offset += br; + show_progress(offset); + } + show_progress(offset); + printf("\n"); + + f_close(&file); + f_mount(0, "", 0); } +define_command(flash_from_sdcard, flash_from_sdcard_handler, "Write file from SD card to flash", SPIFLASH_CMDS); -define_command(flash_erase, flash_erase_handler, "Erase whole flash", SPIFLASH_CMDS); -#endif +static void flash_erase_range_handler(int nb_params, char **params) +{ + char *c; + uint32_t addr; + uint32_t count; + + if (nb_params < 2) { + printf("flash_erase "); + return; + } + + addr = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect offset"); + return; + } + + count = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + spiflash_erase_range(addr, count); +} + +define_command(flash_erase_range, flash_erase_range_handler, "Erase flash range", SPIFLASH_CMDS); +#endif From e23fe832f00e46728200a3cff642716f8c1ad2e0 Mon Sep 17 00:00:00 2001 From: "Lukas F. Hartmann" Date: Tue, 25 Apr 2023 17:05:33 +0200 Subject: [PATCH 010/454] litespi/flash: fix status reg read; remove delays --- litex/soc/software/liblitespi/spiflash.c | 48 +++++++++++++++--------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index e7f0cd12a..5bd827318 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -114,25 +114,30 @@ static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len) spiflash_core_master_phyconfig_mask_write(1); spiflash_core_master_cs_write(1); + flush_cpu_dcache(); for (int i=0; i < len; i++) { resp[i] = transfer_byte(bs[i]); } spiflash_core_master_cs_write(0); + flush_cpu_dcache(); } static uint32_t spiflash_read_status_register(void) { - uint8_t buf[2]; + volatile uint8_t buf[4]; w_buf[0] = 0x05; w_buf[1] = 0x00; - transfer_cmd(w_buf, buf, 2); - flush_cpu_dcache(); + transfer_cmd(w_buf, buf, 4); + +#if SPIFLASH_DEBUG + printf("[SR: %02x %02x %02x %02x]", buf[0], buf[1], buf[2], buf[3]); +#endif - /* FIXME hack: sometimes, the result is in buf[0]. - * not sure why this happens. timing? */ - if (buf[1] == 0xff) return buf[0]; - return buf[1]; + /* FIXME normally the status should be in buf[1], + but we have to read it a few more times to be + stable for unknown reasons */ + return buf[3]; } static void spiflash_write_enable(void) @@ -149,7 +154,6 @@ static void page_program(uint32_t addr, uint8_t *data, int len) w_buf[2] = addr>>8; w_buf[3] = addr>>0; memcpy(w_buf+4, data, len); - flush_cpu_dcache(); transfer_cmd(w_buf, r_buf, len+4); } @@ -159,7 +163,6 @@ static void spiflash_sector_erase(uint32_t addr) w_buf[1] = addr>>16; w_buf[2] = addr>>8; w_buf[3] = addr>>0; - flush_cpu_dcache(); transfer_cmd(w_buf, r_buf, 4); } @@ -173,16 +176,15 @@ void spiflash_erase_range(uint32_t addr, uint32_t len) uint32_t i = 0; uint32_t j = 0; for (i=0; i Date: Thu, 27 Apr 2023 18:56:21 +0200 Subject: [PATCH 011/454] tools/litex_client: Add binded property to simplify user scripts. --- litex/tools/litex_client.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/litex/tools/litex_client.py b/litex/tools/litex_client.py index f832f4cc8..c082de09e 100644 --- a/litex/tools/litex_client.py +++ b/litex/tools/litex_client.py @@ -34,6 +34,7 @@ def __init__(self, host="localhost", port=1234, base_address=0, csr_csv=None, cs self.host = host self.port = port self.debug = debug + self.binded = False self.base_address = base_address if base_address is not None else 0 def _receive_server_info(self): @@ -44,17 +45,19 @@ def _receive_server_info(self): self.base_address = -self.mems.csr.base def open(self): - if hasattr(self, "socket"): + if self.binded: return self.socket = socket.create_connection((self.host, self.port), 5.0) self.socket.settimeout(5.0) self._receive_server_info() + self.binded = True def close(self): - if not hasattr(self, "socket"): + if not self.binded: return self.socket.close() del self.socket + self.binded = False def read(self, addr, length=None, burst="incr"): length_int = 1 if length is None else length From f62d380b2f0b2f4ab16dd2e3d76df9d4e4997e3f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Apr 2023 18:57:04 +0200 Subject: [PATCH 012/454] build/yosys_wrapper: Skip language=None files. --- litex/build/yosys_wrapper.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/build/yosys_wrapper.py b/litex/build/yosys_wrapper.py index 504bd9e5b..c720f5abc 100644 --- a/litex/build/yosys_wrapper.py +++ b/litex/build/yosys_wrapper.py @@ -81,6 +81,8 @@ def _import_sources(self): # yosys has no such function read_systemverilog if language == "systemverilog": language = "verilog -sv" + if language is None: + continue reads.append(f"read_{language}{includes} {filename}") return "\n".join(reads) From 0f1ad8dcfc545a532a5b4d03a6ad2ca9f90ffa6e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 5 May 2023 10:08:11 +0200 Subject: [PATCH 013/454] CHANGES.md: Update. --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 8b1d7953c..6065555d5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,8 @@ - cpu/soc : Fixed CPU IRQ reservation. - litepcie/software : Fixed compilation with DMA_CHECK_DATA commented. - litedram/dma : Fixed rdata connection (omit list update since LiteX AXI changes). + - litepcie/US(P) : Fixed possible MSI deadlock. + - cores/usb_ohci : Fixed build issue (usb_clk_freq wrapped as int). [> Added -------- @@ -80,6 +82,8 @@ - litedram/bist : Replicated data for large data-width. - litedram/ci : Allowed tests to run in parallel. - litedram/gw2ddrphy : Improvements to remove warnings in simulation. + - liblitespi/spiflash : Add erasee and write functions. + - liblitespi/Spiflash : Add write from sdcard file function. [> Changed ---------- From 85ee31aae7b9c8cb6a0000336a469abdd89aa705 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 7 May 2023 20:54:04 +0200 Subject: [PATCH 014/454] setup.py: Prepare for 2023.04. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f0966159b..a4b0df2a0 100755 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="litex", - version="2022.12", + version="2023.04", description="Python SoC/Core builder for building FPGA based systems.", long_description=long_description, long_description_content_type="text/markdown", From c5c7e86ccad9f0cca4bdf2917bf850d2458ef4a8 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Mon, 8 May 2023 13:42:10 +0700 Subject: [PATCH 015/454] WIP AvalonMM interface and Avalon to Wishbone Bridge (#1674) Add initial AvalonMM interface and AvalonMM2Wishbone. --- litex/soc/interconnect/avalon.py | 230 +++++++++++++++++++++++++++++++ test/test_avalon.py | 72 ++++++++++ 2 files changed, 302 insertions(+) create mode 100644 test/test_avalon.py diff --git a/litex/soc/interconnect/avalon.py b/litex/soc/interconnect/avalon.py index fbea428b1..307b4b253 100644 --- a/litex/soc/interconnect/avalon.py +++ b/litex/soc/interconnect/avalon.py @@ -2,6 +2,7 @@ # This file is part of LiteX. # # Copyright (c) 2019-2020 Florent Kermarrec +# Copyright (c) 2023 Hans Baier # SPDX-License-Identifier: BSD-2-Clause """Avalon support for LiteX""" @@ -9,6 +10,235 @@ from migen import * from litex.soc.interconnect import stream +from litex.soc.interconnect import wishbone + +_layout = [ + ("address", "adr_width", DIR_M_TO_S), + ("writedata", "data_width", DIR_M_TO_S), + ("readdata", "data_width", DIR_S_TO_M), + ("readdatavalid", 1, DIR_S_TO_M), + ("byteenable", "sel_width", DIR_M_TO_S), + ("read", 1, DIR_M_TO_S), + ("write", 1, DIR_M_TO_S), + ("waitrequest", 1, DIR_S_TO_M), + ("burstbegin", 1, DIR_M_TO_S), # this is optional + ("burstcount", 8, DIR_M_TO_S), + ("chipselect", 1, DIR_M_TO_S), # this is optional +] + +class AvalonMMInterface(Record): + def __init__(self, data_width=32, adr_width=30, **kwargs): + self.data_width = data_width + if kwargs.get("adr_width", False): + adr_width = kwargs["adr_width"] - int(log2(data_width//8)) + self.adr_width = adr_width + Record.__init__(self, set_layout_parameters(_layout, + adr_width = adr_width, + data_width = data_width, + sel_width = data_width//8)) + self.address.reset_less = True + self.writedata.reset_less = True + self.readdata.reset_less = True + self.byteenable.reset_less = True + + @staticmethod + def like(other): + return AvalonMMInterface(len(other.writedata)) + + def get_ios(self, bus_name="avl"): + subsignals = [] + for name, width, direction in self.layout: + subsignals.append(Subsignal(name, Pins(width))) + ios = [(bus_name , 0) + tuple(subsignals)] + return ios + + def connect_to_pads(self, pads, mode="master"): + assert mode in ["slave", "master"] + r = [] + for name, width, direction in self.layout: + sig = getattr(self, name) + pad = getattr(pads, name) + if mode == "master": + if direction == DIR_M_TO_S: + r.append(pad.eq(sig)) + else: + r.append(sig.eq(pad)) + else: + if direction == DIR_S_TO_M: + r.append(pad.eq(sig)) + else: + r.append(sig.eq(pad)) + return r + + def bus_read(self, address, byteenable=None, burstcount=1, chipselect=None): + if byteenable is None: + byteenable = 2**len(self.byteenable) - 1 + yield self.address.eq(address) + yield self.write.eq(0) + yield self.read.eq(1) + yield self.byteenable.eq(byteenable) + if burstcount != 1: + yield self.burstcount.eq(burstcount) + if chipselect is not None: + yield self.chipselect.eq(chipselect) + yield + while (yield self.waitrequest): + yield + yield self.read.eq(0) + # actually don't care outside of a transaction + # this makes the traces look neater + yield self.byteenable.eq(0) + if burstcount != 1: + yield self.burstcount.eq(0) + if chipselect is not None: + yield self.chipselect.eq(0) + + while not (yield self.readdatavalid): + yield + return (yield self.readdata) + + def continue_read_burst(self): + yield + return (yield self.readdata) + + def bus_write(self, address, writedata, byteenable=None, chipselect=None): + if not isinstance(writedata, list): + writedata = [ writedata ] + burstcount = len(writedata) + if byteenable is None: + byteenable = 2**len(self.byteenable) - 1 + yield self.address.eq(address) + yield self.write.eq(1) + yield self.read.eq(0) + yield self.byteenable.eq(byteenable) + if burstcount is not None: + yield self.burstcount.eq(burstcount) + if chipselect is not None: + yield self.chipselect.eq(chipselect) + for data in writedata: + yield self.writedata.eq(data) + yield + while (yield self.waitrequest): + yield + yield self.burstcount.eq(0) + yield self.writedata.eq(0) + yield self.write.eq(0) + # actually don't care outside of a transaction + # this makes the traces look neater + yield self.byteenable.eq(0) + if chipselect is not None: + yield self.chipselect.eq(0) + +class AvalonMM2Wishbone(Module): + def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, wishbone_extend_address_bits=0, avoid_combinatorial_loop=True): + word_width = data_width // 8 + word_width_bits = log2_int(word_width) + wishbone_address_width = address_width - word_width_bits + wishbone_extend_address_bits + + self.a2w_wb = wb = wishbone.Interface(data_width=data_width, adr_width=wishbone_address_width, bursting=True) + self.a2w_avl = avl = AvalonMMInterface (data_width=data_width, adr_width=address_width) + + read_access = Signal() + readdatavalid = Signal() + readdata = Signal(data_width) + + last_burst_cycle = Signal() + burst_cycle = Signal() + burst_counter = Signal.like(avl.burstcount) + burst_address = Signal(address_width) + burst_read = Signal() + burst_sel = Signal.like(avl.byteenable) + + self.sync += last_burst_cycle.eq(burst_cycle) + + # Some designs might have trouble with the combinatorial loop created + # by wb.ack, so cut it, incurring one clock cycle of overhead on each + # bus transaction + if avoid_combinatorial_loop: + self.sync += [ + If (wb.ack | wb.err, read_access.eq(0)) \ + .Elif(avl.read, read_access.eq(1)), + readdata.eq(wb.dat_r), + readdatavalid.eq((wb.ack | wb.err) & read_access), + ] + else: + self.comb += [ + read_access.eq(avl.read), + readdata.eq(wb.dat_r), + readdatavalid.eq((wb.ack | wb.err) & read_access), + ] + + # Wishbone -> Avalon + self.comb += [ + avl.waitrequest.eq(~(wb.ack | wb.err) | burst_read), + avl.readdata.eq(readdata), + avl.readdatavalid.eq(readdatavalid), + ] + + # Avalon -> Wishbone + self.comb += [ + # avalon is byte addresses, wishbone word addressed + wb.adr.eq(Mux(burst_cycle & last_burst_cycle, + burst_address, avl.address)[word_width_bits:] + + Constant(wishbone_base_address, (wishbone_address_width, 0))), + wb.dat_w.eq(avl.writedata), + wb.we.eq(avl.write), + wb.cyc.eq(read_access | avl.write | burst_cycle), + wb.stb.eq(read_access | avl.write), + wb.bte.eq(Constant(0, 2)), + ] + + self.submodules.fsm = fsm = FSM(reset_state="NORMAL") + fsm.act("NORMAL", + burst_cycle.eq(0), + wb.sel.eq(avl.byteenable), + wb.cti.eq(Mux(avl.burstcount > 1, + wishbone.CTI_BURST_INCREMENTING, + wishbone.CTI_BURST_NONE)), + If(~avl.waitrequest & (avl.burstcount > 1), + burst_cycle.eq(1), + NextValue(burst_counter, avl.burstcount - 1), + NextValue(burst_address, avl.address + word_width), + NextValue(burst_sel, avl.byteenable), + If(avl.write, NextState("BURST_WRITE")), + If(avl.read, + NextValue(burst_read, 1), + NextState("BURST_READ"))) + ) + fsm.act("BURST_WRITE", + burst_cycle.eq(1), + wb.sel.eq(burst_sel), + wb.cti.eq(Mux(burst_counter > 1, + wishbone.CTI_BURST_INCREMENTING, + Mux(burst_counter == 1, wishbone.CTI_BURST_END, wishbone.CTI_BURST_NONE))), + If(~avl.waitrequest, + NextValue(burst_address, burst_address + word_width), + NextValue(burst_counter, burst_counter - 1)), + If(burst_counter == 0, + burst_cycle.eq(0), + wb.sel.eq(avl.byteenable), + NextValue(burst_sel, 0), + NextState("NORMAL")) + ) + fsm.act("BURST_READ", # TODO + burst_cycle.eq(1), + wb.stb.eq(1), + wb.sel.eq(burst_sel), + wb.cti.eq(Mux(burst_counter > 1, + wishbone.CTI_BURST_INCREMENTING, + Mux(burst_counter == 1, wishbone.CTI_BURST_END, wishbone.CTI_BURST_NONE))), + If (wb.ack, + avl.readdatavalid.eq(1), + NextValue(burst_address, burst_address + word_width), + NextValue(burst_counter, burst_counter - 1)), + If (burst_counter == 0, + wb.cyc.eq(0), + wb.stb.eq(0), + wb.sel.eq(avl.byteenable), + NextValue(burst_sel, 0), + NextValue(burst_read, 0), + NextState("NORMAL")) + ) # Avalon-ST to/from native LiteX's stream ---------------------------------------------------------- diff --git a/test/test_avalon.py b/test/test_avalon.py new file mode 100644 index 000000000..4e7dbbd81 --- /dev/null +++ b/test/test_avalon.py @@ -0,0 +1,72 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Hans Baier +# SPDX-License-Identifier: BSD-2-Clause + +import unittest + +from migen import * + +from litex.soc.interconnect import wishbone, avalon + +# TestWishbone ------------------------------------------------------------------------------------- + +class TestAvalon2Wishbone(unittest.TestCase): + + def test_sram(self): + def generator(dut): + yield from dut.avl.bus_write(0x0000, 0x01234567) + yield from dut.avl.bus_write(0x0004, 0x89abcdef) + yield from dut.avl.bus_write(0x0008, 0xdeadbeef) + yield from dut.avl.bus_write(0x000c, 0xc0ffee00) + yield from dut.avl.bus_write(0x0010, 0x76543210) + yield + self.assertEqual((yield from dut.avl.bus_read(0x0000)), 0x01234567) + self.assertEqual((yield from dut.avl.bus_read(0x0004)), 0x89abcdef) + self.assertEqual((yield from dut.avl.bus_read(0x0008)), 0xdeadbeef) + self.assertEqual((yield from dut.avl.bus_read(0x000c)), 0xc0ffee00) + self.assertEqual((yield from dut.avl.bus_read(0x0010)), 0x76543210) + + class DUT(Module): + def __init__(self): + a2w = avalon.AvalonMM2Wishbone() + self.avl = a2w.a2w_avl + wishbone_mem = wishbone.SRAM(32, bus=a2w.a2w_wb) + self.submodules += a2w + self.submodules += wishbone_mem + + dut = DUT() + run_simulation(dut, generator(dut)) #, vcd_name="avalon.vcd") + + def test_sram_burst(self): + def generator(dut): + yield from dut.avl.bus_write(0x0, [0x01234567, 0x89abcdef, 0xdeadbeef, 0xc0ffee00, 0x76543210]) + yield + self.assertEqual((yield from dut.avl.bus_read(0x0000, burstcount=5)), 0x01234567) + self.assertEqual((yield from dut.avl.continue_read_burst()), 0x89abcdef) + self.assertEqual((yield from dut.avl.continue_read_burst()), 0xdeadbeef) + self.assertEqual((yield from dut.avl.continue_read_burst()), 0xc0ffee00) + self.assertEqual((yield from dut.avl.continue_read_burst()), 0x76543210) + yield + yield + yield + yield + self.assertEqual((yield from dut.avl.bus_read(0x0000)), 0x01234567) + self.assertEqual((yield from dut.avl.bus_read(0x0004)), 0x89abcdef) + self.assertEqual((yield from dut.avl.bus_read(0x0008)), 0xdeadbeef) + self.assertEqual((yield from dut.avl.bus_read(0x000c)), 0xc0ffee00) + self.assertEqual((yield from dut.avl.bus_read(0x0010)), 0x76543210) + yield + yield + + class DUT(Module): + def __init__(self): + a2w = avalon.AvalonMM2Wishbone() + self.avl = a2w.a2w_avl + wishbone_mem = wishbone.SRAM(32, bus=a2w.a2w_wb) + self.submodules += a2w + self.submodules += wishbone_mem + + dut = DUT() + run_simulation(dut, generator(dut)) #, vcd_name="avalon_burst.vcd") From 7071304b10cf924b45aa2620cc14bf400664cc01 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 09:14:35 +0200 Subject: [PATCH 016/454] soc/interconnect/avalon/AvalonMM: Do a first cosmetic cleanup pass. - Add separators. - Use coding style similar to other modules. - Replace the Mux with simpler If/Else constructs to improve understanding and readability. --- litex/soc/interconnect/avalon.py | 93 +++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/litex/soc/interconnect/avalon.py b/litex/soc/interconnect/avalon.py index 307b4b253..6e2c44ff2 100644 --- a/litex/soc/interconnect/avalon.py +++ b/litex/soc/interconnect/avalon.py @@ -12,6 +12,9 @@ from litex.soc.interconnect import stream from litex.soc.interconnect import wishbone + +# Avalon MM Layout --------------------------------------------------------------------------------- + _layout = [ ("address", "adr_width", DIR_M_TO_S), ("writedata", "data_width", DIR_M_TO_S), @@ -21,11 +24,13 @@ ("read", 1, DIR_M_TO_S), ("write", 1, DIR_M_TO_S), ("waitrequest", 1, DIR_S_TO_M), - ("burstbegin", 1, DIR_M_TO_S), # this is optional + ("burstbegin", 1, DIR_M_TO_S), # Optional. ("burstcount", 8, DIR_M_TO_S), - ("chipselect", 1, DIR_M_TO_S), # this is optional + ("chipselect", 1, DIR_M_TO_S), # Optional. ] +# Avalon MM Interface ------------------------------------------------------------------------------ + class AvalonMMInterface(Record): def __init__(self, data_width=32, adr_width=30, **kwargs): self.data_width = data_width @@ -85,8 +90,7 @@ def bus_read(self, address, byteenable=None, burstcount=1, chipselect=None): while (yield self.waitrequest): yield yield self.read.eq(0) - # actually don't care outside of a transaction - # this makes the traces look neater + # Actually don't care outside of a transaction this makes the traces look neater. yield self.byteenable.eq(0) if burstcount != 1: yield self.burstcount.eq(0) @@ -129,6 +133,8 @@ def bus_write(self, address, writedata, byteenable=None, chipselect=None): if chipselect is not None: yield self.chipselect.eq(0) +# Avalon MM <--> Wishbone Bridge ------------------------------------------------------------------- + class AvalonMM2Wishbone(Module): def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, wishbone_extend_address_bits=0, avoid_combinatorial_loop=True): word_width = data_width // 8 @@ -156,8 +162,11 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w # bus transaction if avoid_combinatorial_loop: self.sync += [ - If (wb.ack | wb.err, read_access.eq(0)) \ - .Elif(avl.read, read_access.eq(1)), + If(wb.ack | wb.err, + read_access.eq(0) + ).Elif(avl.read, + read_access.eq(1) + ), readdata.eq(wb.dat_r), readdatavalid.eq((wb.ack | wb.err) & read_access), ] @@ -177,40 +186,52 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w # Avalon -> Wishbone self.comb += [ - # avalon is byte addresses, wishbone word addressed - wb.adr.eq(Mux(burst_cycle & last_burst_cycle, - burst_address, avl.address)[word_width_bits:] - + Constant(wishbone_base_address, (wishbone_address_width, 0))), + # Avalon is byte addresses, Wishbone word addressed + If(burst_cycle & last_burst_cycle, + wb.adr.eq(burst_address[word_width_bits:] + wishbone_base_address) + ).Else( + wb.adr.eq(avl.address[word_width_bits:] + wishbone_base_address) + ), wb.dat_w.eq(avl.writedata), wb.we.eq(avl.write), wb.cyc.eq(read_access | avl.write | burst_cycle), wb.stb.eq(read_access | avl.write), - wb.bte.eq(Constant(0, 2)), + wb.bte.eq(0b00), ] - self.submodules.fsm = fsm = FSM(reset_state="NORMAL") - fsm.act("NORMAL", + self.submodules.fsm = fsm = FSM(reset_state="SINGLE") + fsm.act("SINGLE", burst_cycle.eq(0), wb.sel.eq(avl.byteenable), - wb.cti.eq(Mux(avl.burstcount > 1, - wishbone.CTI_BURST_INCREMENTING, - wishbone.CTI_BURST_NONE)), + If(avl.burstcount > 1, + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) + ).Else( + wb.cti.eq(wishbone.CTI_BURST_NONE) + ), If(~avl.waitrequest & (avl.burstcount > 1), burst_cycle.eq(1), NextValue(burst_counter, avl.burstcount - 1), NextValue(burst_address, avl.address + word_width), NextValue(burst_sel, avl.byteenable), - If(avl.write, NextState("BURST_WRITE")), + If(avl.write, + NextState("BURST-WRITE")), If(avl.read, NextValue(burst_read, 1), - NextState("BURST_READ"))) + NextState("BURST-READ")) + ) ) - fsm.act("BURST_WRITE", + fsm.act("BURST-WRITE", burst_cycle.eq(1), wb.sel.eq(burst_sel), - wb.cti.eq(Mux(burst_counter > 1, - wishbone.CTI_BURST_INCREMENTING, - Mux(burst_counter == 1, wishbone.CTI_BURST_END, wishbone.CTI_BURST_NONE))), + If(burst_counter > 1, + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) + ).Else( + If(burst_counter == 1, + wb.cti.eq(wishbone.CTI_BURST_END) + ).Else( + wb.cti.eq(wishbone.CTI_BURST_NONE) + ) + ), If(~avl.waitrequest, NextValue(burst_address, burst_address + word_width), NextValue(burst_counter, burst_counter - 1)), @@ -218,26 +239,34 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w burst_cycle.eq(0), wb.sel.eq(avl.byteenable), NextValue(burst_sel, 0), - NextState("NORMAL")) + NextState("SINGLE") + ) ) - fsm.act("BURST_READ", # TODO + fsm.act("BURST-READ", # TODO burst_cycle.eq(1), wb.stb.eq(1), wb.sel.eq(burst_sel), - wb.cti.eq(Mux(burst_counter > 1, - wishbone.CTI_BURST_INCREMENTING, - Mux(burst_counter == 1, wishbone.CTI_BURST_END, wishbone.CTI_BURST_NONE))), - If (wb.ack, + If(burst_counter > 1, + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), + ).Else( + If(burst_counter == 1, + wb.cti.eq(wishbone.CTI_BURST_END) + ).Else( + wb.cti.eq(wishbone.CTI_BURST_NONE) + ) + ), + If(wb.ack, avl.readdatavalid.eq(1), NextValue(burst_address, burst_address + word_width), - NextValue(burst_counter, burst_counter - 1)), - If (burst_counter == 0, + NextValue(burst_counter, burst_counter - 1) + ), + If(burst_counter == 0, wb.cyc.eq(0), wb.stb.eq(0), wb.sel.eq(avl.byteenable), - NextValue(burst_sel, 0), + NextValue(burst_sel, 0), NextValue(burst_read, 0), - NextState("NORMAL")) + NextState("SINGLE")) ) # Avalon-ST to/from native LiteX's stream ---------------------------------------------------------- From 8e1a3880d3a079b20fd40dbeec39be7852c864bd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 09:25:16 +0200 Subject: [PATCH 017/454] interconnect/avalon: Switch to directory/python package and split mm/st. Similarly to what is done for AXI and will avoid too complex/large files. --- litex/soc/interconnect/avalon.py | 312 ------------------ litex/soc/interconnect/avalon/__init__.py | 6 + litex/soc/interconnect/avalon/avalon_mm.py | 133 ++++++++ .../avalon/avalon_mm_to_wishbone.py | 149 +++++++++ litex/soc/interconnect/avalon/avalon_st.py | 53 +++ test/{test_avalon.py => test_avalon_mm.py} | 0 6 files changed, 341 insertions(+), 312 deletions(-) delete mode 100644 litex/soc/interconnect/avalon.py create mode 100644 litex/soc/interconnect/avalon/__init__.py create mode 100644 litex/soc/interconnect/avalon/avalon_mm.py create mode 100644 litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py create mode 100644 litex/soc/interconnect/avalon/avalon_st.py rename test/{test_avalon.py => test_avalon_mm.py} (100%) diff --git a/litex/soc/interconnect/avalon.py b/litex/soc/interconnect/avalon.py deleted file mode 100644 index 6e2c44ff2..000000000 --- a/litex/soc/interconnect/avalon.py +++ /dev/null @@ -1,312 +0,0 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2019-2020 Florent Kermarrec -# Copyright (c) 2023 Hans Baier -# SPDX-License-Identifier: BSD-2-Clause - -"""Avalon support for LiteX""" - -from migen import * - -from litex.soc.interconnect import stream -from litex.soc.interconnect import wishbone - - -# Avalon MM Layout --------------------------------------------------------------------------------- - -_layout = [ - ("address", "adr_width", DIR_M_TO_S), - ("writedata", "data_width", DIR_M_TO_S), - ("readdata", "data_width", DIR_S_TO_M), - ("readdatavalid", 1, DIR_S_TO_M), - ("byteenable", "sel_width", DIR_M_TO_S), - ("read", 1, DIR_M_TO_S), - ("write", 1, DIR_M_TO_S), - ("waitrequest", 1, DIR_S_TO_M), - ("burstbegin", 1, DIR_M_TO_S), # Optional. - ("burstcount", 8, DIR_M_TO_S), - ("chipselect", 1, DIR_M_TO_S), # Optional. -] - -# Avalon MM Interface ------------------------------------------------------------------------------ - -class AvalonMMInterface(Record): - def __init__(self, data_width=32, adr_width=30, **kwargs): - self.data_width = data_width - if kwargs.get("adr_width", False): - adr_width = kwargs["adr_width"] - int(log2(data_width//8)) - self.adr_width = adr_width - Record.__init__(self, set_layout_parameters(_layout, - adr_width = adr_width, - data_width = data_width, - sel_width = data_width//8)) - self.address.reset_less = True - self.writedata.reset_less = True - self.readdata.reset_less = True - self.byteenable.reset_less = True - - @staticmethod - def like(other): - return AvalonMMInterface(len(other.writedata)) - - def get_ios(self, bus_name="avl"): - subsignals = [] - for name, width, direction in self.layout: - subsignals.append(Subsignal(name, Pins(width))) - ios = [(bus_name , 0) + tuple(subsignals)] - return ios - - def connect_to_pads(self, pads, mode="master"): - assert mode in ["slave", "master"] - r = [] - for name, width, direction in self.layout: - sig = getattr(self, name) - pad = getattr(pads, name) - if mode == "master": - if direction == DIR_M_TO_S: - r.append(pad.eq(sig)) - else: - r.append(sig.eq(pad)) - else: - if direction == DIR_S_TO_M: - r.append(pad.eq(sig)) - else: - r.append(sig.eq(pad)) - return r - - def bus_read(self, address, byteenable=None, burstcount=1, chipselect=None): - if byteenable is None: - byteenable = 2**len(self.byteenable) - 1 - yield self.address.eq(address) - yield self.write.eq(0) - yield self.read.eq(1) - yield self.byteenable.eq(byteenable) - if burstcount != 1: - yield self.burstcount.eq(burstcount) - if chipselect is not None: - yield self.chipselect.eq(chipselect) - yield - while (yield self.waitrequest): - yield - yield self.read.eq(0) - # Actually don't care outside of a transaction this makes the traces look neater. - yield self.byteenable.eq(0) - if burstcount != 1: - yield self.burstcount.eq(0) - if chipselect is not None: - yield self.chipselect.eq(0) - - while not (yield self.readdatavalid): - yield - return (yield self.readdata) - - def continue_read_burst(self): - yield - return (yield self.readdata) - - def bus_write(self, address, writedata, byteenable=None, chipselect=None): - if not isinstance(writedata, list): - writedata = [ writedata ] - burstcount = len(writedata) - if byteenable is None: - byteenable = 2**len(self.byteenable) - 1 - yield self.address.eq(address) - yield self.write.eq(1) - yield self.read.eq(0) - yield self.byteenable.eq(byteenable) - if burstcount is not None: - yield self.burstcount.eq(burstcount) - if chipselect is not None: - yield self.chipselect.eq(chipselect) - for data in writedata: - yield self.writedata.eq(data) - yield - while (yield self.waitrequest): - yield - yield self.burstcount.eq(0) - yield self.writedata.eq(0) - yield self.write.eq(0) - # actually don't care outside of a transaction - # this makes the traces look neater - yield self.byteenable.eq(0) - if chipselect is not None: - yield self.chipselect.eq(0) - -# Avalon MM <--> Wishbone Bridge ------------------------------------------------------------------- - -class AvalonMM2Wishbone(Module): - def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, wishbone_extend_address_bits=0, avoid_combinatorial_loop=True): - word_width = data_width // 8 - word_width_bits = log2_int(word_width) - wishbone_address_width = address_width - word_width_bits + wishbone_extend_address_bits - - self.a2w_wb = wb = wishbone.Interface(data_width=data_width, adr_width=wishbone_address_width, bursting=True) - self.a2w_avl = avl = AvalonMMInterface (data_width=data_width, adr_width=address_width) - - read_access = Signal() - readdatavalid = Signal() - readdata = Signal(data_width) - - last_burst_cycle = Signal() - burst_cycle = Signal() - burst_counter = Signal.like(avl.burstcount) - burst_address = Signal(address_width) - burst_read = Signal() - burst_sel = Signal.like(avl.byteenable) - - self.sync += last_burst_cycle.eq(burst_cycle) - - # Some designs might have trouble with the combinatorial loop created - # by wb.ack, so cut it, incurring one clock cycle of overhead on each - # bus transaction - if avoid_combinatorial_loop: - self.sync += [ - If(wb.ack | wb.err, - read_access.eq(0) - ).Elif(avl.read, - read_access.eq(1) - ), - readdata.eq(wb.dat_r), - readdatavalid.eq((wb.ack | wb.err) & read_access), - ] - else: - self.comb += [ - read_access.eq(avl.read), - readdata.eq(wb.dat_r), - readdatavalid.eq((wb.ack | wb.err) & read_access), - ] - - # Wishbone -> Avalon - self.comb += [ - avl.waitrequest.eq(~(wb.ack | wb.err) | burst_read), - avl.readdata.eq(readdata), - avl.readdatavalid.eq(readdatavalid), - ] - - # Avalon -> Wishbone - self.comb += [ - # Avalon is byte addresses, Wishbone word addressed - If(burst_cycle & last_burst_cycle, - wb.adr.eq(burst_address[word_width_bits:] + wishbone_base_address) - ).Else( - wb.adr.eq(avl.address[word_width_bits:] + wishbone_base_address) - ), - wb.dat_w.eq(avl.writedata), - wb.we.eq(avl.write), - wb.cyc.eq(read_access | avl.write | burst_cycle), - wb.stb.eq(read_access | avl.write), - wb.bte.eq(0b00), - ] - - self.submodules.fsm = fsm = FSM(reset_state="SINGLE") - fsm.act("SINGLE", - burst_cycle.eq(0), - wb.sel.eq(avl.byteenable), - If(avl.burstcount > 1, - wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) - ).Else( - wb.cti.eq(wishbone.CTI_BURST_NONE) - ), - If(~avl.waitrequest & (avl.burstcount > 1), - burst_cycle.eq(1), - NextValue(burst_counter, avl.burstcount - 1), - NextValue(burst_address, avl.address + word_width), - NextValue(burst_sel, avl.byteenable), - If(avl.write, - NextState("BURST-WRITE")), - If(avl.read, - NextValue(burst_read, 1), - NextState("BURST-READ")) - ) - ) - fsm.act("BURST-WRITE", - burst_cycle.eq(1), - wb.sel.eq(burst_sel), - If(burst_counter > 1, - wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) - ).Else( - If(burst_counter == 1, - wb.cti.eq(wishbone.CTI_BURST_END) - ).Else( - wb.cti.eq(wishbone.CTI_BURST_NONE) - ) - ), - If(~avl.waitrequest, - NextValue(burst_address, burst_address + word_width), - NextValue(burst_counter, burst_counter - 1)), - If(burst_counter == 0, - burst_cycle.eq(0), - wb.sel.eq(avl.byteenable), - NextValue(burst_sel, 0), - NextState("SINGLE") - ) - ) - fsm.act("BURST-READ", # TODO - burst_cycle.eq(1), - wb.stb.eq(1), - wb.sel.eq(burst_sel), - If(burst_counter > 1, - wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), - ).Else( - If(burst_counter == 1, - wb.cti.eq(wishbone.CTI_BURST_END) - ).Else( - wb.cti.eq(wishbone.CTI_BURST_NONE) - ) - ), - If(wb.ack, - avl.readdatavalid.eq(1), - NextValue(burst_address, burst_address + word_width), - NextValue(burst_counter, burst_counter - 1) - ), - If(burst_counter == 0, - wb.cyc.eq(0), - wb.stb.eq(0), - wb.sel.eq(avl.byteenable), - NextValue(burst_sel, 0), - NextValue(burst_read, 0), - NextState("SINGLE")) - ) - -# Avalon-ST to/from native LiteX's stream ---------------------------------------------------------- - -# In native LiteX's streams, ready signal has no latency (similar to AXI). In Avalon-ST streams the -# ready signal has a latency: If ready is asserted on cycle n, then cycle n + latency is a "ready" -# in the LiteX/AXI's sense) cycle. This means that: -# - when converting to Avalon-ST, we need to add this latency on datas. -# - when converting from Avalon-ST, we need to make sure we are able to store datas for "latency" -# cycles after ready deassertion on the native interface. - -class Native2AvalonST(Module): - """Native LiteX's stream to Avalon-ST stream""" - def __init__(self, layout, latency=2): - self.sink = sink = stream.Endpoint(layout) - self.source = source = stream.Endpoint(layout) - - # # # - - _from = sink - for n in range(latency): - _to = stream.Endpoint(layout) - self.sync += _from.connect(_to, omit={"ready"}) - if n == 0: - self.sync += _to.valid.eq(sink.valid & source.ready) - _from = _to - self.comb += _to.connect(source, omit={"ready"}) - self.comb += sink.ready.eq(source.ready) - - -class AvalonST2Native(Module): - """Avalon-ST Stream to native LiteX's stream""" - def __init__(self, layout, latency=2): - self.sink = sink = stream.Endpoint(layout) - self.source = source = stream.Endpoint(layout) - - # # # - - buf = stream.SyncFIFO(layout, latency) - self.submodules += buf - self.comb += sink.connect(buf.sink, omit={"ready"}) - self.comb += sink.ready.eq(source.ready) - self.comb += buf.source.connect(source) diff --git a/litex/soc/interconnect/avalon/__init__.py b/litex/soc/interconnect/avalon/__init__.py new file mode 100644 index 000000000..1dac2b0b6 --- /dev/null +++ b/litex/soc/interconnect/avalon/__init__.py @@ -0,0 +1,6 @@ +# Avalon MM. +from litex.soc.interconnect.avalon.avalon_mm import AvalonMMInterface +from litex.soc.interconnect.avalon.avalon_mm_to_wishbone import AvalonMM2Wishbone + +# Avalon ST. +from litex.soc.interconnect.avalon.avalon_st import Native2AvalonST, AvalonST2Native \ No newline at end of file diff --git a/litex/soc/interconnect/avalon/avalon_mm.py b/litex/soc/interconnect/avalon/avalon_mm.py new file mode 100644 index 000000000..1fef0a9fe --- /dev/null +++ b/litex/soc/interconnect/avalon/avalon_mm.py @@ -0,0 +1,133 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Hans Baier +# Copyright (c) 2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +"""Avalon support for LiteX""" + +from migen import * + +from litex.soc.interconnect import stream +from litex.soc.interconnect import wishbone + +# Avalon MM Layout --------------------------------------------------------------------------------- + +_layout = [ + ("address", "adr_width", DIR_M_TO_S), + ("writedata", "data_width", DIR_M_TO_S), + ("readdata", "data_width", DIR_S_TO_M), + ("readdatavalid", 1, DIR_S_TO_M), + ("byteenable", "sel_width", DIR_M_TO_S), + ("read", 1, DIR_M_TO_S), + ("write", 1, DIR_M_TO_S), + ("waitrequest", 1, DIR_S_TO_M), + ("burstbegin", 1, DIR_M_TO_S), # Optional. + ("burstcount", 8, DIR_M_TO_S), + ("chipselect", 1, DIR_M_TO_S), # Optional. +] + +# Avalon MM Interface ------------------------------------------------------------------------------ + +class AvalonMMInterface(Record): + def __init__(self, data_width=32, adr_width=30, **kwargs): + self.data_width = data_width + if kwargs.get("adr_width", False): + adr_width = kwargs["adr_width"] - int(log2(data_width//8)) + self.adr_width = adr_width + Record.__init__(self, set_layout_parameters(_layout, + adr_width = adr_width, + data_width = data_width, + sel_width = data_width//8)) + self.address.reset_less = True + self.writedata.reset_less = True + self.readdata.reset_less = True + self.byteenable.reset_less = True + + @staticmethod + def like(other): + return AvalonMMInterface(len(other.writedata)) + + def get_ios(self, bus_name="avl"): + subsignals = [] + for name, width, direction in self.layout: + subsignals.append(Subsignal(name, Pins(width))) + ios = [(bus_name , 0) + tuple(subsignals)] + return ios + + def connect_to_pads(self, pads, mode="master"): + assert mode in ["slave", "master"] + r = [] + for name, width, direction in self.layout: + sig = getattr(self, name) + pad = getattr(pads, name) + if mode == "master": + if direction == DIR_M_TO_S: + r.append(pad.eq(sig)) + else: + r.append(sig.eq(pad)) + else: + if direction == DIR_S_TO_M: + r.append(pad.eq(sig)) + else: + r.append(sig.eq(pad)) + return r + + def bus_read(self, address, byteenable=None, burstcount=1, chipselect=None): + if byteenable is None: + byteenable = 2**len(self.byteenable) - 1 + yield self.address.eq(address) + yield self.write.eq(0) + yield self.read.eq(1) + yield self.byteenable.eq(byteenable) + if burstcount != 1: + yield self.burstcount.eq(burstcount) + if chipselect is not None: + yield self.chipselect.eq(chipselect) + yield + while (yield self.waitrequest): + yield + yield self.read.eq(0) + # Actually don't care outside of a transaction this makes the traces look neater. + yield self.byteenable.eq(0) + if burstcount != 1: + yield self.burstcount.eq(0) + if chipselect is not None: + yield self.chipselect.eq(0) + + while not (yield self.readdatavalid): + yield + return (yield self.readdata) + + def continue_read_burst(self): + yield + return (yield self.readdata) + + def bus_write(self, address, writedata, byteenable=None, chipselect=None): + if not isinstance(writedata, list): + writedata = [ writedata ] + burstcount = len(writedata) + if byteenable is None: + byteenable = 2**len(self.byteenable) - 1 + yield self.address.eq(address) + yield self.write.eq(1) + yield self.read.eq(0) + yield self.byteenable.eq(byteenable) + if burstcount is not None: + yield self.burstcount.eq(burstcount) + if chipselect is not None: + yield self.chipselect.eq(chipselect) + for data in writedata: + yield self.writedata.eq(data) + yield + while (yield self.waitrequest): + yield + yield self.burstcount.eq(0) + yield self.writedata.eq(0) + yield self.write.eq(0) + # actually don't care outside of a transaction + # this makes the traces look neater + yield self.byteenable.eq(0) + if chipselect is not None: + yield self.chipselect.eq(0) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py new file mode 100644 index 000000000..9d2dcce0b --- /dev/null +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -0,0 +1,149 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Hans Baier +# Copyright (c) 2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +"""Avalon support for LiteX""" + +from migen import * + +from litex.soc.interconnect import wishbone +from litex.soc.interconnect.avalon import AvalonMMInterface + +# Avalon MM <--> Wishbone Bridge ------------------------------------------------------------------- + +class AvalonMM2Wishbone(Module): + def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, wishbone_extend_address_bits=0, avoid_combinatorial_loop=True): + word_width = data_width // 8 + word_width_bits = log2_int(word_width) + wishbone_address_width = address_width - word_width_bits + wishbone_extend_address_bits + + self.a2w_wb = wb = wishbone.Interface(data_width=data_width, adr_width=wishbone_address_width, bursting=True) + self.a2w_avl = avl = AvalonMMInterface (data_width=data_width, adr_width=address_width) + + read_access = Signal() + readdatavalid = Signal() + readdata = Signal(data_width) + + last_burst_cycle = Signal() + burst_cycle = Signal() + burst_counter = Signal.like(avl.burstcount) + burst_address = Signal(address_width) + burst_read = Signal() + burst_sel = Signal.like(avl.byteenable) + + self.sync += last_burst_cycle.eq(burst_cycle) + + # Some designs might have trouble with the combinatorial loop created + # by wb.ack, so cut it, incurring one clock cycle of overhead on each + # bus transaction + if avoid_combinatorial_loop: + self.sync += [ + If(wb.ack | wb.err, + read_access.eq(0) + ).Elif(avl.read, + read_access.eq(1) + ), + readdata.eq(wb.dat_r), + readdatavalid.eq((wb.ack | wb.err) & read_access), + ] + else: + self.comb += [ + read_access.eq(avl.read), + readdata.eq(wb.dat_r), + readdatavalid.eq((wb.ack | wb.err) & read_access), + ] + + # Wishbone -> Avalon + self.comb += [ + avl.waitrequest.eq(~(wb.ack | wb.err) | burst_read), + avl.readdata.eq(readdata), + avl.readdatavalid.eq(readdatavalid), + ] + + # Avalon -> Wishbone + self.comb += [ + # Avalon is byte addresses, Wishbone word addressed + If(burst_cycle & last_burst_cycle, + wb.adr.eq(burst_address[word_width_bits:] + wishbone_base_address) + ).Else( + wb.adr.eq(avl.address[word_width_bits:] + wishbone_base_address) + ), + wb.dat_w.eq(avl.writedata), + wb.we.eq(avl.write), + wb.cyc.eq(read_access | avl.write | burst_cycle), + wb.stb.eq(read_access | avl.write), + wb.bte.eq(0b00), + ] + + self.submodules.fsm = fsm = FSM(reset_state="SINGLE") + fsm.act("SINGLE", + burst_cycle.eq(0), + wb.sel.eq(avl.byteenable), + If(avl.burstcount > 1, + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) + ).Else( + wb.cti.eq(wishbone.CTI_BURST_NONE) + ), + If(~avl.waitrequest & (avl.burstcount > 1), + burst_cycle.eq(1), + NextValue(burst_counter, avl.burstcount - 1), + NextValue(burst_address, avl.address + word_width), + NextValue(burst_sel, avl.byteenable), + If(avl.write, + NextState("BURST-WRITE")), + If(avl.read, + NextValue(burst_read, 1), + NextState("BURST-READ")) + ) + ) + fsm.act("BURST-WRITE", + burst_cycle.eq(1), + wb.sel.eq(burst_sel), + If(burst_counter > 1, + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) + ).Else( + If(burst_counter == 1, + wb.cti.eq(wishbone.CTI_BURST_END) + ).Else( + wb.cti.eq(wishbone.CTI_BURST_NONE) + ) + ), + If(~avl.waitrequest, + NextValue(burst_address, burst_address + word_width), + NextValue(burst_counter, burst_counter - 1)), + If(burst_counter == 0, + burst_cycle.eq(0), + wb.sel.eq(avl.byteenable), + NextValue(burst_sel, 0), + NextState("SINGLE") + ) + ) + fsm.act("BURST-READ", # TODO + burst_cycle.eq(1), + wb.stb.eq(1), + wb.sel.eq(burst_sel), + If(burst_counter > 1, + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), + ).Else( + If(burst_counter == 1, + wb.cti.eq(wishbone.CTI_BURST_END) + ).Else( + wb.cti.eq(wishbone.CTI_BURST_NONE) + ) + ), + If(wb.ack, + avl.readdatavalid.eq(1), + NextValue(burst_address, burst_address + word_width), + NextValue(burst_counter, burst_counter - 1) + ), + If(burst_counter == 0, + wb.cyc.eq(0), + wb.stb.eq(0), + wb.sel.eq(avl.byteenable), + NextValue(burst_sel, 0), + NextValue(burst_read, 0), + NextState("SINGLE")) + ) diff --git a/litex/soc/interconnect/avalon/avalon_st.py b/litex/soc/interconnect/avalon/avalon_st.py new file mode 100644 index 000000000..726ef39af --- /dev/null +++ b/litex/soc/interconnect/avalon/avalon_st.py @@ -0,0 +1,53 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2019-2020 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +"""Avalon ST support for LiteX""" + +from migen import * + +from litex.soc.interconnect import stream + +# Avalon-ST to/from native LiteX's stream ---------------------------------------------------------- + +# In native LiteX's streams, ready signal has no latency (similar to AXI). In Avalon-ST streams the +# ready signal has a latency: If ready is asserted on cycle n, then cycle n + latency is a "ready" +# in the LiteX/AXI's sense) cycle. This means that: +# - when converting to Avalon-ST, we need to add this latency on datas. +# - when converting from Avalon-ST, we need to make sure we are able to store datas for "latency" +# cycles after ready deassertion on the native interface. + +class Native2AvalonST(Module): + """Native LiteX's stream to Avalon-ST stream""" + def __init__(self, layout, latency=2): + self.sink = sink = stream.Endpoint(layout) + self.source = source = stream.Endpoint(layout) + + # # # + + _from = sink + for n in range(latency): + _to = stream.Endpoint(layout) + self.sync += _from.connect(_to, omit={"ready"}) + if n == 0: + self.sync += _to.valid.eq(sink.valid & source.ready) + _from = _to + self.comb += _to.connect(source, omit={"ready"}) + self.comb += sink.ready.eq(source.ready) + + +class AvalonST2Native(Module): + """Avalon-ST Stream to native LiteX's stream""" + def __init__(self, layout, latency=2): + self.sink = sink = stream.Endpoint(layout) + self.source = source = stream.Endpoint(layout) + + # # # + + buf = stream.SyncFIFO(layout, latency) + self.submodules += buf + self.comb += sink.connect(buf.sink, omit={"ready"}) + self.comb += sink.ready.eq(source.ready) + self.comb += buf.source.connect(source) diff --git a/test/test_avalon.py b/test/test_avalon_mm.py similarity index 100% rename from test/test_avalon.py rename to test/test_avalon_mm.py From 451fb8d378297392b7f9171f08ce3602ab35b17e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 09:27:05 +0200 Subject: [PATCH 018/454] avalon/AvalonMM2Wishbone: Directly set burst_read in BURST-READ state. --- litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 9d2dcce0b..70825f4bb 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -95,7 +95,6 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w If(avl.write, NextState("BURST-WRITE")), If(avl.read, - NextValue(burst_read, 1), NextState("BURST-READ")) ) ) @@ -123,6 +122,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w ) fsm.act("BURST-READ", # TODO burst_cycle.eq(1), + burst_read.eq(1), wb.stb.eq(1), wb.sel.eq(burst_sel), If(burst_counter > 1, @@ -144,6 +144,5 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w wb.stb.eq(0), wb.sel.eq(avl.byteenable), NextValue(burst_sel, 0), - NextValue(burst_read, 0), NextState("SINGLE")) ) From a62149831deb01b83287c54adcf70bf86431215a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 09:29:02 +0200 Subject: [PATCH 019/454] avalon/AvalonMM2Wishbone: Avoid reseting burst_set (not useful since always set before use). --- litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 70825f4bb..6d7a85390 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -116,7 +116,6 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w If(burst_counter == 0, burst_cycle.eq(0), wb.sel.eq(avl.byteenable), - NextValue(burst_sel, 0), NextState("SINGLE") ) ) @@ -143,6 +142,5 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w wb.cyc.eq(0), wb.stb.eq(0), wb.sel.eq(avl.byteenable), - NextValue(burst_sel, 0), NextState("SINGLE")) ) From 9f44a498d6a0bdbff363228844eb88fbdedb1cac Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 09:42:12 +0200 Subject: [PATCH 020/454] avalon/AvalonMM2Wishbone: Simplify wb.cti. In BURST-WRITE/READ, wb.cti can't be BURST_NONE. --- .../avalon/avalon_mm_to_wishbone.py | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 6d7a85390..31bd78e00 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -82,10 +82,9 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w fsm.act("SINGLE", burst_cycle.eq(0), wb.sel.eq(avl.byteenable), + wb.cti.eq(wishbone.CTI_BURST_NONE), If(avl.burstcount > 1, wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) - ).Else( - wb.cti.eq(wishbone.CTI_BURST_NONE) ), If(~avl.waitrequest & (avl.burstcount > 1), burst_cycle.eq(1), @@ -101,14 +100,9 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w fsm.act("BURST-WRITE", burst_cycle.eq(1), wb.sel.eq(burst_sel), - If(burst_counter > 1, - wb.cti.eq(wishbone.CTI_BURST_INCREMENTING) - ).Else( - If(burst_counter == 1, - wb.cti.eq(wishbone.CTI_BURST_END) - ).Else( - wb.cti.eq(wishbone.CTI_BURST_NONE) - ) + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), + If(burst_counter == 1, + wb.cti.eq(wishbone.CTI_BURST_END) ), If(~avl.waitrequest, NextValue(burst_address, burst_address + word_width), @@ -124,14 +118,9 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w burst_read.eq(1), wb.stb.eq(1), wb.sel.eq(burst_sel), - If(burst_counter > 1, - wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), - ).Else( - If(burst_counter == 1, - wb.cti.eq(wishbone.CTI_BURST_END) - ).Else( - wb.cti.eq(wishbone.CTI_BURST_NONE) - ) + wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), + If(burst_counter == 1, + wb.cti.eq(wishbone.CTI_BURST_END) ), If(wb.ack, avl.readdatavalid.eq(1), From f7ee9fad9663760b9e7efc2c0ea60a1a546f2321 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 09:57:35 +0200 Subject: [PATCH 021/454] avalon/AvalonMM2Wishbone: Do other cosmetic changes. --- .../avalon/avalon_mm_to_wishbone.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 31bd78e00..bd5bfcfcc 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -27,14 +27,14 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w readdatavalid = Signal() readdata = Signal(data_width) - last_burst_cycle = Signal() burst_cycle = Signal() - burst_counter = Signal.like(avl.burstcount) + burst_cycle_last = Signal() + burst_count = Signal(len(avl.burstcount)) burst_address = Signal(address_width) burst_read = Signal() - burst_sel = Signal.like(avl.byteenable) + burst_sel = Signal(len(avl.byteenable)) - self.sync += last_burst_cycle.eq(burst_cycle) + self.sync += burst_cycle_last.eq(burst_cycle) # Some designs might have trouble with the combinatorial loop created # by wb.ack, so cut it, incurring one clock cycle of overhead on each @@ -66,10 +66,9 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w # Avalon -> Wishbone self.comb += [ # Avalon is byte addresses, Wishbone word addressed - If(burst_cycle & last_burst_cycle, + wb.adr.eq(avl.address[word_width_bits:] + wishbone_base_address), + If(burst_cycle & burst_cycle_last, wb.adr.eq(burst_address[word_width_bits:] + wishbone_base_address) - ).Else( - wb.adr.eq(avl.address[word_width_bits:] + wishbone_base_address) ), wb.dat_w.eq(avl.writedata), wb.we.eq(avl.write), @@ -88,46 +87,48 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w ), If(~avl.waitrequest & (avl.burstcount > 1), burst_cycle.eq(1), - NextValue(burst_counter, avl.burstcount - 1), + NextValue(burst_count, avl.burstcount - 1), NextValue(burst_address, avl.address + word_width), NextValue(burst_sel, avl.byteenable), If(avl.write, - NextState("BURST-WRITE")), + NextState("BURST-WRITE") + ), If(avl.read, - NextState("BURST-READ")) + NextState("BURST-READ") ) + ) ) fsm.act("BURST-WRITE", burst_cycle.eq(1), wb.sel.eq(burst_sel), wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), - If(burst_counter == 1, + If(burst_count == 1, wb.cti.eq(wishbone.CTI_BURST_END) ), If(~avl.waitrequest, NextValue(burst_address, burst_address + word_width), - NextValue(burst_counter, burst_counter - 1)), - If(burst_counter == 0, + NextValue(burst_count, burst_count - 1)), + If(burst_count == 0, burst_cycle.eq(0), wb.sel.eq(avl.byteenable), NextState("SINGLE") ) ) - fsm.act("BURST-READ", # TODO + fsm.act("BURST-READ", burst_cycle.eq(1), burst_read.eq(1), wb.stb.eq(1), wb.sel.eq(burst_sel), wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), - If(burst_counter == 1, + If(burst_count == 1, wb.cti.eq(wishbone.CTI_BURST_END) ), If(wb.ack, avl.readdatavalid.eq(1), NextValue(burst_address, burst_address + word_width), - NextValue(burst_counter, burst_counter - 1) + NextValue(burst_count, burst_count - 1) ), - If(burst_counter == 0, + If(burst_count == 0, wb.cyc.eq(0), wb.stb.eq(0), wb.sel.eq(avl.byteenable), From dd40c25b2305c91c064d136910d9e32576482163 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 10:02:40 +0200 Subject: [PATCH 022/454] avalon/AvalonMM2Wishbone: Fix write byteenable/sel. From mnl_avalon_spec.pdf: "The byteenables can change for different words of the burst." --- litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index bd5bfcfcc..f05cef331 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -32,7 +32,6 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w burst_count = Signal(len(avl.burstcount)) burst_address = Signal(address_width) burst_read = Signal() - burst_sel = Signal(len(avl.byteenable)) self.sync += burst_cycle_last.eq(burst_cycle) @@ -89,7 +88,6 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w burst_cycle.eq(1), NextValue(burst_count, avl.burstcount - 1), NextValue(burst_address, avl.address + word_width), - NextValue(burst_sel, avl.byteenable), If(avl.write, NextState("BURST-WRITE") ), @@ -100,7 +98,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w ) fsm.act("BURST-WRITE", burst_cycle.eq(1), - wb.sel.eq(burst_sel), + wb.sel.eq(avl.byteenable), wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), If(burst_count == 1, wb.cti.eq(wishbone.CTI_BURST_END) @@ -110,7 +108,6 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w NextValue(burst_count, burst_count - 1)), If(burst_count == 0, burst_cycle.eq(0), - wb.sel.eq(avl.byteenable), NextState("SINGLE") ) ) @@ -118,7 +115,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w burst_cycle.eq(1), burst_read.eq(1), wb.stb.eq(1), - wb.sel.eq(burst_sel), + wb.sel.eq(2**len(wb.sel) - 1), wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), If(burst_count == 1, wb.cti.eq(wishbone.CTI_BURST_END) @@ -131,6 +128,5 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w If(burst_count == 0, wb.cyc.eq(0), wb.stb.eq(0), - wb.sel.eq(avl.byteenable), NextState("SINGLE")) ) From 3c03b6f5e485c918ad1d6238fd0d6b96d48d5339 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 10:18:56 +0200 Subject: [PATCH 023/454] avalon/AvalonMM2Wishbone: Fix avl.readdatavalid. Multi-driven, remove assign in BURST-READ. --- litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index f05cef331..5a75157c0 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -105,7 +105,8 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w ), If(~avl.waitrequest, NextValue(burst_address, burst_address + word_width), - NextValue(burst_count, burst_count - 1)), + NextValue(burst_count, burst_count - 1), + ), If(burst_count == 0, burst_cycle.eq(0), NextState("SINGLE") @@ -121,7 +122,6 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w wb.cti.eq(wishbone.CTI_BURST_END) ), If(wb.ack, - avl.readdatavalid.eq(1), NextValue(burst_address, burst_address + word_width), NextValue(burst_count, burst_count - 1) ), From 3ab7ebe5367f716a2103d17086934bb999649063 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 8 May 2023 10:59:17 +0200 Subject: [PATCH 024/454] CHANGES.md: Release 2023.04. --- CHANGES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6065555d5..73c4d324b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,5 @@ -[> Changes since 2022.12 ------------------------- +[> 2023.04, released on May 8th 2023 +------------------------------------ [> Fixed -------- From f00eb4e1129656c9cbac1123d5cfe6520c5c2978 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 9 May 2023 15:26:27 +0700 Subject: [PATCH 025/454] AvalonMM2Wishbone: use same addressing on avalon and wishbone, leave address translation to the user --- .../avalon/avalon_mm_to_wishbone.py | 21 +++++++--------- test/test_avalon_mm.py | 24 +++++++++---------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 5a75157c0..29d22bf30 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -15,13 +15,9 @@ # Avalon MM <--> Wishbone Bridge ------------------------------------------------------------------- class AvalonMM2Wishbone(Module): - def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, wishbone_extend_address_bits=0, avoid_combinatorial_loop=True): - word_width = data_width // 8 - word_width_bits = log2_int(word_width) - wishbone_address_width = address_width - word_width_bits + wishbone_extend_address_bits - + def __init__(self, data_width=32, avalon_address_width=32, wishbone_address_width=32, wishbone_base_address=0x0, burst_increment=1, avoid_combinatorial_loop=True): + self.a2w_avl = avl = AvalonMMInterface (data_width=data_width, adr_width=avalon_address_width) self.a2w_wb = wb = wishbone.Interface(data_width=data_width, adr_width=wishbone_address_width, bursting=True) - self.a2w_avl = avl = AvalonMMInterface (data_width=data_width, adr_width=address_width) read_access = Signal() readdatavalid = Signal() @@ -30,7 +26,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w burst_cycle = Signal() burst_cycle_last = Signal() burst_count = Signal(len(avl.burstcount)) - burst_address = Signal(address_width) + burst_address = Signal(wishbone_address_width) burst_read = Signal() self.sync += burst_cycle_last.eq(burst_cycle) @@ -65,9 +61,9 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w # Avalon -> Wishbone self.comb += [ # Avalon is byte addresses, Wishbone word addressed - wb.adr.eq(avl.address[word_width_bits:] + wishbone_base_address), + wb.adr.eq(avl.address + wishbone_base_address), If(burst_cycle & burst_cycle_last, - wb.adr.eq(burst_address[word_width_bits:] + wishbone_base_address) + wb.adr.eq(burst_address + wishbone_base_address) ), wb.dat_w.eq(avl.writedata), wb.we.eq(avl.write), @@ -87,7 +83,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w If(~avl.waitrequest & (avl.burstcount > 1), burst_cycle.eq(1), NextValue(burst_count, avl.burstcount - 1), - NextValue(burst_address, avl.address + word_width), + NextValue(burst_address, avl.address + burst_increment), If(avl.write, NextState("BURST-WRITE") ), @@ -104,7 +100,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w wb.cti.eq(wishbone.CTI_BURST_END) ), If(~avl.waitrequest, - NextValue(burst_address, burst_address + word_width), + NextValue(burst_address, burst_address + burst_increment), NextValue(burst_count, burst_count - 1), ), If(burst_count == 0, @@ -122,7 +118,8 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w wb.cti.eq(wishbone.CTI_BURST_END) ), If(wb.ack, - NextValue(burst_address, burst_address + word_width), + avl.readdatavalid.eq(1), + NextValue(burst_address, burst_address + burst_increment), NextValue(burst_count, burst_count - 1) ), If(burst_count == 0, diff --git a/test/test_avalon_mm.py b/test/test_avalon_mm.py index 4e7dbbd81..87723a8e7 100644 --- a/test/test_avalon_mm.py +++ b/test/test_avalon_mm.py @@ -17,16 +17,16 @@ class TestAvalon2Wishbone(unittest.TestCase): def test_sram(self): def generator(dut): yield from dut.avl.bus_write(0x0000, 0x01234567) - yield from dut.avl.bus_write(0x0004, 0x89abcdef) - yield from dut.avl.bus_write(0x0008, 0xdeadbeef) - yield from dut.avl.bus_write(0x000c, 0xc0ffee00) - yield from dut.avl.bus_write(0x0010, 0x76543210) + yield from dut.avl.bus_write(0x0001, 0x89abcdef) + yield from dut.avl.bus_write(0x0002, 0xdeadbeef) + yield from dut.avl.bus_write(0x0003, 0xc0ffee00) + yield from dut.avl.bus_write(0x0004, 0x76543210) yield self.assertEqual((yield from dut.avl.bus_read(0x0000)), 0x01234567) - self.assertEqual((yield from dut.avl.bus_read(0x0004)), 0x89abcdef) - self.assertEqual((yield from dut.avl.bus_read(0x0008)), 0xdeadbeef) - self.assertEqual((yield from dut.avl.bus_read(0x000c)), 0xc0ffee00) - self.assertEqual((yield from dut.avl.bus_read(0x0010)), 0x76543210) + self.assertEqual((yield from dut.avl.bus_read(0x0001)), 0x89abcdef) + self.assertEqual((yield from dut.avl.bus_read(0x0002)), 0xdeadbeef) + self.assertEqual((yield from dut.avl.bus_read(0x0003)), 0xc0ffee00) + self.assertEqual((yield from dut.avl.bus_read(0x0004)), 0x76543210) class DUT(Module): def __init__(self): @@ -53,10 +53,10 @@ def generator(dut): yield yield self.assertEqual((yield from dut.avl.bus_read(0x0000)), 0x01234567) - self.assertEqual((yield from dut.avl.bus_read(0x0004)), 0x89abcdef) - self.assertEqual((yield from dut.avl.bus_read(0x0008)), 0xdeadbeef) - self.assertEqual((yield from dut.avl.bus_read(0x000c)), 0xc0ffee00) - self.assertEqual((yield from dut.avl.bus_read(0x0010)), 0x76543210) + self.assertEqual((yield from dut.avl.bus_read(0x0001)), 0x89abcdef) + self.assertEqual((yield from dut.avl.bus_read(0x0002)), 0xdeadbeef) + self.assertEqual((yield from dut.avl.bus_read(0x0003)), 0xc0ffee00) + self.assertEqual((yield from dut.avl.bus_read(0x0004)), 0x76543210) yield yield From 90581a2f13224edeb1dff4a1b3e06fd29bea8901 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 9 May 2023 15:28:00 +0700 Subject: [PATCH 026/454] add some low resolution video modes --- litex/soc/cores/video.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 62b867c7b..50a2f9edf 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -28,6 +28,28 @@ # Video Timings ------------------------------------------------------------------------------------ video_timings = { + "160x100@60Hz" : { + "pix_clk" : 1.655e6, + "h_active" : 160, + "h_blanking" : 80, + "h_sync_offset" : 8, + "h_sync_width" : 32, + "v_active" : 100, + "v_blanking" : 15, + "v_sync_offset" : 1, + "v_sync_width" : 8, + }, + "320x200@60Hz" : { + "pix_clk" : 5.16e6, + "h_active" : 320, + "h_blanking" : 80, + "h_sync_offset" : 8, + "h_sync_width" : 32, + "v_active" : 200, + "v_blanking" : 15, + "v_sync_offset" : 1, + "v_sync_width" : 8, + }, "640x480@60Hz" : { "pix_clk" : 25.175e6, "h_active" : 640, From 71a0e398a7dc8c8d61e1ed2a4a3e842fd00595be Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Wed, 10 May 2023 04:04:02 +0700 Subject: [PATCH 027/454] Avalon2Wishbone test: assert readdatavalid on bursts --- test/test_avalon_mm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_avalon_mm.py b/test/test_avalon_mm.py index 4e7dbbd81..8ddd0aa00 100644 --- a/test/test_avalon_mm.py +++ b/test/test_avalon_mm.py @@ -44,9 +44,13 @@ def generator(dut): yield from dut.avl.bus_write(0x0, [0x01234567, 0x89abcdef, 0xdeadbeef, 0xc0ffee00, 0x76543210]) yield self.assertEqual((yield from dut.avl.bus_read(0x0000, burstcount=5)), 0x01234567) + self.assertEqual((yield dut.avl.readdatavalid), 1) self.assertEqual((yield from dut.avl.continue_read_burst()), 0x89abcdef) + self.assertEqual((yield dut.avl.readdatavalid), 1) self.assertEqual((yield from dut.avl.continue_read_burst()), 0xdeadbeef) + self.assertEqual((yield dut.avl.readdatavalid), 1) self.assertEqual((yield from dut.avl.continue_read_burst()), 0xc0ffee00) + self.assertEqual((yield dut.avl.readdatavalid), 1) self.assertEqual((yield from dut.avl.continue_read_burst()), 0x76543210) yield yield From ef904a14e18bcd41b8e7dc47e4c277fa50dd8138 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Wed, 10 May 2023 05:22:23 +0700 Subject: [PATCH 028/454] AvalonMM2Wishbone: fix burst reads (#1686) --- litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 5a75157c0..2177dbfdf 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -59,7 +59,6 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w self.comb += [ avl.waitrequest.eq(~(wb.ack | wb.err) | burst_read), avl.readdata.eq(readdata), - avl.readdatavalid.eq(readdatavalid), ] # Avalon -> Wishbone @@ -79,6 +78,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w self.submodules.fsm = fsm = FSM(reset_state="SINGLE") fsm.act("SINGLE", burst_cycle.eq(0), + avl.readdatavalid.eq(readdatavalid), wb.sel.eq(avl.byteenable), wb.cti.eq(wishbone.CTI_BURST_NONE), If(avl.burstcount > 1, @@ -97,6 +97,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w ) ) fsm.act("BURST-WRITE", + avl.readdatavalid.eq(0), burst_cycle.eq(1), wb.sel.eq(avl.byteenable), wb.cti.eq(wishbone.CTI_BURST_INCREMENTING), @@ -113,6 +114,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w ) ) fsm.act("BURST-READ", + avl.readdatavalid.eq(0), burst_cycle.eq(1), burst_read.eq(1), wb.stb.eq(1), @@ -122,6 +124,7 @@ def __init__(self, data_width=32, address_width=32, wishbone_base_address=0x0, w wb.cti.eq(wishbone.CTI_BURST_END) ), If(wb.ack, + avl.readdatavalid.eq(1), NextValue(burst_address, burst_address + word_width), NextValue(burst_count, burst_count - 1) ), From 2b4c75ddd3aa5a74ee4e1bdd72dca2d98a90317c Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Thu, 11 May 2023 08:24:12 +0700 Subject: [PATCH 029/454] Avalon2Wishbone: Burst can only advance if write is high and waitrequest low --- litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 19f3e7984..4bdeaa3fc 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -100,7 +100,7 @@ def __init__(self, data_width=32, avalon_address_width=32, wishbone_address_widt If(burst_count == 1, wb.cti.eq(wishbone.CTI_BURST_END) ), - If(~avl.waitrequest, + If(~avl.waitrequest & avl.write, NextValue(burst_address, burst_address + burst_increment), NextValue(burst_count, burst_count - 1), ), From 4e15fd54b02cd93783e962c0db5680baa0d34ff9 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 15 May 2023 18:45:10 +0800 Subject: [PATCH 030/454] add an option to generate without reg initializers (asic targets) ASIC targets can't set a reg to a known value on boot, so for more accurate simulations it would be nice to have an option in the platform to specify generating the verilog without 'reg' initializers. The presence of these initializers can mask problems in simulations with X-prop that can lead to missing explicit reset conditions. --- litex/gen/fhdl/verilog.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index 8a6bc4c05..48994fe1b 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -421,7 +421,7 @@ def _print_module(f, ios, name, ns, attr_translate): return r -def _print_signals(f, ios, name, ns, attr_translate): +def _print_signals(f, ios, name, ns, attr_translate, asic=False): sigs = list_signals(f) | list_special_ios(f, ins=True, outs=True, inouts=True) special_outs = list_special_ios(f, ins=False, outs=True, inouts=True) inouts = list_special_ios(f, ins=False, outs=False, inouts=True) @@ -434,7 +434,10 @@ def _print_signals(f, ios, name, ns, attr_translate): if sig in wires: r += "wire " + _print_signal(ns, sig) + ";\n" else: - r += "reg " + _print_signal(ns, sig) + " = " + _print_expression(ns, sig.reset)[0] + ";\n" + if asic: + r += "reg " + _print_signal(ns, sig) + ";\n" # ASICs can't assign an initial value to a reg, it is always X + else: + r += "reg " + _print_signal(ns, sig) + " = " + _print_expression(ns, sig.reset)[0] + ";\n" return r # ------------------------------------------------------------------------------------------------ # @@ -532,6 +535,8 @@ def convert(f, ios=set(), name="top", platform=None, # Sim parameters. time_unit = "1ns", time_precision = "1ps", + # Generate for ASIC simulation (i.e. capture X-on-init for regs) + asic = False, ): # Build Logic. @@ -618,7 +623,7 @@ def convert(f, ios=set(), name="top", platform=None, # Module Signals. verilog += _print_separator("Signals") - verilog += _print_signals(f, ios, name, ns, attr_translate) + verilog += _print_signals(f, ios, name, ns, attr_translate, asic) # Combinatorial Logic. verilog += _print_separator("Combinatorial Logic") From 91f56aaf0ec9d5f15193fa817ba6024e76085531 Mon Sep 17 00:00:00 2001 From: Vegard Storheil Eriksen Date: Wed, 17 May 2023 01:36:42 +0200 Subject: [PATCH 031/454] =?UTF-8?q?soc/interconnect/packet:=20Don=E2=80=99?= =?UTF-8?q?t=20bypass=20dispatcher=20with=20a=20single=20slave=20if=20it?= =?UTF-8?q?=20can=20be=20deselected.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litex/soc/interconnect/packet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/interconnect/packet.py b/litex/soc/interconnect/packet.py index ac7a0bf1e..2886164de 100644 --- a/litex/soc/interconnect/packet.py +++ b/litex/soc/interconnect/packet.py @@ -62,7 +62,7 @@ class Dispatcher(Module): def __init__(self, master, slaves, one_hot=False): if len(slaves) == 0: self.sel = Signal() - elif len(slaves) == 1: + elif len(slaves) == 1 and not one_hot: self.comb += master.connect(slaves.pop()) self.sel = Signal() else: From 53a0bc92e459ad440ae1a9fb9f6f24c600f658d6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 17 May 2023 16:44:35 +0200 Subject: [PATCH 032/454] build/generic_toolchain: Directly handle specific cases with clk None and differential clk. --- litex/build/generic_toolchain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/build/generic_toolchain.py b/litex/build/generic_toolchain.py index 8dae9d865..8ad3fef9b 100644 --- a/litex/build/generic_toolchain.py +++ b/litex/build/generic_toolchain.py @@ -158,6 +158,10 @@ def build(self, platform, fragment, return v_output.ns def add_period_constraint(self, platform, clk, period, keep=True): + if clk is None: + return + if hasattr(clk, "p"): + clk = clk.p if keep: clk.attr.add("keep") period = math.floor(period*1e3)/1e3 # Round to lowest picosecond. From fb0c9e846d72fc4fe99ca329cc84a8d2537d3d8d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 17 May 2023 16:45:45 +0200 Subject: [PATCH 033/454] build/add_period_constraint: Simplify by using new integrated cases in generic add_period_constraint. --- litex/build/altera/platform.py | 3 --- litex/build/anlogic/anlogic.py | 9 --------- litex/build/anlogic/platform.py | 1 - litex/build/efinix/platform.py | 3 --- litex/build/gowin/platform.py | 1 - litex/build/lattice/platform.py | 3 --- litex/build/microsemi/platform.py | 4 ---- litex/build/osfpga/platform.py | 1 - litex/build/xilinx/platform.py | 3 --- 9 files changed, 28 deletions(-) diff --git a/litex/build/altera/platform.py b/litex/build/altera/platform.py index ca690dd77..59f1078ff 100644 --- a/litex/build/altera/platform.py +++ b/litex/build/altera/platform.py @@ -45,9 +45,6 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period): - if clk is None: return - if hasattr(clk, "p"): - clk = clk.p self.toolchain.add_period_constraint(self, clk, period, keep=False) def add_false_path_constraint(self, from_, to): diff --git a/litex/build/anlogic/anlogic.py b/litex/build/anlogic/anlogic.py index bb239d2d2..838f0bf9c 100644 --- a/litex/build/anlogic/anlogic.py +++ b/litex/build/anlogic/anlogic.py @@ -204,12 +204,3 @@ def parse_device(self): (architecture, family, package) = devices[device] return (architecture, family, package) - - def add_period_constraint(self, platform, clk, period): - clk.attr.add("keep") - period = math.floor(period*1e3)/1e3 # round to lowest picosecond - if clk in self.clocks: - if period != self.clocks[clk]: - raise ValueError("Clock already constrained to {:.2f}ns, new constraint to {:.2f}ns" - .format(self.clocks[clk], period)) - self.clocks[clk] = period diff --git a/litex/build/anlogic/platform.py b/litex/build/anlogic/platform.py index 627882467..9979223df 100644 --- a/litex/build/anlogic/platform.py +++ b/litex/build/anlogic/platform.py @@ -36,5 +36,4 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period): - if clk is None: return self.toolchain.add_period_constraint(self, clk, period) diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index 14ec97d43..2ca80593a 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -63,9 +63,6 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period): - if clk is None: return - if hasattr(clk, "p"): - clk = clk.p self.toolchain.add_period_constraint(self, clk, period) def add_false_path_constraint(self, from_, to): diff --git a/litex/build/gowin/platform.py b/litex/build/gowin/platform.py index b37e8d155..30c86bd6e 100644 --- a/litex/build/gowin/platform.py +++ b/litex/build/gowin/platform.py @@ -43,5 +43,4 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period): - if clk is None: return self.toolchain.add_period_constraint(self, clk, period) diff --git a/litex/build/lattice/platform.py b/litex/build/lattice/platform.py index 029ca578c..2aaa4e77b 100644 --- a/litex/build/lattice/platform.py +++ b/litex/build/lattice/platform.py @@ -48,9 +48,6 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period): - if clk is None: return - if hasattr(clk, "p"): - clk = clk.p self.toolchain.add_period_constraint(self, clk, period) def add_false_path_constraint(self, from_, to): diff --git a/litex/build/microsemi/platform.py b/litex/build/microsemi/platform.py index ace9bfe4a..a324a776b 100644 --- a/litex/build/microsemi/platform.py +++ b/litex/build/microsemi/platform.py @@ -34,10 +34,6 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period): - if clk is None: return - clk.attr.add("keep") - if hasattr(clk, "p"): - clk = clk.p self.toolchain.add_period_constraint(self, clk, period) def add_false_path_constraint(self, from_, to): diff --git a/litex/build/osfpga/platform.py b/litex/build/osfpga/platform.py index b01516629..d3e822908 100644 --- a/litex/build/osfpga/platform.py +++ b/litex/build/osfpga/platform.py @@ -36,7 +36,6 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period): - if clk is None: return self.toolchain.add_period_constraint(self, clk, period) def add_false_path_constraint(self, from_, to): diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index fd75dae1d..806516038 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -85,9 +85,6 @@ def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) def add_period_constraint(self, clk, period, keep=True): - if clk is None: return - if hasattr(clk, "p"): - clk = clk.p self.toolchain.add_period_constraint(self, clk, period, keep=keep) def add_false_path_constraint(self, from_, to): From 9c890a0a27b60a7b38afe70a0cbfb9570acaf681 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 17 May 2023 17:23:47 +0200 Subject: [PATCH 034/454] gen/fhdl/verilog: Simplify/Rename registers initialization parameter. --- litex/gen/fhdl/verilog.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index 48994fe1b..b4736aae3 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -421,7 +421,7 @@ def _print_module(f, ios, name, ns, attr_translate): return r -def _print_signals(f, ios, name, ns, attr_translate, asic=False): +def _print_signals(f, ios, name, ns, attr_translate, regs_init): sigs = list_signals(f) | list_special_ios(f, ins=True, outs=True, inouts=True) special_outs = list_special_ios(f, ins=False, outs=True, inouts=True) inouts = list_special_ios(f, ins=False, outs=False, inouts=True) @@ -434,10 +434,10 @@ def _print_signals(f, ios, name, ns, attr_translate, asic=False): if sig in wires: r += "wire " + _print_signal(ns, sig) + ";\n" else: - if asic: - r += "reg " + _print_signal(ns, sig) + ";\n" # ASICs can't assign an initial value to a reg, it is always X - else: - r += "reg " + _print_signal(ns, sig) + " = " + _print_expression(ns, sig.reset)[0] + ";\n" + r += "reg " + _print_signal(ns, sig) + if regs_init: + r += " = " + _print_expression(ns, sig.reset)[0] + r += ";\n" return r # ------------------------------------------------------------------------------------------------ # @@ -532,11 +532,10 @@ def convert(f, ios=set(), name="top", platform=None, special_overrides = dict(), attr_translate = DummyAttrTranslate(), regular_comb = True, + regs_init = True, # Sim parameters. time_unit = "1ns", time_precision = "1ps", - # Generate for ASIC simulation (i.e. capture X-on-init for regs) - asic = False, ): # Build Logic. @@ -623,7 +622,7 @@ def convert(f, ios=set(), name="top", platform=None, # Module Signals. verilog += _print_separator("Signals") - verilog += _print_signals(f, ios, name, ns, attr_translate, asic) + verilog += _print_signals(f, ios, name, ns, attr_translate, regs_init) # Combinatorial Logic. verilog += _print_separator("Combinatorial Logic") @@ -640,7 +639,7 @@ def convert(f, ios=set(), name="top", platform=None, verilog += _print_separator("Specialized Logic") verilog += _print_specials( name = name, - overrides =special_overrides, + overrides = special_overrides, specials = f.specials - lowered_specials, namespace = ns, add_data_file = r.add_data_file, From 60537fc39f3efa9b5c222f15f469746b6ed87cb3 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 18 May 2023 12:13:29 +0200 Subject: [PATCH 035/454] build/xilinx/yosys_nextpnr: fix f4pga_device for xc7a100 : xc7a35t -> xc7a100t --- litex/build/xilinx/yosys_nextpnr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/xilinx/yosys_nextpnr.py b/litex/build/xilinx/yosys_nextpnr.py index 41a5d00d3..264fc3d11 100644 --- a/litex/build/xilinx/yosys_nextpnr.py +++ b/litex/build/xilinx/yosys_nextpnr.py @@ -53,7 +53,7 @@ def _check_properties(self): self.f4pga_device = { # FIXME: fine for now since only a few devices are supported, do more clever device re-mapping. "xc7a35ticsg324-1L" : "xc7a35t", - "xc7a100tcsg324-1" : "xc7a35t", + "xc7a100tcsg324-1" : "xc7a100t", "xc7z010clg400-1" : "xc7z010", "xc7z020clg400-1" : "xc7z020", }[self.platform.device] From f5a9efd8ba42da36cd1ab6a63bc685dfe7ce317b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 21 May 2023 09:06:20 +0200 Subject: [PATCH 036/454] build/add_period_constraint: Fix trellis (thanks bjonnh and zyp) and avoid specific add_period_constraint in libero_soc. --- litex/build/lattice/trellis.py | 4 ++++ litex/build/microsemi/libero_soc.py | 7 ------- litex/build/xilinx/ise.py | 4 ++++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index 0f365c831..367864237 100644 --- a/litex/build/lattice/trellis.py +++ b/litex/build/lattice/trellis.py @@ -146,6 +146,10 @@ def nextpnr_ecp5_parse_device(self, device): } def add_period_constraint(self, platform, clk, period): + if clk is None: + return + if hasattr(clk, "p"): + clk = clk.p platform.add_platform_command("""FREQUENCY PORT "{clk}" {freq} MHz;""".format( freq=str(float(1/period)*1000), clk="{clk}"), clk=clk) diff --git a/litex/build/microsemi/libero_soc.py b/litex/build/microsemi/libero_soc.py index 91a0b2bfd..b4ca3cde7 100644 --- a/litex/build/microsemi/libero_soc.py +++ b/litex/build/microsemi/libero_soc.py @@ -236,13 +236,6 @@ def run_script(self, script): if subprocess.call(shell + [script]) != 0: raise OSError("Subprocess failed") - def add_period_constraint(self, platform, clk, period): - if clk in self.clocks: - if period != self.clocks[clk]: - raise ValueError("Clock already constrained to {:.2f}ns, new constraint to {:.2f}ns" - .format(self.clocks[clk], period)) - self.clocks[clk] = period - def add_false_path_constraint(self, platform, from_, to): if (to, from_) not in self.false_paths: self.false_paths.add((from_, to)) diff --git a/litex/build/xilinx/ise.py b/litex/build/xilinx/ise.py index 19ad929ed..ca20f7ad5 100755 --- a/litex/build/xilinx/ise.py +++ b/litex/build/xilinx/ise.py @@ -206,6 +206,10 @@ def run_script(self, script): # them through clock objects like DCM and PLL objects. def add_period_constraint(self, platform, clk, period): + if clk is None: + return + if hasattr(clk, "p"): + clk = clk.p clk.attr.add("keep") platform.add_platform_command( """ From 54192651d8a0b990eb14b3bffa4f85fb565101a0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 21 May 2023 09:33:19 +0200 Subject: [PATCH 037/454] build/xilinx/ise/add_period_constraint: Add keep parameter. --- litex/build/xilinx/ise.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/build/xilinx/ise.py b/litex/build/xilinx/ise.py index ca20f7ad5..d62c9ca85 100755 --- a/litex/build/xilinx/ise.py +++ b/litex/build/xilinx/ise.py @@ -205,12 +205,13 @@ def run_script(self, script): # constraints and other constraints otherwise it will be unable to trace # them through clock objects like DCM and PLL objects. - def add_period_constraint(self, platform, clk, period): + def add_period_constraint(self, platform, clk, period, keep=True): if clk is None: return if hasattr(clk, "p"): clk = clk.p - clk.attr.add("keep") + if keep: + clk.attr.add("keep") platform.add_platform_command( """ NET "{clk}" TNM_NET = "PRD{clk}"; From 6ad14ef6447a5b1f0b2a18e15c638157d5e34659 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Mon, 22 May 2023 10:03:53 +0700 Subject: [PATCH 038/454] AvalonMM/AvalonMM2Wishbone: fix read bursts (readdatavalid one cycle too short) --- litex/soc/interconnect/avalon/avalon_mm.py | 2 ++ litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/litex/soc/interconnect/avalon/avalon_mm.py b/litex/soc/interconnect/avalon/avalon_mm.py index 1fef0a9fe..c166da078 100644 --- a/litex/soc/interconnect/avalon/avalon_mm.py +++ b/litex/soc/interconnect/avalon/avalon_mm.py @@ -102,6 +102,8 @@ def bus_read(self, address, byteenable=None, burstcount=1, chipselect=None): def continue_read_burst(self): yield + while not (yield self.readdatavalid): + yield return (yield self.readdata) def bus_write(self, address, writedata, byteenable=None, chipselect=None): diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 4bdeaa3fc..0e85f801a 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -15,7 +15,7 @@ # Avalon MM <--> Wishbone Bridge ------------------------------------------------------------------- class AvalonMM2Wishbone(Module): - def __init__(self, data_width=32, avalon_address_width=32, wishbone_address_width=32, wishbone_base_address=0x0, burst_increment=1, avoid_combinatorial_loop=True): + def __init__(self, data_width=32, avalon_address_width=32, wishbone_address_width=32, wishbone_base_address=0x0, burst_increment=1, avoid_combinatorial_loop=False): self.a2w_avl = avl = AvalonMMInterface (data_width=data_width, adr_width=avalon_address_width) self.a2w_wb = wb = wishbone.Interface(data_width=data_width, adr_width=wishbone_address_width, bursting=True) @@ -125,6 +125,7 @@ def __init__(self, data_width=32, avalon_address_width=32, wishbone_address_widt NextValue(burst_count, burst_count - 1) ), If(burst_count == 0, + avl.readdatavalid.eq(int(avoid_combinatorial_loop)), wb.cyc.eq(0), wb.stb.eq(0), NextState("SINGLE")) From 2a27ca18eae821f5633738af71c24139e228ccc8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 26 May 2023 10:10:44 +0200 Subject: [PATCH 039/454] stream/Pipeline: Allow Pipeline to be created dynamically. Ex: self.submodules.pipeline = Pipeline() self.pipeline.add(m0) self.pipeline.add(m1) self.pipeline.add(m3) --- litex/soc/interconnect/stream.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index e9b049366..f9901ae10 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -940,14 +940,20 @@ def __init__(self, layout_from, n, reverse=False): class Pipeline(Module): def __init__(self, *modules): - n = len(modules) - m = modules[0] + self.modules = list(modules) + + def add(self, module): + self.modules.append(module) + + def do_finalize(self): + n = len(self.modules) + m = self.modules[0] # Expose sink of first module if available. if hasattr(m, "sink"): self.sink = m.sink # Iterate on Modules/Endpoints. for i in range(1, n): - m_n = modules[i] + m_n = self.modules[i] # If m is an Endpoint, use it as Source, else use Module.source. source = m if isinstance(m, Endpoint) else m.source # If m_n is an Endpoint, use it as Sink, else use Module.sink. From eb8e43359de4839823b94853e1fc3e8400689e75 Mon Sep 17 00:00:00 2001 From: Jonathan Bisson Date: Sat, 27 May 2023 18:59:07 -0500 Subject: [PATCH 040/454] Fix frequency specification for ECPDAP on Lattice It was given as kHz but it takes Hz --- litex/build/lattice/programmer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/build/lattice/programmer.py b/litex/build/lattice/programmer.py index 13156b7ba..df81062d2 100644 --- a/litex/build/lattice/programmer.py +++ b/litex/build/lattice/programmer.py @@ -169,12 +169,12 @@ class EcpDapProgrammer(GenericProgrammer): needs_bitreverse = False def __init__(self, frequency=8_000_000): - self.frequency_khz = frequency // 1000 + self.frequency = frequency def flash(self, address, bitstream_file): self.call(["ecpdap", "flash", "write", - "--freq", str(self.frequency_khz), + "--freq", str(self.frequency), "--offset", str(address), bitstream_file ]) @@ -182,7 +182,7 @@ def flash(self, address, bitstream_file): def load_bitstream(self, bitstream_file): self.call(["ecpdap", "program", - "--freq", str(self.frequency_khz), + "--freq", str(self.frequency), bitstream_file ]) From 93b45a687fd791cbde783a6aa87cbf8d333903ad Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 30 May 2023 08:25:08 +0200 Subject: [PATCH 041/454] interconnect/stream/Pipeline: Finalize Pipeline if modules are provided during __init__ (for retro-compatibility). --- litex/soc/interconnect/stream.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index f9901ae10..94c571c5a 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -941,8 +941,11 @@ def __init__(self, layout_from, n, reverse=False): class Pipeline(Module): def __init__(self, *modules): self.modules = list(modules) + if len(self.modules): + self.finalize() def add(self, module): + assert not self.finalized self.modules.append(module) def do_finalize(self): From a1106b997e33c2783a9088bfbc87e34b8b0de54c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 4 Jun 2023 08:19:15 +0200 Subject: [PATCH 042/454] soc/add_spi_sdcard: Fix broken/useless add_module. Was already useless before and raise a valid assertion. --- litex/soc/integration/soc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 698fab697..7a3f6eacb 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1813,7 +1813,6 @@ def add_spi_sdcard(self, name="spisdcard", spi_clk_freq=400e3, with_tristate=Fal self.specials += Tristate(spi_sdcard_tristate_pads.cs_n, spi_sdcard_pads.cs_n, ~tristate) self.specials += Tristate(spi_sdcard_tristate_pads.mosi, spi_sdcard_pads.mosi, ~tristate) self.comb += spi_sdcard_pads.miso.eq(spi_sdcard_tristate_pads.miso) - self.add_module(name=f"{name}_tristate", module=tristate) # Core. self.check_if_exists(name) From d8ba2e8f650ec4c321851c8c2575e9e147b1128c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 5 Jun 2023 14:20:20 +0200 Subject: [PATCH 043/454] build/xilinx/vivado: Add project commands to add commands just after project creation. --- litex/build/xilinx/vivado.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 40f96b85a..073dacd31 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -101,6 +101,7 @@ def __init__(self): super().__init__() self.bitstream_commands = [] self.additional_commands = [] + self.project_commands = XilinxVivadoCommands() self.pre_synthesis_commands = XilinxVivadoCommands() self.pre_placement_commands = XilinxVivadoCommands() self.pre_routing_commands = XilinxVivadoCommands() @@ -223,6 +224,10 @@ def build_project(self): if self.vivado_max_threads: tcl.append(f"set_param general.maxThreads {self.vivado_max_threads}") + # Add project commands + tcl.append("\n# Add project commands\n") + tcl.extend(c.format(build_name=self._build_name) for c in self.project_commands.resolve(self._vns)) + # Enable Xilinx Parameterized Macros if self._enable_xpm: tcl.append("\n# Enable Xilinx Parameterized Macros\n") From 200a1a18ee980aad32c3239acc66af64d10c5a2b Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Wed, 31 May 2023 17:17:04 +1000 Subject: [PATCH 044/454] soc/software: move helpers to hw/common.h Fixes warning: liblitespi/spiflash.c: In function 'spiflash_erase_range': liblitespi/spiflash.c:202:4: warning: implicit declaration of function 'cdelay' [-Wimplicit-function-declaration] cdelay(CONFIG_CLOCK_FREQUENCY/25); ^~~~~~ Fixes link failure with spiflash and without liblitedram after commit: 118dd6ed08 ld: ../liblitespi/liblitespi.a(spiflash.o): in function `spiflash_erase_range': ../liblitespi/spiflash.c:209: undefined reference to `cdelay' --- litex/soc/software/bios/boot.c | 7 ------- litex/soc/software/include/hw/common.h | 16 ++++++++++++++++ litex/soc/software/libbase/memtest.h | 3 --- litex/soc/software/liblitedram/sdram.c | 16 ---------------- litex/soc/software/liblitesdcard/sdcard.c | 7 ------- litex/soc/software/liblitesdcard/spisdcard.c | 7 ------- 6 files changed, 16 insertions(+), 40 deletions(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index d30df1385..39233fcee 100755 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -36,13 +36,6 @@ #include #include -/*-----------------------------------------------------------------------*/ -/* Helpers */ -/*-----------------------------------------------------------------------*/ - -#define max(x, y) (((x) > (y)) ? (x) : (y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) - /*-----------------------------------------------------------------------*/ /* Boot */ /*-----------------------------------------------------------------------*/ diff --git a/litex/soc/software/include/hw/common.h b/litex/soc/software/include/hw/common.h index 1d59794f9..927c13d1f 100644 --- a/litex/soc/software/include/hw/common.h +++ b/litex/soc/software/include/hw/common.h @@ -4,6 +4,22 @@ #include #include +/*-----------------------------------------------------------------------*/ +/* Helpers */ +/*-----------------------------------------------------------------------*/ + +#define max(x, y) (((x) > (y)) ? (x) : (y)) +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +static inline void cdelay(int i) { +#ifndef CONFIG_BIOS_NO_DELAYS + while(i > 0) { + __asm__ volatile(CONFIG_CPU_NOP); + i--; + } +#endif // CONFIG_BIOS_NO_DELAYS +} + /* To overwrite CSR subregister accessors, define extern, non-inlined versions * of csr_[read|write]_simple(), and define CSR_ACCESSORS_DEFINED. */ diff --git a/litex/soc/software/libbase/memtest.h b/litex/soc/software/libbase/memtest.h index 955ed80c7..3a9a81005 100644 --- a/litex/soc/software/libbase/memtest.h +++ b/litex/soc/software/libbase/memtest.h @@ -10,9 +10,6 @@ extern "C" { #include #include -#define max(x, y) (((x) > (y)) ? (x) : (y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) - #ifndef MEMTEST_DATA_SIZE #define MEMTEST_DATA_SIZE (2*1024*1024) #endif diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index 0a00ed5fa..3d69d16cf 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -50,22 +50,6 @@ #define MODULO (1) #endif // SDRAM_PHY_DELAYS > 32 -/*-----------------------------------------------------------------------*/ -/* Helpers */ -/*-----------------------------------------------------------------------*/ - -#define max(x, y) (((x) > (y)) ? (x) : (y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) - -__attribute__((unused)) void cdelay(int i) { -#ifndef CONFIG_BIOS_NO_DELAYS - while(i > 0) { - __asm__ volatile(CONFIG_CPU_NOP); - i--; - } -#endif // CONFIG_BIOS_NO_DELAYS -} - /*-----------------------------------------------------------------------*/ /* Constants */ /*-----------------------------------------------------------------------*/ diff --git a/litex/soc/software/liblitesdcard/sdcard.c b/litex/soc/software/liblitesdcard/sdcard.c index 990d20572..05be4e670 100644 --- a/litex/soc/software/liblitesdcard/sdcard.c +++ b/litex/soc/software/liblitesdcard/sdcard.c @@ -33,13 +33,6 @@ #define SDCARD_CLK_FREQ 25000000 #endif -/*-----------------------------------------------------------------------*/ -/* Helpers */ -/*-----------------------------------------------------------------------*/ - -#define max(x, y) (((x) > (y)) ? (x) : (y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) - /*-----------------------------------------------------------------------*/ /* SDCard command helpers */ /*-----------------------------------------------------------------------*/ diff --git a/litex/soc/software/liblitesdcard/spisdcard.c b/litex/soc/software/liblitesdcard/spisdcard.c index 44cf231ea..9cdc1bad5 100644 --- a/litex/soc/software/liblitesdcard/spisdcard.c +++ b/litex/soc/software/liblitesdcard/spisdcard.c @@ -28,13 +28,6 @@ #define SPISDCARD_CLK_FREQ 20000000 #endif -/*-----------------------------------------------------------------------*/ -/* Helpers */ -/*-----------------------------------------------------------------------*/ - -#define max(x, y) (((x) > (y)) ? (x) : (y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) - /*-----------------------------------------------------------------------*/ /* SPI SDCard clocker functions */ /*-----------------------------------------------------------------------*/ From 9b67898e99b87283e3ca4b8425defed4cb5ddf09 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 14 Oct 2021 08:51:01 +1100 Subject: [PATCH 045/454] tools/linux: add sys_clk to device tree * required for using standard devm_clk_get() clock mechanism in linux drivers --- litex/tools/litex_json2dts_linux.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/litex/tools/litex_json2dts_linux.py b/litex/tools/litex_json2dts_linux.py index 4bc91ac55..c94c8d8ee 100755 --- a/litex/tools/litex_json2dts_linux.py +++ b/litex/tools/litex_json2dts_linux.py @@ -88,6 +88,16 @@ def generate_dts(d, initrd_start=None, initrd_size=None, initrd=None, root_devic }; """ + # Clocks ------------------------------------------------------------------------------------------ + + dts += """ + sys_clk: pll {{ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <{sys_clk_freq}>; + }}; +""".format(sys_clk_freq=d["constants"]["config_clock_frequency"]) + # CPU ------------------------------------------------------------------------------------------ # RISC-V From eb67197a462ca42e7e9cc513bd9d6aa73d309486 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 14 Oct 2021 08:52:04 +1100 Subject: [PATCH 046/454] tools/linux: fix dts warning: missing #address-cells --- litex/tools/litex_json2dts_linux.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/tools/litex_json2dts_linux.py b/litex/tools/litex_json2dts_linux.py index c94c8d8ee..7d0f1ccc7 100755 --- a/litex/tools/litex_json2dts_linux.py +++ b/litex/tools/litex_json2dts_linux.py @@ -175,6 +175,7 @@ def generate_dts(d, initrd_start=None, initrd_size=None, initrd=None, root_devic {cache_desc} {tlb_desc} L{irq}: interrupt-controller {{ + #address-cells = <0>; #interrupt-cells = <0x00000001>; interrupt-controller; compatible = "riscv,cpu-intc"; From 88ec1b3f5ef28a5c349c194dcbb680300039a791 Mon Sep 17 00:00:00 2001 From: Richard Tucker Date: Thu, 31 Mar 2022 16:43:30 +1100 Subject: [PATCH 047/454] tools: include LITESD in zephyr dts generator --- litex/tools/litex_json2dts_zephyr.py | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/litex/tools/litex_json2dts_zephyr.py b/litex/tools/litex_json2dts_zephyr.py index c9a07ac13..a064a3d45 100755 --- a/litex/tools/litex_json2dts_zephyr.py +++ b/litex/tools/litex_json2dts_zephyr.py @@ -212,6 +212,36 @@ def peripheral_handler(name, parm, csr): 'alias': 'spi0', 'config_entry': 'SPI_LITESPI' }, + 'sdblock2mem': { + 'handler': peripheral_handler, + 'alias': 'sdblock2mem', + 'size': 0x18, + 'config_entry': 'SD_LITESD' + }, + 'sdcore': { + 'handler': peripheral_handler, + 'alias': 'sdcore', + 'size': 0x2C, + 'config_entry': 'SD_LITESD' + }, + 'sdirq': { + 'handler': peripheral_handler, + 'alias': 'sdirq', + 'size': 0x0C, + 'config_entry': 'SD_LITESD' + }, + 'sdmem2block': { + 'handler': peripheral_handler, + 'alias': 'sdmem2block', + 'size': 0x18, + 'config_entry': 'SD_LITESD' + }, + 'sdphy': { + 'handler': peripheral_handler, + 'alias': 'sdphy', + 'size': 0x10, + 'config_entry': 'SD_LITESD' + }, 'i2c0' : { 'handler': i2c_handler, 'config_entry': 'I2C_LITEX' From 5e667f17d7994e965127af08ed29caf31ef84db2 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 2 Jun 2022 16:14:47 +1000 Subject: [PATCH 048/454] csr: fix field access check * Broken in 5dc440e80de --- litex/soc/interconnect/csr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/csr.py b/litex/soc/interconnect/csr.py index 849cfd27e..711785a9c 100644 --- a/litex/soc/interconnect/csr.py +++ b/litex/soc/interconnect/csr.py @@ -217,10 +217,10 @@ def __init__(self, fields, access): for field in fields: if field.access is None: field.access = access - elif field.access == CSRAccess.ReadOnly: + elif access == CSRAccess.ReadOnly: assert not field.pulse assert field.access == CSRAccess.ReadOnly - elif field.access == CSRAccess.ReadWrite: + elif access == CSRAccess.ReadWrite: assert field.access in [CSRAccess.ReadWrite, CSRAccess.WriteOnly] if field.pulse: field.access = CSRAccess.WriteOnly From 4eed62143c260d997d4679828b89a8dcf94a4d50 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 2 Jun 2022 16:15:43 +1000 Subject: [PATCH 049/454] litex_client: remove duplicate read --- litex/tools/litex_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/tools/litex_client.py b/litex/tools/litex_client.py index c082de09e..9e5c37dea 100644 --- a/litex/tools/litex_client.py +++ b/litex/tools/litex_client.py @@ -317,7 +317,7 @@ def timer_callback(refresh=1e-1, xadc_points=100): # CSR Update. for name, reg in bus.regs.__dict__.items(): value = reg.read() - dpg.set_value(item=name, value=f"0x{reg.read():x}") + dpg.set_value(item=name, value=f"0x{value():x}") # XADC Update. if with_xadc: From e10643bfd517c2be9a0a6d0e2fcc8e415c3cd98b Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Wed, 18 Jan 2023 10:58:02 +1100 Subject: [PATCH 050/454] yosys: add command line arg to be quiet --- litex/build/lattice/radiant.py | 3 ++- litex/build/yosys_nextpnr_toolchain.py | 2 ++ litex/build/yosys_wrapper.py | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/litex/build/lattice/radiant.py b/litex/build/lattice/radiant.py index 0cce1d78d..b635c539f 100644 --- a/litex/build/lattice/radiant.py +++ b/litex/build/lattice/radiant.py @@ -92,6 +92,7 @@ def build(self, platform, fragment, self._timingstrict = timingstrict self._synth_mode = synth_mode + self._quiet = kwargs.pop("quiet", False) return GenericToolchain.build(self, platform, fragment, **kwargs) @@ -123,7 +124,7 @@ def finalize(self): self._yosys = YosysWrapper(self.platform, self._build_name, output_name=self._build_name+"_yosys", target="nexus", template=[], yosys_cmds=yosys_cmds, - yosys_opts=self._synth_opts, synth_format="vm") + yosys_opts=self._synth_opts, synth_format="vm", quiet = self._quiet) # Constraints (.ldc) --------------------------------------------------------------------------- diff --git a/litex/build/yosys_nextpnr_toolchain.py b/litex/build/yosys_nextpnr_toolchain.py index 1c637b94b..6491d7568 100644 --- a/litex/build/yosys_nextpnr_toolchain.py +++ b/litex/build/yosys_nextpnr_toolchain.py @@ -122,6 +122,7 @@ def build(self, platform, fragment, self.timingstrict = timingstrict self.ignoreloops = ignoreloops self.seed = seed + self._quiet = kwargs.pop("quiet", False) return GenericToolchain.build(self, platform, fragment, **kwargs) @@ -139,6 +140,7 @@ def finalize(self): synth_format = self.synth_fmt, nowidelut = self._nowidelut, abc9 = self._abc9, + quiet = self._quiet, ) # NextPnr options diff --git a/litex/build/yosys_wrapper.py b/litex/build/yosys_wrapper.py index c720f5abc..c340e3f83 100644 --- a/litex/build/yosys_wrapper.py +++ b/litex/build/yosys_wrapper.py @@ -57,6 +57,7 @@ def __init__(self, platform, build_name, self._synth_format = synth_format self._yosys_opts = yosys_opts self._yosys_cmds = yosys_cmds + self._quiet = "" if not kwargs.pop("quiet", False) else '-Qq' self._target = target @@ -132,7 +133,7 @@ def get_yosys_call(self, target="script"): ======= str containing instruction and/or rule """ - base_cmd = f"yosys -l {self._build_name}.rpt {self._build_name}.ys" + base_cmd = f"yosys {self._quiet} -l {self._build_name}.rpt {self._build_name}.ys" if target == "makefile": return f"{self._build_name}.{self._synth_format}:\n\t" + base_cmd + "\n" elif target == "script": @@ -144,10 +145,12 @@ def yosys_args(parser): parser.add_argument("--yosys-nowidelut", action="store_true", help="Use Yosys's nowidelut mode.") parser.add_argument("--yosys-abc9", action="store_true", help="Use Yosys's abc9 mode.") parser.add_argument("--yosys-flow3", action="store_true", help="Use Yosys's abc9 mode with the flow3 script.") + parser.add_argument("--yosys-quiet", action="store_true", help="Use Yosys's '-Qq' to be quiet") def yosys_argdict(args): return { "nowidelut": args.yosys_nowidelut, "abc9": args.yosys_abc9, "flow3": args.yosys_flow3, + "quiet": args.yosys_quiet, } From 8066a9e265a84296d849fb302be7818adcb7297f Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Fri, 12 May 2023 13:19:29 +1000 Subject: [PATCH 051/454] efinix/dbparser: support more Titanium pll_in pins * Veridied to fix using A11 on Ti60F255. Without this the wrong GPIO was silently used * Seems to correctly select PLL_IN clock for these Ti60F255 pins: ** H6, B2, C5, E6, A11, C14, L11, R13, P11, R5, A2 --- litex/build/efinix/dbparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/efinix/dbparser.py b/litex/build/efinix/dbparser.py index 2e06a8638..1fa882036 100644 --- a/litex/build/efinix/dbparser.py +++ b/litex/build/efinix/dbparser.py @@ -112,7 +112,7 @@ def get_pll_inst_from_gpio_inst(self, dmap, inst): if i == None: continue if (i == inst) or (inst + '.' in i): - refclk_no = 0 + refclk_no = 0 if self.device[:2] != "Ti" else c.get('index') if c.get('index') == '3': refclk_no = 1 return (p.get('name'), refclk_no) From f8a604e0fa0fe91b61828b5d941f09cd53345004 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 22 May 2023 15:19:28 +1000 Subject: [PATCH 052/454] build/efinity: assert DRIVE_STRENGTH is valid With invalid drive strength Efinity 2021.2 fails with an unhelpful message: "WARNING: Fail to generate summary report file" Efinity 2022.2 does report DRIVE_STRENGTH is invalid --- litex/build/efinix/efinity.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index abdf65667..954dfe9f8 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -144,6 +144,9 @@ def _format_constraint(self, c, signame, fmt_r): if "DRIVE_STRENGTH" in c.misc: prop = "DRIVE_STRENGTH" val = c.misc.split("=")[1] + valid = ["1", "2", "3", "4"] if self.platform.family == "Trion" else [ + "2", "4", "6", "8", "10", "12", "16" ] + assert val in valid, f"DRIVE_STRENGTH {val} is not in {valid}" if "SLEWRATE" in c.misc: prop = "SLEW_RATE" From d60f5c221ca5b32f868133b3fd0bc8ab4d7f0d21 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 22 May 2023 17:18:38 +1000 Subject: [PATCH 053/454] build/efinity: document SLEW 1 is fast --- litex/build/efinix/efinity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 954dfe9f8..bba1981bf 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -150,7 +150,7 @@ def _format_constraint(self, c, signame, fmt_r): if "SLEWRATE" in c.misc: prop = "SLEW_RATE" - val = "1" + val = "1" # FAST if prop == "": # Print error, warning ?? From 93bc2760fe37e10a72859b94b7c2b3cddd4b9a05 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 29 May 2023 14:37:12 +1000 Subject: [PATCH 054/454] build/openfpgaloader: support jtag index-chain * allows loading a FPGA that is not the only device in a JTAG scan chain --- litex/build/openfpgaloader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index 4ac59aa1e..d3ca7773f 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -12,7 +12,7 @@ class OpenFPGALoader(GenericProgrammer): needs_bitreverse = False - def __init__(self, board="", cable="", freq=0): + def __init__(self, board="", cable="", freq=0, index_chain=None): self.cmd = ["openFPGALoader"] if board: self.cmd += ["--board", board] @@ -20,6 +20,8 @@ def __init__(self, board="", cable="", freq=0): self.cmd += ["--cable", cable] if freq: self.cmd += ["--freq", str(int(float(freq)))] + if index_chain is not None: + self.cmd += ["--index-chain", str(int(index_chain))] def load_bitstream(self, bitstream_file): cmd = self.cmd + ["--bitstream", bitstream_file] From 51dd5277af322ca06ae68dc74d2debc5b83a7ae2 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 29 May 2023 15:03:38 +1000 Subject: [PATCH 055/454] soc/integration: support software_debug for add_spi_flash() --- litex/soc/integration/soc.py | 4 +++- litex/soc/software/liblitespi/spiflash.c | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 7a3f6eacb..a504d4757 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1758,7 +1758,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk, eth_tx_clk) # Add SPI Flash -------------------------------------------------------------------------------- - def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, phy=None, rate="1:1", **kwargs): + def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, phy=None, rate="1:1", software_debug=False, **kwargs): # Imports. from litespi import LiteSPI from litespi.phy.generic import LiteSPIPHY @@ -1792,6 +1792,8 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, 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 SDCard ------------------------------------------------------------------------------- def add_spi_sdcard(self, name="spisdcard", spi_clk_freq=400e3, with_tristate=False, software_debug=False): diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index 5bd827318..eb565c5ac 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -28,7 +28,7 @@ int spiflash_freq_init(void) crc = crc32((unsigned char *)SPIFLASH_BASE, SPI_FLASH_BLOCK_SIZE); crc_test = crc; -#if SPIFLASH_DEBUG +#ifdef SPIFLASH_DEBUG printf("Testing against CRC32: %08x\n\r", crc); #endif @@ -41,7 +41,7 @@ int spiflash_freq_init(void) while((crc == crc_test) && (lowest_div-- > 0)) { spiflash_phy_clk_divisor_write((uint32_t)lowest_div); crc_test = crc32((unsigned char *)SPIFLASH_BASE, SPI_FLASH_BLOCK_SIZE); -#if SPIFLASH_DEBUG +#ifdef SPIFLASH_DEBUG printf("[DIV: %d] %08x\n\r", lowest_div, crc_test); #endif } @@ -62,7 +62,7 @@ int spiflash_freq_init(void) void spiflash_dummy_bits_setup(unsigned int dummy_bits) { spiflash_core_mmap_dummy_bits_write((uint32_t)dummy_bits); -#if SPIFLASH_DEBUG +#ifdef SPIFLASH_DEBUG printf("Dummy bits set to: %d\n\r", spiflash_core_mmap_dummy_bits_read()); #endif } From bd7b951af04b0443065e84f3886a22e74ba42cfc Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 29 May 2023 15:07:36 +1000 Subject: [PATCH 056/454] soc/software/liblitesdcard: be less verbose debug is now more usable: Booting from SDCard in SD-Mode... Booting from boot.json... Setting SDCard clk freq to 781 KHz CMD0: GO_IDLE cmdevt: wait for event & 0x1 cmdevt: 00000001 00000000 00000000 00000000 00000000 CMD8: SEND_EXT_CSD, arg: 0x000001aa cmdevt: wait for event & 0x1 cmdevt: 00000005 00000000 00000000 00000000 00000000 Booting from boot.bin... Setting SDCard clk freq to 781 KHz CMD0: GO_IDLE cmdevt: wait for event & 0x1 cmdevt: 00000001 00000000 00000000 00000000 00000000 CMD8: SEND_EXT_CSD, arg: 0x000001aa cmdevt: wait for event & 0x1 cmdevt: 00000005 00000000 00000000 00000000 00000000 SDCard boot failed. No boot medium found --- litex/soc/software/liblitesdcard/sdcard.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/litex/soc/software/liblitesdcard/sdcard.c b/litex/soc/software/liblitesdcard/sdcard.c index 05be4e670..6557d3a63 100644 --- a/litex/soc/software/liblitesdcard/sdcard.c +++ b/litex/soc/software/liblitesdcard/sdcard.c @@ -41,17 +41,16 @@ int sdcard_wait_cmd_done(void) { unsigned int event; #ifdef SDCARD_DEBUG uint32_t r[SD_CMD_RESPONSE_SIZE/4]; + printf("cmdevt: wait for event & 0x1\n"); #endif for (;;) { event = sdcore_cmd_event_read(); -#ifdef SDCARD_DEBUG - printf("cmdevt: %08x\n", event); -#endif busy_wait_us(10); if (event & 0x1) break; } #ifdef SDCARD_DEBUG + printf("cmdevt: %08x\n", event); csr_rd_buf_uint32(CSR_SDCORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); printf("%08x %08x %08x %08x\n", r[0], r[1], r[2], r[3]); @@ -65,15 +64,18 @@ int sdcard_wait_cmd_done(void) { int sdcard_wait_data_done(void) { unsigned int event; - for (;;) { - event = sdcore_data_event_read(); #ifdef SDCARD_DEBUG - printf("dataevt: %08x\n", event); + printf("dataevt: wait for event & 0x1\n"); #endif + for (;;) { + event = sdcore_data_event_read(); if (event & 0x1) break; busy_wait_us(10); } +#ifdef SDCARD_DEBUG + printf("dataevt: %08x\n", event); +#endif if (event & 0x4) return SD_TIMEOUT; else if (event & 0x8) From d0b7f54d2763c9ac34b74c19f0750491cc13ea18 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Tue, 30 May 2023 15:17:03 +1000 Subject: [PATCH 057/454] build/openfpgaloader: support --fpga-part --- litex/build/openfpgaloader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index d3ca7773f..abaf12d74 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -12,10 +12,12 @@ class OpenFPGALoader(GenericProgrammer): needs_bitreverse = False - def __init__(self, board="", cable="", freq=0, index_chain=None): + def __init__(self, board="", cable="", freq=0, fpga_part="", index_chain=None): self.cmd = ["openFPGALoader"] if board: self.cmd += ["--board", board] + if fpga_part: + self.cmd += ["--fpga-part", fpga_part] if cable: self.cmd += ["--cable", cable] if freq: From 9c426c14a2975c50a657d4784d9aaa8ef5aac4ef Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Tue, 30 May 2023 15:18:01 +1000 Subject: [PATCH 058/454] software/liblitespi: add read_id() --- litex/soc/software/liblitespi/spiflash.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index eb565c5ac..503b15301 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -123,6 +123,23 @@ static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len) flush_cpu_dcache(); } +static uint32_t spiflash_read_id_register(void) +{ + volatile uint8_t buf[4]; + w_buf[0] = 0x9F; + w_buf[1] = 0x00; + transfer_cmd(w_buf, buf, 4); + +#ifdef SPIFLASH_DEBUG + printf("[ID: %02x %02x %02x %02x]", buf[0], buf[1], buf[2], buf[3]); +#endif + + /* FIXME normally the status should be in buf[1], + but we have to read it a few more times to be + stable for unknown reasons */ + return buf[3]; +} + static uint32_t spiflash_read_status_register(void) { volatile uint8_t buf[4]; @@ -254,6 +271,8 @@ void spiflash_init(void) #ifdef CSR_SPIFLASH_CORE_MASTER_CS_ADDR + spiflash_read_id_register(); + /* Quad / QPI Configuration. */ #ifdef SPIFLASH_MODULE_QUAD_CAPABLE printf("Enabling Quad mode...\n"); From e84881072f88eca0c366614dc69a21791ebdba7d Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Tue, 30 May 2023 15:19:20 +1000 Subject: [PATCH 059/454] software/liblitespi: fix building with debug --- litex/soc/software/liblitespi/spiflash.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index 503b15301..410c43948 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -147,7 +147,7 @@ static uint32_t spiflash_read_status_register(void) w_buf[1] = 0x00; transfer_cmd(w_buf, buf, 4); -#if SPIFLASH_DEBUG +#ifdef SPIFLASH_DEBUG printf("[SR: %02x %02x %02x %02x]", buf[0], buf[1], buf[2], buf[3]); #endif @@ -220,7 +220,7 @@ int spiflash_write_stream(uint32_t addr, uint8_t *stream, uint32_t len) uint32_t offset = 0; uint32_t j = 0; -#if SPIFLASH_DEBUG +#ifdef SPIFLASH_DEBUG printf("Write SPI Flash @0x%08lx", ((uint32_t)addr)); #endif @@ -229,7 +229,7 @@ int spiflash_write_stream(uint32_t addr, uint8_t *stream, uint32_t len) page_program(addr+offset, stream+offset, w_len); while(spiflash_read_status_register() & 1) { -#if SPIFLASH_DEBUG +#ifdef SPIFLASH_DEBUG printf("."); #endif } @@ -245,7 +245,7 @@ int spiflash_write_stream(uint32_t addr, uint8_t *stream, uint32_t len) w_len = min(len-offset, SPI_FLASH_BLOCK_SIZE); res = offset; } -#if SPIFLASH_DEBUG +#ifdef SPIFLASH_DEBUG printf("\n"); #endif return res; From c6adf703a345b16a81efbcca58850b69270b0237 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 6 Jun 2023 11:09:44 +0200 Subject: [PATCH 060/454] CHANGES.md: Update. --- CHANGES.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 73c4d324b..a18547672 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,37 @@ +[> Changes since 2023.04 +------------------------ + + [> Fixed + -------- + - lattice/programmer : Fixed ECPDAP frequency specification. + - soc/add_spi_sdcard : Fixed Tristate build. + - csr/fields : Fixed access type checks. + - software/liblitespi : Fixed support with debug. + + [> Added + -------- + - soc/cores/video : Added low resolution video modes. + - interconnect : Added initial AvalonMM support. + - soc/interconnect/packet : Avoided bypass of dispatcher with a single slave. + - build/add_period_constraints : Improved generic platform and simplify specific platforms. + - gen/fhdl/verilog : Added parameter to avoid register initialization (required for ASIC). + - litedram : Added clamshell topology support. + - stream/Pipeline : Added dynamic pipeline creation capability. + - build/xilinx/vivado : Added project commands to allow adding commands just after project creation. + - soc/software : Moved helpers to hw/common.h. + - tools/litex_json2dts_linux : Added sys_clk to device tree and fixed dts warning. + - tools/litex_json2dts_zephyr : Added LiteSD defines. + - build/yosys : Added quiet capability. + - build/efinix : Improved Titanium support (PLL, DRIVE_STRENGTH, SLEW). + - build/openfpgaloader : Added -fpga-part and -index-chain support. + - soc/add_spi_flash : Added software_debug support. + - software/liblitespi : Added read_id support. + - litex_boards : Added QMtech XC7K325T, VCU128, SITLINV_STVL7325_V2, Enclustra XU8/PE3 support. + + [> Changed + ---------- + - + [> 2023.04, released on May 8th 2023 ------------------------------------ From a7ba5771b1213a5dc1405b9480037e164c5226cf Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 9 Jun 2023 15:18:23 +0200 Subject: [PATCH 061/454] integration/soc/add_etherbone: Fix typo. --- litex/soc/integration/soc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index a504d4757..c0fd216fa 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1732,7 +1732,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, "eth_tx": phy_cd + "_tx", "eth_rx": phy_cd + "_rx", "sys": phy_cd + "_rx"})(ethcore) - self.add_module(name=f"ethcode_{name}", module=ethcore) + self.add_module(name=f"ethcore_{name}", module=ethcore) etherbone_cd = "sys" if not with_sys_datapath: From 3a7aaf51249e0b2a824083c3984cb4c7d4c079cf Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 13 Jun 2023 10:00:37 +0200 Subject: [PATCH 062/454] cores/code_8b10b: Add D function. --- litex/soc/cores/code_8b10b.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litex/soc/cores/code_8b10b.py b/litex/soc/cores/code_8b10b.py index 8ae45202e..7e850d2f1 100644 --- a/litex/soc/cores/code_8b10b.py +++ b/litex/soc/cores/code_8b10b.py @@ -30,6 +30,9 @@ def K(x, y): return (y << 5) | x +def D(x, y): + return (y << 5) | x + def disparity(word, nbits): n0 = 0 n1 = 0 From 57840c63a31602f15b03f3b7918a853c951fc9e1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 13 Jun 2023 13:23:47 +0200 Subject: [PATCH 063/454] cores/clock/xilinx_common: Add BUFH support and lower buf parameter before use to allow user to specify it in upper or lower case. --- litex/soc/cores/clock/xilinx_common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litex/soc/cores/clock/xilinx_common.py b/litex/soc/cores/clock/xilinx_common.py index 02b9d9f46..e79ed45ae 100644 --- a/litex/soc/cores/clock/xilinx_common.py +++ b/litex/soc/cores/clock/xilinx_common.py @@ -53,10 +53,13 @@ def create_clkout(self, cd, freq, phase=0, buf="bufg", margin=1e-2, with_reset=T else: clkout_buf = Signal() self.comb += cd.clk.eq(clkout_buf) + buf = buf.lower() if buf == "bufg": self.specials += Instance("BUFG", i_I=clkout, o_O=clkout_buf) elif buf == "bufr": self.specials += Instance("BUFR", i_I=clkout, o_O=clkout_buf) + elif buf == "bufh": + self.specials += Instance("BUFH", i_I=clkout, o_O=clkout_buf) elif buf == "bufgce": if ce is None: raise ValueError("BUFGCE requires user to provide a clock enable ce Signal") From 7a4fa58cbf73c048afdb8f40bf53e60dec412b3b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 13 Jun 2023 18:37:34 +0200 Subject: [PATCH 064/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index a18547672..17dcc266e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,6 +27,7 @@ - soc/add_spi_flash : Added software_debug support. - software/liblitespi : Added read_id support. - litex_boards : Added QMtech XC7K325T, VCU128, SITLINV_STVL7325_V2, Enclustra XU8/PE3 support. + - liteeth : Added Ultrascale+ GTY/GTH SGMII/1000BaseX PHYs. [> Changed ---------- From 3d3ca053593483727f1949b501f065b9d6aaf9f7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 14 Jun 2023 16:59:47 +0200 Subject: [PATCH 065/454] tools/litex_client: Fix read regression. --- litex/tools/litex_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/tools/litex_client.py b/litex/tools/litex_client.py index 9e5c37dea..ff6ac180f 100644 --- a/litex/tools/litex_client.py +++ b/litex/tools/litex_client.py @@ -317,7 +317,7 @@ def timer_callback(refresh=1e-1, xadc_points=100): # CSR Update. for name, reg in bus.regs.__dict__.items(): value = reg.read() - dpg.set_value(item=name, value=f"0x{value():x}") + dpg.set_value(item=name, value=f"0x{value:x}") # XADC Update. if with_xadc: From 56927ee73ab66216681cdc6fe131bb2fd96065f0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 15 Jun 2023 15:45:34 +0200 Subject: [PATCH 066/454] cpu/vexriscv_smp/core: Add add_synthesis_define function to add 'define SYNTHESIS to VexRiscv-SMP generated code for toolchains requiring it. This was causing issue with Gowin synthesis tool and it's not yet clear how to define it from Gowin project. So do it directly in the generated code for now until we find a better solution. See https://github.com/enjoy-digital/litex/issues/1698. --- litex/soc/cores/cpu/vexriscv_smp/core.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index 9b48c79f8..18780e187 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -391,7 +391,21 @@ def add_sources(self, platform): platform.add_source(os.path.join(vdir, ram_filename), "verilog") # Add Cluster. - platform.add_source(os.path.join(vdir, self.cluster_name + ".v"), "verilog") + cluster_filename = os.path.join(vdir, self.cluster_name + ".v") + def add_synthesis_define(filename): + """Add SYNTHESIS define to verilog for toolchains requiring it, ex Gowin""" + synthesis_define = "`define SYNTHESIS\n" + # Read file. + with open(filename, "r") as f: + lines = f.readlines() + # Modify file. + with open(filename, "w") as f: + if lines[0] != synthesis_define: + f.write(synthesis_define) + for line in lines: + f.write(line) + add_synthesis_define(cluster_filename) + platform.add_source(cluster_filename, "verilog") def add_soc_components(self, soc): if self.variant == "linux": From 6e5651b320a423d3dccec89413c273d6467aa1f1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 16 Jun 2023 08:33:23 +0200 Subject: [PATCH 067/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 17dcc266e..cfb636247 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ - soc/add_spi_sdcard : Fixed Tristate build. - csr/fields : Fixed access type checks. - software/liblitespi : Fixed support with debug. + - cpu/vexriscv_smp : Fixed compilation with Gowin toolchain (ex for Tang Nano 20K Linux). [> Added -------- From ae22f4028adb7c99a009c043bc44267012d015d6 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Sun, 18 Jun 2023 21:55:27 +0930 Subject: [PATCH 068/454] microwatt: Correct SoCRegion typo Fixes: 45b96369021a ("integration/soc: Avoid soc_region_cls workaround and update CPUs.") --- litex/soc/cores/cpu/microwatt/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/microwatt/core.py b/litex/soc/cores/cpu/microwatt/core.py index 35df0abc7..cc9208f0c 100644 --- a/litex/soc/cores/cpu/microwatt/core.py +++ b/litex/soc/cores/cpu/microwatt/core.py @@ -154,7 +154,7 @@ def add_soc_components(self, soc): int_level_in = self.interrupt, ) xicsicp_region = SoCRegion(origin=soc.mem_map.get("xicsicp"), size=4096, cached=False) - xicsics_region = SocRegion(origin=soc.mem_map.get("xicsics"), size=4096, cached=False) + xicsics_region = SoCRegion(origin=soc.mem_map.get("xicsics"), size=4096, cached=False) soc.bus.add_slave(name="xicsicp", slave=self.xics.icp_bus, region=xicsicp_region) soc.bus.add_slave(name="xicsics", slave=self.xics.ics_bus, region=xicsics_region) From a9cbb16785db134c333056d83916179bcc7177d6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Jun 2023 09:44:37 +0200 Subject: [PATCH 069/454] soc/add_pcie: Add msi_type parameter to select MSI, MSI-Multi-Vector or MSI-X. --- CHANGES.md | 1 + litex/soc/integration/soc.py | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index cfb636247..b708359e5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,6 +29,7 @@ - software/liblitespi : Added read_id support. - litex_boards : Added QMtech XC7K325T, VCU128, SITLINV_STVL7325_V2, Enclustra XU8/PE3 support. - liteeth : Added Ultrascale+ GTY/GTH SGMII/1000BaseX PHYs. + - soc/add_pcie : Added msi_type parameter to select MSI, MSI-Multi-Vector or MSI-X. [> Changed ---------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index c0fd216fa..b33edf8b8 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1976,12 +1976,12 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre with_dma_synchronizer = False, with_dma_monitor = False, with_dma_status = False, - with_msi = True, + with_msi = True, msi_type="msi", ): # Imports from litepcie.phy.uspciephy import USPCIEPHY from litepcie.phy.usppciephy import USPPCIEPHY - from litepcie.core import LitePCIeEndpoint, LitePCIeMSI + from litepcie.core import LitePCIeEndpoint, LitePCIeMSI, LitePCIeMSIMultiVector, LitePCIeMSIX from litepcie.frontend.dma import LitePCIeDMA from litepcie.frontend.wishbone import LitePCIeWishboneMaster @@ -2005,18 +2005,25 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre # MSI. if with_msi: + assert msi_type in ["msi", "msi-multi-vector", "msi-x"] self.check_if_exists(f"{name}_msi") - msi = LitePCIeMSI() + if msi_type == "msi": + msi = LitePCIeMSI() + if msi_type == "msi-multi-vector": + msi = LitePCIeMSIMultiVector() + if msi_type == "msi-x": + msi = LitePCIeMSIX(endpoint=self.pcie_endpoint) self.add_module(name=f"{name}_msi", module=msi) # FIXME: On Ultrascale/Ultrascale+ limit rate of IRQs to 1MHz (to prevent issue with # IRQs stalled). - if isinstance(phy, (USPCIEPHY, USPPCIEPHY)): - msi_timer = WaitTimer(int(self.sys_clk_freq/1e6)) - self.add_module(name=f"{name}_msi_timer", module=msi_timer) - self.comb += msi_timer.wait.eq(~msi_timer.done) - self.comb += If(msi_timer.done, msi.source.connect(phy.msi)) - else: - self.comb += msi.source.connect(phy.msi) + if msi_type in ["msi", "msi-multi-vector"]: + if isinstance(phy, (USPCIEPHY, USPPCIEPHY)): + msi_timer = WaitTimer(int(self.sys_clk_freq/1e6)) + self.add_module(name=f"{name}_msi_timer", module=msi_timer) + self.comb += msi_timer.wait.eq(~msi_timer.done) + self.comb += If(msi_timer.done, msi.source.connect(phy.msi)) + else: + self.comb += msi.source.connect(phy.msi) self.msis = {} # DMAs. From 94a0a5b0d8968fb52cd193683693bb84676d815a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Jun 2023 09:54:10 +0200 Subject: [PATCH 070/454] soc/add_pcie: Add msi_width parameter to select MSI width. --- CHANGES.md | 1 + litex/soc/integration/soc.py | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b708359e5..89de3bde8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,6 +30,7 @@ - litex_boards : Added QMtech XC7K325T, VCU128, SITLINV_STVL7325_V2, Enclustra XU8/PE3 support. - liteeth : Added Ultrascale+ GTY/GTH SGMII/1000BaseX PHYs. - soc/add_pcie : Added msi_type parameter to select MSI, MSI-Multi-Vector or MSI-X. + - soc/add_pcie : Added msi_width parameter to select MSI width. [> Changed ---------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index b33edf8b8..bd16393ef 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1971,12 +1971,12 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) # Add PCIe ------------------------------------------------------------------------------------- def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, address_width=32, - with_dma_buffering = True, dma_buffering_depth=1024, + with_dma_buffering = True, dma_buffering_depth=1024, with_dma_loopback = True, with_dma_synchronizer = False, with_dma_monitor = False, with_dma_status = False, - with_msi = True, msi_type="msi", + with_msi = True, msi_type="msi", msi_width=32, ): # Imports from litepcie.phy.uspciephy import USPCIEPHY @@ -2008,11 +2008,11 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre assert msi_type in ["msi", "msi-multi-vector", "msi-x"] self.check_if_exists(f"{name}_msi") if msi_type == "msi": - msi = LitePCIeMSI() + msi = LitePCIeMSI(width=msi_width) if msi_type == "msi-multi-vector": - msi = LitePCIeMSIMultiVector() + msi = LitePCIeMSIMultiVector(width=msi_width) if msi_type == "msi-x": - msi = LitePCIeMSIX(endpoint=self.pcie_endpoint) + msi = LitePCIeMSIX(endpoint=self.pcie_endpoint, width=msi_width) self.add_module(name=f"{name}_msi", module=msi) # FIXME: On Ultrascale/Ultrascale+ limit rate of IRQs to 1MHz (to prevent issue with # IRQs stalled). From d2aae18957a769362d5b28cdfd0e9805dbd166c0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Jun 2023 19:21:05 +0200 Subject: [PATCH 071/454] soc/add_pcie/MSI-X: Pass csr_ordering to LitePCIeMSIX. --- CHANGES.md | 1 + litex/soc/integration/soc.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 89de3bde8..d9ec5e664 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -31,6 +31,7 @@ - liteeth : Added Ultrascale+ GTY/GTH SGMII/1000BaseX PHYs. - soc/add_pcie : Added msi_type parameter to select MSI, MSI-Multi-Vector or MSI-X. - soc/add_pcie : Added msi_width parameter to select MSI width. + - litepcie : Added 7-Series MSI-X capability/integration. [> Changed ---------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index bd16393ef..5e1878cea 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -2012,7 +2012,7 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre if msi_type == "msi-multi-vector": msi = LitePCIeMSIMultiVector(width=msi_width) if msi_type == "msi-x": - msi = LitePCIeMSIX(endpoint=self.pcie_endpoint, width=msi_width) + msi = LitePCIeMSIX(endpoint=self.pcie_endpoint, width=msi_width, csr_ordering=self.csr.ordering) self.add_module(name=f"{name}_msi", module=msi) # FIXME: On Ultrascale/Ultrascale+ limit rate of IRQs to 1MHz (to prevent issue with # IRQs stalled). From 7b5515ced477c43f330c0a646dae2c63d9d230e5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Jun 2023 23:02:50 +0200 Subject: [PATCH 072/454] cores/pwm: Simplify pwm generation and avoid potential glitch on reset. --- litex/soc/cores/pwm.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/litex/soc/cores/pwm.py b/litex/soc/cores/pwm.py index 20818ecfe..bdc762981 100644 --- a/litex/soc/cores/pwm.py +++ b/litex/soc/cores/pwm.py @@ -47,14 +47,7 @@ def __init__(self, pwm=None, clock_domain="sys", counter=None, with_csr=True, ] # PWM Width logic. - sync += [ - pwm.eq(0), - If(self.enable & ~self.reset, - If(counter < self.width, - pwm.eq(1) - ) - ) - ] + sync += pwm.eq(self.enable & (counter < self.width)) if with_csr: self.add_csr(clock_domain) From fbe3fcf76ad1a872d4fe8b3cb4d06baf6d017671 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Jun 2023 12:46:16 +0200 Subject: [PATCH 073/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index d9ec5e664..79ccfbe87 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ - csr/fields : Fixed access type checks. - software/liblitespi : Fixed support with debug. - cpu/vexriscv_smp : Fixed compilation with Gowin toolchain (ex for Tang Nano 20K Linux). + - liteiclink/serwb : Fixed 7-Series initialization corner cases. [> Added -------- @@ -32,6 +33,7 @@ - soc/add_pcie : Added msi_type parameter to select MSI, MSI-Multi-Vector or MSI-X. - soc/add_pcie : Added msi_width parameter to select MSI width. - litepcie : Added 7-Series MSI-X capability/integration. + - liteiclink : Improved GTH3/GTH4 support and similarity with Wizard's generated code. [> Changed ---------- From a9d6a0c6c91e8a9accb17af27c05607089ef6883 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 22 Jun 2023 17:40:41 +0200 Subject: [PATCH 074/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 79ccfbe87..be2ada631 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -34,6 +34,7 @@ - soc/add_pcie : Added msi_width parameter to select MSI width. - litepcie : Added 7-Series MSI-X capability/integration. - liteiclink : Improved GTH3/GTH4 support and similarity with Wizard's generated code. + - liteeth_gen : Added SGMII/1000BaseX PHYs support. [> Changed ---------- From 7d1e12c870450f3570803b062ef9f099150525e3 Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Tue, 20 Jun 2023 13:26:30 -0400 Subject: [PATCH 075/454] software/liblitesata: update to multi-sector read, write The LiteSATA gateware now supports multi-sector transfers, and expects a sector count register to be populated by the software before a DMA transfer is initiated. This patch also fixes checks for `done` and `error` during writes by using the correct `mem2sector` read function (instead of `sector2mem`, which is for use during read operations). Signed-off-by: Gabriel Somlo --- litex/soc/software/liblitesata/sata.c | 45 +++++++++++---------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/litex/soc/software/liblitesata/sata.c b/litex/soc/software/liblitesata/sata.c index 9650593b5..fd3fd67de 100644 --- a/litex/soc/software/liblitesata/sata.c +++ b/litex/soc/software/liblitesata/sata.c @@ -100,20 +100,16 @@ int sata_init(int show) { void sata_read(uint32_t sector, uint32_t count, uint8_t* buf) { - uint32_t i; - - /* Write sectors */ - for (i=0; i Date: Tue, 20 Jun 2023 13:32:40 -0400 Subject: [PATCH 076/454] software/bios/cmd_litesata: add multi-sector xfer between SATA and memory Signed-off-by: Gabriel Somlo --- litex/soc/software/bios/cmds/cmd_litesata.c | 76 +++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/litex/soc/software/bios/cmds/cmd_litesata.c b/litex/soc/software/bios/cmds/cmd_litesata.c index 811998336..83b0c3728 100644 --- a/litex/soc/software/bios/cmds/cmd_litesata.c +++ b/litex/soc/software/bios/cmds/cmd_litesata.c @@ -58,6 +58,44 @@ static void sata_read_handler(int nb_params, char **params) } define_command(sata_read, sata_read_handler, "Read SATA sector", LITESATA_CMDS); + +static void sata_sec2mem_handler(int nb_params, char **params) +{ + char *c; + unsigned int sec, cnt; + uint8_t *dst; + + if (nb_params < 2) { + printf("sata_s2m [count]"); + return; + } + + sec = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect sector number"); + return; + } + + dst = (uint8_t *)strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect destination address"); + return; + } + + if (nb_params == 2) { + cnt = 1; + } else { + cnt = strtoul(params[2], &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + } + + sata_read(sec, cnt, dst); +} + +define_command(sata_sec2mem, sata_sec2mem_handler, "Read SATA into memory", LITESATA_CMDS); #endif /** @@ -99,4 +137,42 @@ static void sata_write_handler(int nb_params, char **params) } define_command(sata_write, sata_write_handler, "Write SATA sector", LITESATA_CMDS); + +static void sata_mem2sec_handler(int nb_params, char **params) +{ + char *c; + unsigned int sec, cnt; + uint8_t *src; + + if (nb_params < 2) { + printf("sata_s2m [count]"); + return; + } + + src = (uint8_t *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect source address"); + return; + } + + sec = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect sector number"); + return; + } + + if (nb_params == 2) { + cnt = 1; + } else { + cnt = strtoul(params[2], &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + } + + sata_write(sec, cnt, src); +} + +define_command(sata_mem2sec, sata_mem2sec_handler, "Write SATA from memory", LITESATA_CMDS); #endif From 8dca488432f85debad73710c88caa52f98c4be4f Mon Sep 17 00:00:00 2001 From: Gabriel Somlo Date: Wed, 21 Jun 2023 15:20:42 -0400 Subject: [PATCH 077/454] software/bios/cmd_litesata: add multisector read/write test --- litex/soc/software/bios/cmds/cmd_litesata.c | 140 ++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/litex/soc/software/bios/cmds/cmd_litesata.c b/litex/soc/software/bios/cmds/cmd_litesata.c index 83b0c3728..10511c203 100644 --- a/litex/soc/software/bios/cmds/cmd_litesata.c +++ b/litex/soc/software/bios/cmds/cmd_litesata.c @@ -176,3 +176,143 @@ static void sata_mem2sec_handler(int nb_params, char **params) define_command(sata_mem2sec, sata_mem2sec_handler, "Write SATA from memory", LITESATA_CMDS); #endif + +/* LiteSATA read/write test */ +#if defined(CSR_SATA_SECTOR2MEM_BASE) && defined(CSR_SATA_MEM2SECTOR_BASE) +#include +static int sata_rd(uint32_t sector, uint32_t count, void *mem) +{ + uint32_t done_cnt; + uint8_t retry_cnt; + + for (retry_cnt = 8; retry_cnt > 0; retry_cnt--) { + sata_sector2mem_base_write((uint64_t)(uintptr_t)mem); + sata_sector2mem_sector_write(sector); + sata_sector2mem_nsectors_write(count); + sata_sector2mem_start_write(1); + for (done_cnt = 0x0000ffff; done_cnt > 0; done_cnt --) { + if ((sata_sector2mem_done_read() & 0x1) != 0) { + if ((sata_sector2mem_error_read() & 0x1) == 0) + return 0; + else { + printf("sata_rd: op failed, retry\n"); + break; + } + } + } + printf("sata_rd: op timeout (done_cnt)\n"); + busy_wait_us(10); + } + printf("sata_rd: out of retries\n"); + return -1; +} + +static int sata_rd_1(uint32_t sector, uint32_t count, void *mem) +{ + while(count--) { + sata_read(sector++, 1, mem); + mem += 512; + } + return 0; +} + +static int sata_wr(uint32_t sector, uint32_t count, void *mem) +{ + uint32_t done_cnt; + uint8_t retry_cnt; + + for (retry_cnt = 8; retry_cnt > 0; retry_cnt--) { + sata_mem2sector_base_write((uint64_t)(uintptr_t)mem); + sata_mem2sector_sector_write(sector); + sata_mem2sector_nsectors_write(count); + sata_mem2sector_start_write(1); + for (done_cnt = 0x000fffff; done_cnt > 0; done_cnt --) { + if ((sata_mem2sector_done_read() & 0x1) != 0) { + if ((sata_mem2sector_error_read() & 0x1) == 0) + return 0; + else { + printf("sata_wr: op failed, retry\n"); + break; + } + } + } + printf("sata_wr: op timeout (done_cnt)\n"); + busy_wait_us(10); + } + printf("sata_wr: out of retries\n"); + return -1; +} + +static int sata_mem_cmp(char *mem1, char *mem2, uint32_t count) +{ + uint32_t i, j; + + for (i = 0; i < count; i++) + for (j = 0; j < 512; j++) + if (mem1[512*i + j] != mem2[512*i + j]) { + printf("sata_mem_cmp: mismatch in sector %d " + "byte %d: %d != %d\n", + i, j, mem1[512*i + j], mem2[512*i + j]); + return -1; + } + return 0; +} + +static int sata_do_rwtest(uint32_t sec, uint32_t cnt, char *mem, char *str) +{ + char *c = str; + int i; + + if (c != NULL) { + for (i = 0; i < 512 * cnt; i++) { + mem[i] = *c++; + if (*c == 0) + c = str; + } + } + if (sata_wr(sec, cnt, mem) < 0) + return -1; + if (sata_rd(sec, cnt, mem + 512*cnt) < 0) + return -1; + if (sata_mem_cmp(mem, mem + 512*cnt, cnt) == 0) + return 0; + printf("compare failed, retrying with single-sector reads:\n"); + return sata_rd_1(sec, cnt, mem + 512*cnt); +} + +static void sata_rwtest_handler(int nb_params, char **params) +{ + unsigned int sec, cnt; + char *mem; + char *c; + + if (nb_params < 4) { + printf("sata_rwtest
"); + return; + } + + sec = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("incorrect sector"); + return; + } + + mem = (char *)strtoul(params[1], &c, 0); + if (*c != 0) { + printf("incorrect address"); + return; + } + + cnt = strtoul(params[2], &c, 0); + if (*c != 0) { + printf("incorrect count"); + return; + } + + if (sata_do_rwtest(sec, cnt, mem, params[3])) + printf("Failure."); + else + printf("Success."); +} +define_command(sata_rwtest, sata_rwtest_handler, "SATA read/write test", LITESATA_CMDS); +#endif From 7a7c74faa9b02f70ebb6e0f8a08abdc7411a368b Mon Sep 17 00:00:00 2001 From: Nate Slager Date: Fri, 23 Jun 2023 23:57:44 -0700 Subject: [PATCH 078/454] fix radiant bug 'Mal-formed command line - please check for extra quotes in macro' (#1718) * fix radiant bug 'Mal-formed command line - please check for extra quotes in macro' * fix Radiant Mal-formed command line bug (more pythonic) * (typo, rm line 159) fix Radiant Mal-formed command line bug --------- Co-authored-by: slagernate@github.com --- litex/build/lattice/radiant.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/build/lattice/radiant.py b/litex/build/lattice/radiant.py index b635c539f..a0ab290a7 100644 --- a/litex/build/lattice/radiant.py +++ b/litex/build/lattice/radiant.py @@ -153,7 +153,8 @@ def tcl_path(path): return path.replace("\\", "/") # Add include paths vincpath = ";".join(map(lambda x: tcl_path(x), self.platform.verilog_include_paths)) - tcl.append("prj_set_impl_opt {include path} {\"" + vincpath + "\"}") + if vincpath and vincpath.strip(): + tcl.append("prj_set_impl_opt {include path} {\"" + vincpath + "\"}") # Add sources if self._synth_mode == "yosys": From 5524a17702b7228f2d5d97fad41762a1898f913d Mon Sep 17 00:00:00 2001 From: Arne Jansen Date: Tue, 27 Jun 2023 09:45:50 +0200 Subject: [PATCH 079/454] add tx_write_only flag to add_ethernet This can save some resources in case reading the tx buffer is not needed. It also makes it easier for synthesis to infer BRAM, tested on Spartan6. --- litex/soc/integration/soc.py | 2 ++ litex/soc/interconnect/wishbone.py | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 5e1878cea..b411d2a73 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1646,6 +1646,7 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, data_width = 8, nrxslots = 2, ntxslots = 2, + tx_write_only = False, with_timestamp = False, with_timing_constraints = True): # Imports @@ -1665,6 +1666,7 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, endianness = self.cpu.endianness, nrxslots = nrxslots, ntxslots = ntxslots, + tx_write_only = tx_write_only, timestamp = None if not with_timestamp else self.timer0.uptime_cycles, with_preamble_crc = not software_debug, with_sys_datapath = with_sys_datapath) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 359ed10b6..12143df36 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -362,7 +362,7 @@ def __init__(self, master, slave): # Wishbone SRAM ------------------------------------------------------------------------------------ class SRAM(Module): - def __init__(self, mem_or_size, read_only=None, init=None, bus=None, name=None): + def __init__(self, mem_or_size, read_only=None, write_only=None, init=None, bus=None, name=None): if bus is None: bus = Interface() self.bus = bus @@ -468,11 +468,12 @@ def __init__(self, mem_or_size, read_only=None, init=None, bus=None, name=None): self.comb += If(adr_burst & adr_latched, port.adr.eq(adr_next[:len(port.adr)]), ) - self.comb += [ - self.bus.dat_r.eq(port.dat_r) - ] + + if not write_only: + self.comb += self.bus.dat_r.eq(port.dat_r) + if not read_only: - self.comb += port.dat_w.eq(self.bus.dat_w), + self.comb += port.dat_w.eq(self.bus.dat_w) # Generate Ack. self.sync += [ From 2cdc4fb0abd811f299206be7422d2febe0190d1b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 27 Jun 2023 14:32:20 +0200 Subject: [PATCH 080/454] ci: Use last known working version of Verilator for Microwatt (Thanks @trabucayre). --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd58f6327..cbfa106f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,7 @@ jobs: export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" git clone https://github.com/verilator/verilator cd verilator + git checkout 7d2d32420a630befa4097170ecbf227e04e32522 autoconf ./configure make -j$(nproc) From 648c70de82b69013988eda9c7c25e1a259ce9955 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 28 Jun 2023 23:07:17 +0200 Subject: [PATCH 081/454] cmd_litesata: Fix help printf and update CHANGES. --- CHANGES.md | 1 + litex/soc/software/bios/cmds/cmd_litesata.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index be2ada631..556ff0700 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,6 +35,7 @@ - litepcie : Added 7-Series MSI-X capability/integration. - liteiclink : Improved GTH3/GTH4 support and similarity with Wizard's generated code. - liteeth_gen : Added SGMII/1000BaseX PHYs support. + - litesata/dma : Add multi-sector support. [> Changed ---------- diff --git a/litex/soc/software/bios/cmds/cmd_litesata.c b/litex/soc/software/bios/cmds/cmd_litesata.c index 10511c203..d487d1af8 100644 --- a/litex/soc/software/bios/cmds/cmd_litesata.c +++ b/litex/soc/software/bios/cmds/cmd_litesata.c @@ -66,7 +66,7 @@ static void sata_sec2mem_handler(int nb_params, char **params) uint8_t *dst; if (nb_params < 2) { - printf("sata_s2m [count]"); + printf("sata_sec2mem [count]"); return; } @@ -145,7 +145,7 @@ static void sata_mem2sec_handler(int nb_params, char **params) uint8_t *src; if (nb_params < 2) { - printf("sata_s2m [count]"); + printf("sata_mem2sec [count]"); return; } From a12703b4ee70d0940d8d11aaceb43f636fa3ab35 Mon Sep 17 00:00:00 2001 From: Rasmus Pedersen Date: Thu, 29 Jun 2023 14:13:49 +0200 Subject: [PATCH 082/454] litex_json2renode: only add cpu timeProvider if time_provider exists --- litex/tools/litex_json2renode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 3cd37aa73..6259b6d40 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -297,7 +297,7 @@ def unpack_properties(prop_list): cpu{cpu_id}: CPU.{cpu_string.strip()} hartId: {cpu_id} """ - if cpu.get('supports_time_provider', False): + if cpu.get('supports_time_provider', False) and time_provider: result += f' timeProvider: {time_provider}\n' return result From 8d33dc364ff4daa2695fa35e8dface0e13f61271 Mon Sep 17 00:00:00 2001 From: Rasmus Pedersen Date: Fri, 30 Jun 2023 13:44:31 +0200 Subject: [PATCH 083/454] Only add "cpu PC " if opensbi is present --- litex/tools/litex_json2renode.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 6259b6d40..61bd82f04 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -889,8 +889,9 @@ def generate_resc(csr, number_of_cores, args, flash_binaries={}, tftp_binaries={ sysbus LoadBinary @{} {} """.format(args.bios_binary, hex(opensbi_base)) - for cpu_id in range(0, number_of_cores): - result += f"cpu{cpu_id} PC {hex(opensbi_base)}\n" + if opensbi_base: + for cpu_id in range(0, number_of_cores): + result += f"cpu{cpu_id} PC {hex(opensbi_base)}\n" if args.tftp_ip: result += """ From 26ed13a3006f3c65e0e0219f462b524029e1f4bd Mon Sep 17 00:00:00 2001 From: Rasmus Pedersen Date: Fri, 30 Jun 2023 13:45:40 +0200 Subject: [PATCH 084/454] Assume cpu count 1 if not present --- litex/tools/litex_json2renode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 61bd82f04..08a5440b5 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -214,7 +214,7 @@ def get_cpu_type(csr): return (kind, variant) def get_cpu_count(csr): - return csr['constants']['config_cpu_count'] + return csr['constants'].get('config_cpu_count', 1) vexriscv_common_kind = { 'name': 'VexRiscv', From 7fa7a4c72a994955637cf13ac760c32e0845604a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 3 Jul 2023 10:50:47 +0200 Subject: [PATCH 085/454] soc/add_ethernet: Review/Minor changes to TXSlots write-only mode. --- litex/soc/integration/soc.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index b411d2a73..6f185a5c7 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1644,9 +1644,8 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, # Add Ethernet --------------------------------------------------------------------------------- def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, software_debug=False, data_width = 8, - nrxslots = 2, - ntxslots = 2, - tx_write_only = False, + nrxslots = 2, rxslots_read_only = True, + ntxslots = 2, txslots_write_only = False, with_timestamp = False, with_timing_constraints = True): # Imports @@ -1664,9 +1663,8 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, dw = 32, interface = "wishbone", endianness = self.cpu.endianness, - nrxslots = nrxslots, - ntxslots = ntxslots, - tx_write_only = tx_write_only, + nrxslots = nrxslots, rxslots_read_only = rxslots_read_only, + ntxslots = ntxslots, txslots_write_only = txslots_write_only, timestamp = None if not with_timestamp else self.timer0.uptime_cycles, with_preamble_crc = not software_debug, with_sys_datapath = with_sys_datapath) From a2d44370bd8409c6eb267971e16c275b43f9815b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 3 Jul 2023 10:56:29 +0200 Subject: [PATCH 086/454] CHANGES: Update. --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 556ff0700..f41ec2435 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,7 +35,8 @@ - litepcie : Added 7-Series MSI-X capability/integration. - liteiclink : Improved GTH3/GTH4 support and similarity with Wizard's generated code. - liteeth_gen : Added SGMII/1000BaseX PHYs support. - - litesata/dma : Add multi-sector support. + - litesata/dma : Added multi-sector support. + - liteeth/mac : Added TX Slots write-only mode for improved resource usage when software does not read buffer. [> Changed ---------- From c58f46bb7981b935f44d1e01fc92623492ee1a15 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 3 Jul 2023 18:09:56 +0200 Subject: [PATCH 087/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index f41ec2435..015d59425 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,6 +37,7 @@ - liteeth_gen : Added SGMII/1000BaseX PHYs support. - litesata/dma : Added multi-sector support. - liteeth/mac : Added TX Slots write-only mode for improved resource usage when software does not read buffer. + - liteeth/core : Added DHCP support for CPU-less hardware stack. [> Changed ---------- From 54f466772b392101933dda2c2828364866047aa5 Mon Sep 17 00:00:00 2001 From: stone3311 Date: Wed, 5 Jul 2023 20:13:36 +0200 Subject: [PATCH 088/454] cores/zynqmp: Fix boot helper --- litex/soc/cores/cpu/zynqmp/boot-helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/zynqmp/boot-helper.c b/litex/soc/cores/cpu/zynqmp/boot-helper.c index 4dd8ae2d3..f16e05298 100644 --- a/litex/soc/cores/cpu/zynqmp/boot-helper.c +++ b/litex/soc/cores/cpu/zynqmp/boot-helper.c @@ -1,5 +1,5 @@ void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { - goto *addr; + goto *(void*)addr; } From 6f98053b1acfaf3944e5509a26cb9292f93a8a6f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 6 Jul 2023 22:03:41 +0200 Subject: [PATCH 089/454] litex/gen: Add copy of genlib.misc to prepare for #1727. --- litex/gen/genlib/__init__.py | 0 litex/gen/genlib/misc.py | 104 +++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 litex/gen/genlib/__init__.py create mode 100644 litex/gen/genlib/misc.py diff --git a/litex/gen/genlib/__init__.py b/litex/gen/genlib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/litex/gen/genlib/misc.py b/litex/gen/genlib/misc.py new file mode 100644 index 000000000..a44ef6d39 --- /dev/null +++ b/litex/gen/genlib/misc.py @@ -0,0 +1,104 @@ +from migen.fhdl.structure import * +from migen.fhdl.module import Module +from migen.fhdl.bitcontainer import bits_for + + +def split(v, *counts): + r = [] + offset = 0 + for n in counts: + if n != 0: + r.append(v[offset:offset+n]) + else: + r.append(None) + offset += n + return tuple(r) + + +def displacer(signal, shift, output, n=None, reverse=False): + if shift is None: + return output.eq(signal) + if n is None: + n = 2**len(shift) + w = len(signal) + if reverse: + r = reversed(range(n)) + else: + r = range(n) + l = [Replicate(shift == i, w) & signal for i in r] + return output.eq(Cat(*l)) + + +def chooser(signal, shift, output, n=None, reverse=False): + if shift is None: + return output.eq(signal) + if n is None: + n = 2**len(shift) + w = len(output) + cases = {} + for i in range(n): + if reverse: + s = n - i - 1 + else: + s = i + cases[i] = [output.eq(signal[s*w:(s+1)*w])] + return Case(shift, cases).makedefault() + + +def timeline(trigger, events): + lastevent = max([e[0] for e in events]) + counter = Signal(max=lastevent+1) + + counterlogic = If(counter != 0, + counter.eq(counter + 1) + ).Elif(trigger, + counter.eq(1) + ) + # insert counter reset if it doesn't naturally overflow + # (test if lastevent+1 is a power of 2) + if (lastevent & (lastevent + 1)) != 0: + counterlogic = If(counter == lastevent, + counter.eq(0) + ).Else( + counterlogic + ) + + def get_cond(e): + if e[0] == 0: + return trigger & (counter == 0) + else: + return counter == e[0] + sync = [If(get_cond(e), *e[1]) for e in events] + sync.append(counterlogic) + return sync + + +class WaitTimer(Module): + def __init__(self, t): + self.wait = Signal() + self.done = Signal() + + # # # + + count = Signal(bits_for(t), reset=t) + self.comb += self.done.eq(count == 0) + self.sync += \ + If(self.wait, + If(~self.done, count.eq(count - 1)) + ).Else(count.eq(count.reset)) + + +class BitSlip(Module): + def __init__(self, dw): + self.i = Signal(dw) + self.o = Signal(dw) + self.value = Signal(max=dw) + + # # # + + r = Signal(2*dw) + self.sync += r.eq(Cat(r[dw:], self.i)) + cases = {} + for i in range(dw): + cases[i] = self.o.eq(r[i:dw+i]) + self.sync += Case(self.value, cases) From e9739b5446256f700803c030459a7b1134a35b0c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 6 Jul 2023 22:05:23 +0200 Subject: [PATCH 090/454] soc: Switch to litex.gen.genlib.misc. --- litex/soc/cores/esc.py | 2 +- litex/soc/cores/hyperbus.py | 3 ++- litex/soc/cores/led.py | 3 ++- litex/soc/cores/prbs.py | 2 +- litex/soc/cores/uart.py | 3 ++- litex/soc/integration/soc.py | 2 +- litex/soc/interconnect/axi/axi_common.py | 7 +++++-- litex/soc/interconnect/axi/axi_full.py | 5 +++-- litex/soc/interconnect/axi/axi_lite.py | 5 +++-- litex/soc/interconnect/csr_bus.py | 2 +- litex/soc/interconnect/wishbone.py | 2 +- 11 files changed, 22 insertions(+), 14 deletions(-) diff --git a/litex/soc/cores/esc.py b/litex/soc/cores/esc.py index c0e438998..573f47efd 100644 --- a/litex/soc/cores/esc.py +++ b/litex/soc/cores/esc.py @@ -7,9 +7,9 @@ import math from migen import * -from migen.genlib.misc import WaitTimer from litex.gen import LiteXModule +from litex.gen.genlib.misc import WaitTimer from litex.soc.interconnect.csr import * from litex.soc.interconnect import wishbone diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index 594c3791e..fbc3d8ddd 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -7,7 +7,8 @@ # SPDX-License-Identifier: BSD-2-Clause from migen import * -from migen.genlib.misc import WaitTimer + +from litex.gen.genlib.misc import WaitTimer from litex.build.io import DifferentialOutput diff --git a/litex/soc/cores/led.py b/litex/soc/cores/led.py index 2781eb00f..99f8f8168 100644 --- a/litex/soc/cores/led.py +++ b/litex/soc/cores/led.py @@ -8,7 +8,8 @@ import math from migen import * -from migen.genlib.misc import WaitTimer + +from litex.gen.genlib.misc import WaitTimer from litex.soc.interconnect.csr import * from litex.soc.interconnect import wishbone diff --git a/litex/soc/cores/prbs.py b/litex/soc/cores/prbs.py index 662f62fcb..0eb8be971 100644 --- a/litex/soc/cores/prbs.py +++ b/litex/soc/cores/prbs.py @@ -6,10 +6,10 @@ # SPDX-License-Identifier: BSD-2-Clause from migen import * -from migen.genlib.misc import WaitTimer from migen.genlib.cdc import MultiReg from litex.gen import * +from litex.gen.genlib.misc import WaitTimer # Constants ---------------------------------------------------------------------------------------- diff --git a/litex/soc/cores/uart.py b/litex/soc/cores/uart.py index 5a6d147b9..eec88784b 100644 --- a/litex/soc/cores/uart.py +++ b/litex/soc/cores/uart.py @@ -12,7 +12,8 @@ from migen import * from migen.genlib.record import Record from migen.genlib.cdc import MultiReg -from migen.genlib.misc import WaitTimer + +from litex.gen.genlib.misc import WaitTimer from litex.soc.interconnect.csr import * from litex.soc.interconnect.csr_eventmanager import * diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 6f185a5c7..54fbd792d 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -15,10 +15,10 @@ from math import log2, ceil from migen import * -from migen.genlib.misc import WaitTimer from litex.gen import colorer from litex.gen import LiteXModule +from litex.gen.genlib.misc import WaitTimer from litex.gen.fhdl.hierarchy import LiteXHierarchyExplorer from litex.compat.soc_core import * diff --git a/litex/soc/interconnect/axi/axi_common.py b/litex/soc/interconnect/axi/axi_common.py index a0744e905..41b666436 100644 --- a/litex/soc/interconnect/axi/axi_common.py +++ b/litex/soc/interconnect/axi/axi_common.py @@ -9,11 +9,14 @@ from migen import * from migen.genlib import roundrobin -from migen.genlib.misc import WaitTimer -from litex.soc.interconnect import stream +from litex.gen.genlib.misc import WaitTimer + from litex.build.generic_platform import * +from litex.soc.interconnect import stream + + # AXI Constants ------------------------------------------------------------------------------------ BURST_FIXED = 0b00 diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index a6b5e4319..f14d94438 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -9,11 +9,12 @@ from migen import * from migen.genlib import roundrobin -from migen.genlib.misc import WaitTimer -from litex.soc.interconnect import stream +from litex.gen.genlib.misc import WaitTimer + from litex.build.generic_platform import * +from litex.soc.interconnect import stream from litex.soc.interconnect.axi.axi_common import * from litex.soc.interconnect.axi.axi_stream import AXIStreamInterface diff --git a/litex/soc/interconnect/axi/axi_lite.py b/litex/soc/interconnect/axi/axi_lite.py index 388b9b6fc..b336efec5 100644 --- a/litex/soc/interconnect/axi/axi_lite.py +++ b/litex/soc/interconnect/axi/axi_lite.py @@ -9,11 +9,12 @@ from migen import * from migen.genlib import roundrobin -from migen.genlib.misc import WaitTimer -from litex.soc.interconnect import stream +from litex.gen.genlib.misc import WaitTimer + from litex.build.generic_platform import * +from litex.soc.interconnect import stream from litex.soc.interconnect.axi.axi_common import * # AXI-Lite Definition ------------------------------------------------------------------------------ diff --git a/litex/soc/interconnect/csr_bus.py b/litex/soc/interconnect/csr_bus.py index 757bb956e..00a40b7ee 100644 --- a/litex/soc/interconnect/csr_bus.py +++ b/litex/soc/interconnect/csr_bus.py @@ -16,10 +16,10 @@ from migen import * from migen.genlib.record import * -from migen.genlib.misc import chooser from migen.util.misc import xdir from litex.gen import * +from litex.gen.genlib.misc import chooser from litex.soc.interconnect import csr from litex.soc.interconnect.csr import CSRStorage diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 12143df36..ce8e63314 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -14,9 +14,9 @@ from migen import * from migen.genlib import roundrobin from migen.genlib.record import * -from migen.genlib.misc import split, displacer, chooser, WaitTimer from litex.gen import * +from litex.gen.genlib.misc import split, displacer, chooser, WaitTimer from litex.build.generic_platform import * From 2b941cdcd930f5013c6e0374b2678b2bdd1e6121 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 6 Jul 2023 22:23:54 +0200 Subject: [PATCH 091/454] gen/genlib: Add copy of genlib.cdc modules that we are using and not supported by Amaranth to prepare #1727. --- litex/gen/genlib/cdc.py | 94 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 litex/gen/genlib/cdc.py diff --git a/litex/gen/genlib/cdc.py b/litex/gen/genlib/cdc.py new file mode 100644 index 000000000..b77356be8 --- /dev/null +++ b/litex/gen/genlib/cdc.py @@ -0,0 +1,94 @@ +""" +Clock domain crossing module +""" +from math import gcd + +from migen import * + +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.gen.genlib.misc import WaitTimer + + +class BusSynchronizer(Module): + """Clock domain transfer of several bits at once. + + Ensures that all the bits form a single word that was present + synchronously in the input clock domain (unlike direct use of + ``MultiReg``).""" + def __init__(self, width, idomain, odomain, timeout=128): + self.i = Signal(width) + self.o = Signal(width, reset_less=True) + + if width == 1: + self.specials += MultiReg(self.i, self.o, odomain) + else: + sync_i = getattr(self.sync, idomain) + sync_o = getattr(self.sync, odomain) + + starter = Signal(reset=1) + sync_i += starter.eq(0) + self.submodules._ping = PulseSynchronizer(idomain, odomain) + # Extra flop on i->o to avoid race between data and request + # https://github.com/m-labs/nmigen/pull/40#issuecomment-484166790 + ping_o = Signal() + sync_o += ping_o.eq(self._ping.o) + self.submodules._pong = PulseSynchronizer(odomain, idomain) + self.submodules._timeout = ClockDomainsRenamer(idomain)( + WaitTimer(timeout)) + self.comb += [ + self._timeout.wait.eq(~self._ping.i), + self._ping.i.eq(starter | self._pong.o | self._timeout.done), + self._pong.i.eq(ping_o) + ] + + ibuffer = Signal(width, reset_less=True) + obuffer = Signal(width) # registered reset_less by MultiReg + sync_i += If(self._pong.o, ibuffer.eq(self.i)) + ibuffer.attr.add("no_retiming") + self.specials += MultiReg(ibuffer, obuffer, odomain) + sync_o += If(ping_o, self.o.eq(obuffer)) + + +class ElasticBuffer(Module): + def __init__(self, width, depth, idomain, odomain): + self.din = Signal(width) + self.dout = Signal(width) + + # # # + + reset = Signal() + cd_write = ClockDomain() + cd_read = ClockDomain() + self.comb += [ + cd_write.clk.eq(ClockSignal(idomain)), + cd_read.clk.eq(ClockSignal(odomain)), + reset.eq(ResetSignal(idomain) | ResetSignal(odomain)) + ] + self.specials += [ + AsyncResetSynchronizer(cd_write, reset), + AsyncResetSynchronizer(cd_read, reset) + ] + self.clock_domains += cd_write, cd_read + + wrpointer = Signal(max=depth, reset=depth//2) + rdpointer = Signal(max=depth) + + storage = Memory(width, depth) + self.specials += storage + + wrport = storage.get_port(write_capable=True, clock_domain="write") + rdport = storage.get_port(clock_domain="read") + self.specials += wrport, rdport + + self.sync.write += wrpointer.eq(wrpointer + 1) + self.sync.read += rdpointer.eq(rdpointer + 1) + + self.comb += [ + wrport.we.eq(1), + wrport.adr.eq(wrpointer), + wrport.dat_w.eq(self.din), + + rdport.adr.eq(rdpointer), + self.dout.eq(rdport.dat_r) + ] From e62f51c3eb72394390e01c0ec78fa257c502038b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 7 Jul 2023 11:51:04 +0200 Subject: [PATCH 092/454] gen/genlib/cdc: Add missing import. --- litex/gen/genlib/cdc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/gen/genlib/cdc.py b/litex/gen/genlib/cdc.py index b77356be8..130869f83 100644 --- a/litex/gen/genlib/cdc.py +++ b/litex/gen/genlib/cdc.py @@ -5,6 +5,7 @@ from migen import * +from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer from litex.gen.genlib.misc import WaitTimer From 42c422e767f80f6e086c67feeb464f4cda891ae9 Mon Sep 17 00:00:00 2001 From: stone3311 Date: Sun, 9 Jul 2023 19:16:06 +0200 Subject: [PATCH 093/454] cores/arm: Fix computed goto in boot helpers --- litex/soc/cores/cpu/cortex_m1/boot-helper.c | 2 +- litex/soc/cores/cpu/cortex_m3/boot-helper.c | 2 +- litex/soc/cores/cpu/eos_s3/boot-helper.c | 2 +- litex/soc/cores/cpu/gowin_emcu/boot-helper.c | 2 +- litex/soc/cores/cpu/zynq7000/boot-helper.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/soc/cores/cpu/cortex_m1/boot-helper.c b/litex/soc/cores/cpu/cortex_m1/boot-helper.c index 4dd8ae2d3..f16e05298 100644 --- a/litex/soc/cores/cpu/cortex_m1/boot-helper.c +++ b/litex/soc/cores/cpu/cortex_m1/boot-helper.c @@ -1,5 +1,5 @@ void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { - goto *addr; + goto *(void*)addr; } diff --git a/litex/soc/cores/cpu/cortex_m3/boot-helper.c b/litex/soc/cores/cpu/cortex_m3/boot-helper.c index 4dd8ae2d3..f16e05298 100644 --- a/litex/soc/cores/cpu/cortex_m3/boot-helper.c +++ b/litex/soc/cores/cpu/cortex_m3/boot-helper.c @@ -1,5 +1,5 @@ void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { - goto *addr; + goto *(void*)addr; } diff --git a/litex/soc/cores/cpu/eos_s3/boot-helper.c b/litex/soc/cores/cpu/eos_s3/boot-helper.c index 4dd8ae2d3..f16e05298 100644 --- a/litex/soc/cores/cpu/eos_s3/boot-helper.c +++ b/litex/soc/cores/cpu/eos_s3/boot-helper.c @@ -1,5 +1,5 @@ void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { - goto *addr; + goto *(void*)addr; } diff --git a/litex/soc/cores/cpu/gowin_emcu/boot-helper.c b/litex/soc/cores/cpu/gowin_emcu/boot-helper.c index 4dd8ae2d3..f16e05298 100644 --- a/litex/soc/cores/cpu/gowin_emcu/boot-helper.c +++ b/litex/soc/cores/cpu/gowin_emcu/boot-helper.c @@ -1,5 +1,5 @@ void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { - goto *addr; + goto *(void*)addr; } diff --git a/litex/soc/cores/cpu/zynq7000/boot-helper.c b/litex/soc/cores/cpu/zynq7000/boot-helper.c index 4dd8ae2d3..f16e05298 100644 --- a/litex/soc/cores/cpu/zynq7000/boot-helper.c +++ b/litex/soc/cores/cpu/zynq7000/boot-helper.c @@ -1,5 +1,5 @@ void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr); void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr) { - goto *addr; + goto *(void*)addr; } From d18c6316f4f7e71f7abae10957f9bdea0c412e6b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 10 Jul 2023 11:22:03 +0200 Subject: [PATCH 094/454] gen/fhdl/verilog: Improve signal sort by name instead of duid to improve reproducibility. --- litex/gen/fhdl/verilog.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index b4736aae3..244d72bd2 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -394,7 +394,7 @@ def _print_module(f, ios, name, ns, attr_translate): r = f"module {name} (\n" firstp = True - for sig in sorted(ios, key=lambda x: x.duid): + for sig in sorted(ios, key=lambda x: ns.get_name(x)): if not firstp: r += ",\n" firstp = False @@ -429,7 +429,7 @@ def _print_signals(f, ios, name, ns, attr_translate, regs_init): wires = _list_comb_wires(f) | special_outs r = "" - for sig in sorted(sigs - ios, key=lambda x: x.duid): + for sig in sorted(sigs - ios, key=lambda x: ns.get_name(x)): r += _print_attribute(sig.attr, attr_translate) if sig in wires: r += "wire " + _print_signal(ns, sig) + ";\n" @@ -480,7 +480,7 @@ def _print_combinatorial_logic_synth(f, ns): r += "assign " + _print_node(ns, _AT_BLOCKING, 0, g[1][0]) else: r += "always @(*) begin\n" - for t in g[0]: + for t in sorted(g[0], key=lambda x: ns.get_name(x)): r += _tab + ns.get_name(t) + " <= " + _print_expression(ns, t.reset)[0] + ";\n" r += _print_node(ns, _AT_NONBLOCKING, 1, g[1]) r += "end\n" From 26732f626fbd966d69e2e1ad21ce4f7409fac32f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 10 Jul 2023 11:23:10 +0200 Subject: [PATCH 095/454] CHANGES: Update. --- CHANGES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 015d59425..c12152194 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ - software/liblitespi : Fixed support with debug. - cpu/vexriscv_smp : Fixed compilation with Gowin toolchain (ex for Tang Nano 20K Linux). - liteiclink/serwb : Fixed 7-Series initialization corner cases. + - liteeth/core/icmp : Fixed length check on LiteEthICMPEcho before passing data to buffer. [> Added -------- @@ -38,10 +39,12 @@ - litesata/dma : Added multi-sector support. - liteeth/mac : Added TX Slots write-only mode for improved resource usage when software does not read buffer. - liteeth/core : Added DHCP support for CPU-less hardware stack. + - liteeth/core/icmp : Added fifo_depth parameter on LiteEthICMPEcho. + - gen/fhdl/verilog : Improved signal sort by name instead of duid to improve reproducibility. [> Changed ---------- - - + - litex/gen : Added local version of genlib.cdc/misc to better decouple with Migen and prepare Amaranth's compat use. [> 2023.04, released on May 8th 2023 ------------------------------------ From eb1afbad472d864106617750c551f9fbe7db064e Mon Sep 17 00:00:00 2001 From: riktw Date: Tue, 11 Jul 2023 16:16:51 +0200 Subject: [PATCH 096/454] Currently using a lite or minimal Vexriscv config with debug and breakpoints throws an error. Updated the GCC_FLAGS to include these two variants as well. --- litex/soc/cores/cpu/vexriscv/core.py | 50 +++++++++++++++------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index 711e7b29b..2fe72d921 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -50,30 +50,32 @@ # GCC Flags ---------------------------------------------------------------------------------------- GCC_FLAGS = { - # /---------- Base ISA - # | /----- Hardware Multiply + Divide - # | |/---- Atomics - # | ||/--- Compressed ISA - # | |||/-- Single-Precision Floating-Point - # | ||||/- Double-Precision Floating-Point - # i macfd - "minimal": "-march=rv32i2p0 -mabi=ilp32", - "minimal+debug": "-march=rv32i2p0 -mabi=ilp32", - "lite": "-march=rv32i2p0_m -mabi=ilp32", - "lite+debug": "-march=rv32i2p0_m -mabi=ilp32", - "standard": "-march=rv32i2p0_m -mabi=ilp32", - "standard+debug": "-march=rv32i2p0_m -mabi=ilp32", - "imac": "-march=rv32i2p0_mac -mabi=ilp32", - "imac+debug": "-march=rv32i2p0_mac -mabi=ilp32", - "full": "-march=rv32i2p0_m -mabi=ilp32", - "full+cfu": "-march=rv32i2p0_m -mabi=ilp32", - "full+debug": "-march=rv32i2p0_m -mabi=ilp32", - "full+cfu+debug": "-march=rv32i2p0_m -mabi=ilp32", - "linux": "-march=rv32i2p0_ma -mabi=ilp32", - "linux+debug": "-march=rv32i2p0_ma -mabi=ilp32", - "linux+no-dsp": "-march=rv32i2p0_ma -mabi=ilp32", - "secure": "-march=rv32i2p0_ma -mabi=ilp32", - "secure+debug": "-march=rv32i2p0_ma -mabi=ilp32", + # /---------- Base ISA + # | /----- Hardware Multiply + Divide + # | |/---- Atomics + # | ||/--- Compressed ISA + # | |||/-- Single-Precision Floating-Point + # | ||||/- Double-Precision Floating-Point + # i macfd + "minimal": "-march=rv32i2p0 -mabi=ilp32", + "minimal+debug": "-march=rv32i2p0 -mabi=ilp32", + "minimal+debug+hwbp": "-march=rv32i2p0 -mabi=ilp32", + "lite": "-march=rv32i2p0_m -mabi=ilp32", + "lite+debug": "-march=rv32i2p0_m -mabi=ilp32", + "lite+debug+hwbp": "-march=rv32i2p0_m -mabi=ilp32", + "standard": "-march=rv32i2p0_m -mabi=ilp32", + "standard+debug": "-march=rv32i2p0_m -mabi=ilp32", + "imac": "-march=rv32i2p0_mac -mabi=ilp32", + "imac+debug": "-march=rv32i2p0_mac -mabi=ilp32", + "full": "-march=rv32i2p0_m -mabi=ilp32", + "full+cfu": "-march=rv32i2p0_m -mabi=ilp32", + "full+debug": "-march=rv32i2p0_m -mabi=ilp32", + "full+cfu+debug": "-march=rv32i2p0_m -mabi=ilp32", + "linux": "-march=rv32i2p0_ma -mabi=ilp32", + "linux+debug": "-march=rv32i2p0_ma -mabi=ilp32", + "linux+no-dsp": "-march=rv32i2p0_ma -mabi=ilp32", + "secure": "-march=rv32i2p0_ma -mabi=ilp32", + "secure+debug": "-march=rv32i2p0_ma -mabi=ilp32", } # VexRiscv Timer ----------------------------------------------------------------------------------- From f9e32eb3eb94863d54bbe2d7294db784704b0675 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 11 Jul 2023 16:42:21 +0200 Subject: [PATCH 097/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index c12152194..a7d0d11eb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -41,6 +41,7 @@ - liteeth/core : Added DHCP support for CPU-less hardware stack. - liteeth/core/icmp : Added fifo_depth parameter on LiteEthICMPEcho. - gen/fhdl/verilog : Improved signal sort by name instead of duid to improve reproducibility. + - litedram/frontend/dma : Added last generation on end of DMA for LiteDRAMDMAReader. [> Changed ---------- From 3a2586c48b276b66b7d92037c12c0d9e2aff8836 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 12 Jul 2023 19:42:54 +0200 Subject: [PATCH 098/454] soc/add_pcie: Remove csr_ordering parameter (not useful and remove on litepcie). --- litex/soc/integration/soc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 54fbd792d..ed7cd4b5c 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -2012,7 +2012,7 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre if msi_type == "msi-multi-vector": msi = LitePCIeMSIMultiVector(width=msi_width) if msi_type == "msi-x": - msi = LitePCIeMSIX(endpoint=self.pcie_endpoint, width=msi_width, csr_ordering=self.csr.ordering) + msi = LitePCIeMSIX(endpoint=self.pcie_endpoint, width=msi_width) self.add_module(name=f"{name}_msi", module=msi) # FIXME: On Ultrascale/Ultrascale+ limit rate of IRQs to 1MHz (to prevent issue with # IRQs stalled). From 6e46710678a9f36ee4f63daaa0bb751b95a6d8f8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 14 Jul 2023 10:01:32 +0200 Subject: [PATCH 099/454] gen/fhdl/module: Fix CSR clock domain renaming to cores converted to LiteXModule, thanks @smunaut. --- CHANGES.md | 1 + litex/gen/fhdl/module.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a7d0d11eb..2953cf799 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ - cpu/vexriscv_smp : Fixed compilation with Gowin toolchain (ex for Tang Nano 20K Linux). - liteiclink/serwb : Fixed 7-Series initialization corner cases. - liteeth/core/icmp : Fixed length check on LiteEthICMPEcho before passing data to buffer. + - LiteXModule/CSR : Fixed CSR collection order causing CSR clock domain to be changed. [> Added -------- diff --git a/litex/gen/fhdl/module.py b/litex/gen/fhdl/module.py index a3fa016b1..fe756318e 100644 --- a/litex/gen/fhdl/module.py +++ b/litex/gen/fhdl/module.py @@ -8,7 +8,7 @@ from migen.fhdl.module import _ModuleProxy from migen.fhdl.specials import Special -from litex.soc.interconnect.csr import AutoCSR +from litex.soc.interconnect.csr import _CSRBase, AutoCSR from litex.soc.integration.doc import AutoDoc # LiteX Module ------------------------------------------------------------------------------------- @@ -21,7 +21,8 @@ def __setattr__(m, name, value): raise AttributeError("Attempted to assign special Module property - use += instead") # LiteX fix-up: Automatically collect specials/submodules/clock_domains: # - m.module_x = .. equivalent of Migen's m.submodules.module_x = .. - elif isinstance(value, Module) and ((name, value) not in m._submodules): + # Note: Do an exception for CSRs that have a specific collection mechanism. + elif (isinstance(value, Module) and ((name, value) not in m._submodules) and (not isinstance(value, _CSRBase))): setattr(m.submodules, name, value) # - m.special_x = .. equivalent of Migen's m.specials.special_x = .. elif isinstance(value, Special) and (value not in m._fragment.specials): From 8103cf78518161cd7b8a71f3c0905d1f9c2b83af Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 14 Jul 2023 22:17:45 +0200 Subject: [PATCH 100/454] soc/cores: Switch cores to LiteXModule (still need to do cpu, ram, clk, spi). --- litex/soc/cores/bitbang.py | 6 ++-- litex/soc/cores/code_8b10b.py | 6 ++-- litex/soc/cores/code_tmds.py | 2 +- litex/soc/cores/dma.py | 7 +++-- litex/soc/cores/dna.py | 4 +-- litex/soc/cores/ecc.py | 4 +-- litex/soc/cores/emif.py | 8 ++++-- litex/soc/cores/freqmeter.py | 8 ++++-- litex/soc/cores/gpio.py | 19 ++++++------ litex/soc/cores/hyperbus.py | 7 +++-- litex/soc/cores/i2s.py | 14 +++++---- litex/soc/cores/icap.py | 12 ++++---- litex/soc/cores/identifier.py | 4 ++- litex/soc/cores/jtag.py | 28 +++++++++--------- litex/soc/cores/led.py | 13 +++++---- litex/soc/cores/prbs.py | 8 +++--- litex/soc/cores/pwm.py | 6 ++-- litex/soc/cores/spi_flash.py | 4 +-- litex/soc/cores/spi_opi.py | 20 +++++++------ litex/soc/cores/timer.py | 8 ++++-- litex/soc/cores/uart.py | 51 +++++++++++++++++---------------- litex/soc/cores/usb_fifo.py | 22 +++++++------- litex/soc/cores/usb_ohci.py | 4 ++- litex/soc/cores/video.py | 54 +++++++++++++++++------------------ 24 files changed, 174 insertions(+), 145 deletions(-) diff --git a/litex/soc/cores/bitbang.py b/litex/soc/cores/bitbang.py index ddd92af94..a304d2cba 100644 --- a/litex/soc/cores/bitbang.py +++ b/litex/soc/cores/bitbang.py @@ -8,11 +8,13 @@ from migen import * from migen.fhdl.specials import Tristate +from litex.gen import * + from litex.soc.interconnect.csr import * # I2C Master Bit-Banging --------------------------------------------------------------------------- -class I2CMaster(Module, AutoCSR): +class I2CMaster(LiteXModule): """I2C bus master (bit-banged). This core provides minimal hardware for use as a software controlled bit-banged I2C bus master. @@ -145,7 +147,7 @@ def collect_i2c_info(soc): # SPI Master Bit-Banging --------------------------------------------------------------------------- -class SPIMaster(Module, AutoCSR): +class SPIMaster(LiteXModule): """3/4-wire SPI bus master (bit-banged). This core provides minimal hardware for use as a software controlled bit-banged SPI bus master. diff --git a/litex/soc/cores/code_8b10b.py b/litex/soc/cores/code_8b10b.py index 7e850d2f1..5f218e016 100644 --- a/litex/soc/cores/code_8b10b.py +++ b/litex/soc/cores/code_8b10b.py @@ -153,7 +153,7 @@ def reverse_table(inputs, nbits): # Single Encoder ----------------------------------------------------------------------------------- @CEInserter() -class SingleEncoder(Module): +class SingleEncoder(LiteXModule): def __init__(self, lsb_first=False): self.d = Signal(8) self.k = Signal() @@ -252,7 +252,7 @@ def __init__(self, lsb_first=False): # Encoder ------------------------------------------------------------------------------------------ -class Encoder(Module): +class Encoder(LiteXModule): def __init__(self, nwords=1, lsb_first=False): self.ce = Signal(reset=1) self.d = [Signal(8) for _ in range(nwords)] @@ -283,7 +283,7 @@ def __init__(self, nwords=1, lsb_first=False): # Decoder ------------------------------------------------------------------------------------------ -class Decoder(Module): +class Decoder(LiteXModule): def __init__(self, lsb_first=False): self.ce = Signal(reset=1) self.input = Signal(10) diff --git a/litex/soc/cores/code_tmds.py b/litex/soc/cores/code_tmds.py index 18749a4bb..eccadade4 100644 --- a/litex/soc/cores/code_tmds.py +++ b/litex/soc/cores/code_tmds.py @@ -15,7 +15,7 @@ # TMDS Encoder ------------------------------------------------------------------------------------- -class TMDSEncoder(Module): +class TMDSEncoder(LiteXModule): def __init__(self): self.d = Signal(8) self.c = Signal(2) diff --git a/litex/soc/cores/dma.py b/litex/soc/cores/dma.py index c8529d5c5..ec9b8d4de 100644 --- a/litex/soc/cores/dma.py +++ b/litex/soc/cores/dma.py @@ -8,6 +8,7 @@ from migen import * +from litex.gen import * from litex.gen.common import reverse_bytes from litex.soc.interconnect.csr import * @@ -21,7 +22,7 @@ def format_bytes(s, endianness): # WishboneDMAReader -------------------------------------------------------------------------------- -class WishboneDMAReader(Module, AutoCSR): +class WishboneDMAReader(LiteXModule): """Read data from Wishbone MMAP memory. For every address written to the sink, one word will be produced on the source. @@ -48,7 +49,7 @@ def __init__(self, bus, endianness="little", fifo_depth=16, with_csr=False): # # # # FIFO.. - self.submodules.fifo = fifo = stream.SyncFIFO([("data", bus.data_width)], depth=fifo_depth) + self.fifo = fifo = stream.SyncFIFO([("data", bus.data_width)], depth=fifo_depth) # Reads -> FIFO. self.comb += [ @@ -118,7 +119,7 @@ def add_csr(self, default_base=0, default_length=0, default_enable=0, default_lo # WishboneDMAWriter -------------------------------------------------------------------------------- -class WishboneDMAWriter(Module, AutoCSR): +class WishboneDMAWriter(LiteXModule): """Write data to Wishbone MMAP memory. Parameters diff --git a/litex/soc/cores/dna.py b/litex/soc/cores/dna.py index 757306aa3..dfac37c2c 100644 --- a/litex/soc/cores/dna.py +++ b/litex/soc/cores/dna.py @@ -15,7 +15,7 @@ # Xilinx DNA (Device Identifier) ------------------------------------------------------------------- -class XilinxDNA(Module, AutoCSR): +class XilinxDNA(LiteXModule): def __init__(self, nbits=57, primitive="DNA_PORT", clk_divider=2): self.nbits = nbits self.clk_divider = clk_divider @@ -29,7 +29,7 @@ def __init__(self, nbits=57, primitive="DNA_PORT", clk_divider=2): assert math.log2(clk_divider).is_integer() # Create slow DNA Clk. - self.clock_domains.cd_dna = ClockDomain() + self.cd_dna = ClockDomain() dna_clk_count = Signal(int(math.log2(clk_divider))) self.sync += dna_clk_count.eq(dna_clk_count + 1) self.sync += self.cd_dna.clk.eq(dna_clk_count[-1]) diff --git a/litex/soc/cores/ecc.py b/litex/soc/cores/ecc.py index 22fb35b62..e659097c4 100644 --- a/litex/soc/cores/ecc.py +++ b/litex/soc/cores/ecc.py @@ -193,7 +193,7 @@ def compute_parity(self, codeword, parity): # ECC Encoder -------------------------------------------------------------------------------------- -class ECCEncoder(SECDED, Module): +class ECCEncoder(SECDED, LiteXModule): """ ECCEncoder @@ -233,7 +233,7 @@ def __init__(self, k): # ECC Decoder -------------------------------------------------------------------------------------- -class ECCDecoder(SECDED, Module): +class ECCDecoder(SECDED, LiteXModule): """ ECCDecoder diff --git a/litex/soc/cores/emif.py b/litex/soc/cores/emif.py index 0be2367d7..0332dac52 100644 --- a/litex/soc/cores/emif.py +++ b/litex/soc/cores/emif.py @@ -7,10 +7,12 @@ from migen import * from migen.genlib.cdc import MultiReg +from litex.gen import * + from litex.soc.interconnect import wishbone -class EMIF(Module): +class EMIF(LiteXModule): """External Memory Interface core Provides a simple EMIF to Wishbone Master bridge. @@ -83,13 +85,13 @@ def add_tristate(self, pad): return t -class EMIF16To32Adapter(Module): +class EMIF16To32Adapter(LiteXModule): def __init__(self, emif): self.bus = bus = wishbone.Interface() # # # - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(emif.bus.stb & emif.bus.cyc, If(emif.bus.we, diff --git a/litex/soc/cores/freqmeter.py b/litex/soc/cores/freqmeter.py index e2c968a2a..598f97b21 100644 --- a/litex/soc/cores/freqmeter.py +++ b/litex/soc/cores/freqmeter.py @@ -8,11 +8,13 @@ from migen.genlib.cdc import MultiReg, GrayCounter from migen.genlib.cdc import GrayDecoder +from litex.gen import * + from litex.soc.interconnect.csr import * # Sampler ------------------------------------------------------------------------------------------ -class _Sampler(Module): +class _Sampler(LiteXModule): def __init__(self, width): self.latch = Signal() self.i = Signal(width) @@ -38,14 +40,14 @@ def __init__(self, width): # Freq Meter --------------------------------------------------------------------------------------- -class FreqMeter(Module, AutoCSR): +class FreqMeter(LiteXModule): def __init__(self, period, width=6, clk=None): self.clk = Signal() if clk is None else clk self.value = CSRStatus(32) # # # - self.clock_domains.cd_fmeter = ClockDomain(reset_less=True) + self.cd_fmeter = ClockDomain(reset_less=True) self.comb += self.cd_fmeter.clk.eq(self.clk) # Period generation diff --git a/litex/soc/cores/gpio.py b/litex/soc/cores/gpio.py index 12f4ccdae..2724c1905 100644 --- a/litex/soc/cores/gpio.py +++ b/litex/soc/cores/gpio.py @@ -8,8 +8,9 @@ from migen import * from migen.genlib.cdc import MultiReg -from litex.soc.interconnect.csr import * +from litex.gen import * +from litex.soc.interconnect.csr import * from litex.soc.interconnect.csr_eventmanager import * # Helpers ------------------------------------------------------------------------------------------ @@ -18,14 +19,14 @@ def _to_signal(obj): return obj.raw_bits() if isinstance(obj, Record) else obj -class _GPIOIRQ: +class _GPIOIRQ(LiteXModule): def add_irq(self, in_pads): self._mode = CSRStorage(len(in_pads), description="GPIO IRQ Mode: 0: Edge, 1: Change.") self._edge = CSRStorage(len(in_pads), description="GPIO IRQ Edge (when in Edge mode): 0: Rising Edge, 1: Falling Edge.") # # # - self.submodules.ev = EventManager() + self.ev = EventManager() for n in range(len(in_pads)): in_pads_n_d = Signal() self.sync += in_pads_n_d.eq(in_pads[n]) @@ -44,7 +45,7 @@ def add_irq(self, in_pads): # GPIO Input --------------------------------------------------------------------------------------- -class GPIOIn(_GPIOIRQ, Module, AutoCSR): +class GPIOIn(_GPIOIRQ): def __init__(self, pads, with_irq=False): pads = _to_signal(pads) self._in = CSRStatus(len(pads), description="GPIO Input(s) Status.") @@ -54,7 +55,7 @@ def __init__(self, pads, with_irq=False): # GPIO Output -------------------------------------------------------------------------------------- -class GPIOOut(Module, AutoCSR): +class GPIOOut(LiteXModule): def __init__(self, pads, reset=0): pads = _to_signal(pads) self.out = CSRStorage(len(pads), reset=reset, description="GPIO Output(s) Control.") @@ -62,17 +63,17 @@ def __init__(self, pads, reset=0): # GPIO Input/Output -------------------------------------------------------------------------------- -class GPIOInOut(Module): +class GPIOInOut(LiteXModule): def __init__(self, in_pads, out_pads): - self.submodules.gpio_in = GPIOIn(in_pads) - self.submodules.gpio_out = GPIOOut(out_pads) + self.gpio_in = GPIOIn(in_pads) + self.gpio_out = GPIOOut(out_pads) def get_csrs(self): return self.gpio_in.get_csrs() + self.gpio_out.get_csrs() # GPIO Tristate ------------------------------------------------------------------------------------ -class GPIOTristate(_GPIOIRQ, Module, AutoCSR): +class GPIOTristate(_GPIOIRQ): def __init__(self, pads, with_irq=False): internal = not (hasattr(pads, "o") and hasattr(pads, "oe") and hasattr(pads, "i")) nbits = len(pads) if internal else len(pads.o) diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index fbc3d8ddd..cb19385a5 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -8,6 +8,7 @@ from migen import * +from litex.gen import * from litex.gen.genlib.misc import WaitTimer from litex.build.io import DifferentialOutput @@ -16,7 +17,7 @@ # HyperRAM ----------------------------------------------------------------------------------------- -class HyperRAM(Module): +class HyperRAM(LiteXModule): tCSM = 4e-6 """HyperRAM @@ -66,7 +67,7 @@ def __init__(self, pads, latency=6, sys_clk_freq=None): # Burst Timer ------------------------------------------------------------------------------ sys_clk_freq = 10e6 if sys_clk_freq is None else sys_clk_freq burst_timer = WaitTimer(int(sys_clk_freq*self.tCSM)) - self.submodules.burst_timer = burst_timer + self.burst_timer = burst_timer # Clock Generation (sys_clk/4) ------------------------------------------------------------- self.sync += clk_phase.eq(clk_phase + 1) @@ -127,7 +128,7 @@ def __init__(self, pads, latency=6, sys_clk_freq=None): # FSM (Sequencer) -------------------------------------------------------------------------- cycles = Signal(8) first = Signal() - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(first, 1), If(bus.cyc & bus.stb, diff --git a/litex/soc/cores/i2s.py b/litex/soc/cores/i2s.py index 74e95abe2..1113dcc87 100644 --- a/litex/soc/cores/i2s.py +++ b/litex/soc/cores/i2s.py @@ -7,6 +7,8 @@ from migen.genlib.cdc import MultiReg +from litex.gen import * + from litex.soc.cores.clock import * from litex.soc.interconnect import wishbone from litex.soc.interconnect.csr_eventmanager import * @@ -21,7 +23,7 @@ class I2S_FORMAT(Enum): I2S_STANDARD = 1 I2S_LEFT_JUSTIFIED = 2 -class S7I2S(Module, AutoCSR, AutoDoc): +class S7I2S(LiteXModule): def __init__(self, pads, fifo_depth=256, controller=False, master=False, concatenate_channels=True, sample_width=16, frame_format=I2S_FORMAT.I2S_LEFT_JUSTIFIED, lrck_ref_freq=100e6, lrck_freq=44100, bits_per_channel=28, document_interrupts=False, toolchain="vivado"): if master == True: print("Master/slave terminology deprecated, please use controller/peripheral. Please see http://oshwa.org/a-resolution-to-redefine-spi-signal-names.") @@ -200,7 +202,7 @@ def __init__(self, pads, fifo_depth=256, controller=False, master=False, concate ] # Interrupts - self.submodules.ev = EventManager() + self.ev = EventManager() if hasattr(pads, 'rx'): self.ev.rx_ready = EventSourcePulse(description="Indicates FIFO is ready to read") # Rising edge triggered self.ev.rx_error = EventSourcePulse(description="Indicates an Rx error has happened (over/underflow)") @@ -251,7 +253,7 @@ def __init__(self, pads, fifo_depth=256, controller=False, master=False, concate ) ] - self.submodules.rx_fifo = fifo = FIFOSyncMacro("18Kb", data_width=fifo_data_width, + self.rx_fifo = fifo = FIFOSyncMacro("18Kb", data_width=fifo_data_width, almost_empty_offset=8, almost_full_offset=(512 - fifo_depth), toolchain=toolchain) self.comb += fifo.reset.eq(rx_reset) @@ -293,7 +295,7 @@ def __init__(self, pads, fifo_depth=256, controller=False, master=False, concate rx_delay_cnt = Signal() rx_delay_val = 1 if frame_format == I2S_FORMAT.I2S_STANDARD else 0 - self.submodules.rxi2s = rxi2s = FSM(reset_state="IDLE") + self.rxi2s = rxi2s = FSM(reset_state="IDLE") rxi2s.act("IDLE", NextValue(fifo.wr_d, 0), If(self.rx_ctl.fields.enable, @@ -454,7 +456,7 @@ def __init__(self, pads, fifo_depth=256, controller=False, master=False, concate ) ] - self.submodules.tx_fifo = fifo = FIFOSyncMacro("18Kb", data_width=fifo_data_width, + self.tx_fifo = fifo = FIFOSyncMacro("18Kb", data_width=fifo_data_width, almost_empty_offset=(512 - fifo_depth), almost_full_offset=8, toolchain=toolchain) self.comb += fifo.reset.eq(tx_reset) @@ -495,7 +497,7 @@ def __init__(self, pads, fifo_depth=256, controller=False, master=False, concate tx_cnt = Signal(tx_cnt_width) tx_buf = Signal(tx_buf_width) sample_msb = fifo_data_width - 1 - self.submodules.txi2s = txi2s = FSM(reset_state="IDLE") + self.txi2s = txi2s = FSM(reset_state="IDLE") txi2s.act("IDLE", If(self.tx_ctl.fields.enable, If(rising_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin), diff --git a/litex/soc/cores/icap.py b/litex/soc/cores/icap.py index a6ae3edbf..9f0ff620e 100644 --- a/litex/soc/cores/icap.py +++ b/litex/soc/cores/icap.py @@ -11,6 +11,8 @@ from migen.genlib.cdc import PulseSynchronizer +from litex.gen import * + from litex.soc.interconnect.csr import * from litex.soc.interconnect import stream @@ -71,7 +73,7 @@ class ICAPCMDs(IntEnum): # Xilinx 7-series / Ultrascale (Plus) ICAP --------------------------------------------------------- -class ICAP(Module, AutoCSR): +class ICAP(LiteXModule): """ICAP Allow writing/reading ICAPE2's registers of Xilinx 7-Series FPGAs. @@ -94,7 +96,7 @@ def __init__(self, with_csr=True, clk_divider=16, primitive="ICAPE2", simulation assert math.log2(clk_divider).is_integer() # Create slow ICAP Clk. - self.clock_domains.cd_icap = ClockDomain() + self.cd_icap = ClockDomain() icap_clk_counter = Signal(int(math.log2(clk_divider))) self.sync += icap_clk_counter.eq(icap_clk_counter + 1) self.sync += self.cd_icap.clk.eq(icap_clk_counter[-1]) @@ -257,7 +259,7 @@ def add_csr(self): def add_reload(self): self.reload = Signal() # Set to 1 to reload FPGA from logic. - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(self.reload, NextState("RELOAD") @@ -274,7 +276,7 @@ def add_timing_constraints(self, platform, sys_clk_freq, sys_clk): platform.add_false_path_constraints(self.cd_icap.clk, sys_clk) -class ICAPBitstream(Module, AutoCSR): +class ICAPBitstream(LiteXModule): """ICAP Bitstream Allow sending bitstreams to ICAPE2 of Xilinx 7-Series FPGAs. @@ -294,7 +296,7 @@ def __init__(self, fifo_depth=8, icap_clk_div=4, simulation=False): # Create slow icap_clk (sys_clk/4) --------------------------------------------------------- icap_clk_counter = Signal(log2_int(icap_clk_div)) - self.clock_domains.cd_icap = ClockDomain() + self.cd_icap = ClockDomain() self.sync += icap_clk_counter.eq(icap_clk_counter + 1) self.sync += self.cd_icap.clk.eq(icap_clk_counter[-1]) diff --git a/litex/soc/cores/identifier.py b/litex/soc/cores/identifier.py index 05aeb6028..edbfebe40 100644 --- a/litex/soc/cores/identifier.py +++ b/litex/soc/cores/identifier.py @@ -6,9 +6,11 @@ from migen import * +from litex.gen import * + # Identifier --------------------------------------------------------------------------------------- -class Identifier(Module): +class Identifier(LiteXModule): def __init__(self, ident): contents = list(ident.encode()) l = len(contents) diff --git a/litex/soc/cores/jtag.py b/litex/soc/cores/jtag.py index 65644525d..e1305d3c2 100644 --- a/litex/soc/cores/jtag.py +++ b/litex/soc/cores/jtag.py @@ -12,14 +12,16 @@ from migen import * from migen.genlib.cdc import AsyncResetSynchronizer, MultiReg +from litex.gen import * + from litex.build.generic_platform import * from litex.soc.interconnect import stream # JTAG TAP FSM ------------------------------------------------------------------------------------- -class JTAGTAPFSM(Module): +class JTAGTAPFSM(LiteXModule): def __init__(self, tms): - self.submodules.fsm = fsm = FSM(reset_state="TEST_LOGIC_RESET") + self.fsm = fsm = FSM(reset_state="TEST_LOGIC_RESET") def JTAGTAPFSMState(name, transitions={}): logic = [] @@ -158,7 +160,7 @@ def JTAGTAPFSMState(name, transitions={}): # Altera JTAG -------------------------------------------------------------------------------------- -class AlteraJTAG(Module): +class AlteraJTAG(LiteXModule): def __init__(self, primitive, pads): # Common with Xilinx. self.reset = reset = Signal() # Provided by our own TAP FSM. @@ -192,12 +194,12 @@ def __init__(self, primitive, pads): # # # # Create falling-edge JTAG clock domain for TAP FSM. - self.clock_domains.cd_jtag_inv = cd_jtag_inv = ClockDomain("jtag_inv") + self.cd_jtag_inv = cd_jtag_inv = ClockDomain("jtag_inv") self.comb += ClockSignal("jtag_inv").eq(~ClockSignal("jtag")) self.comb += ResetSignal("jtag_inv").eq(ResetSignal("jtag")) # Connect the TAP state signals that LiteX expects but the HW IP doesn't provide. - self.submodules.tap_fsm = ClockDomainsRenamer("jtag")(JTAGTAPFSM(tms)) + self.tap_fsm = ClockDomainsRenamer("jtag")(JTAGTAPFSM(tms)) self.sync.jtag_inv += reset.eq(self.tap_fsm.TEST_LOGIC_RESET) self.sync.jtag_inv += capture.eq(self.tap_fsm.CAPTURE_DR) @@ -286,7 +288,7 @@ def get_primitive(device): # Xilinx JTAG -------------------------------------------------------------------------------------- -class XilinxJTAG(Module): +class XilinxJTAG(LiteXModule): def __init__(self, primitive, chain=1): self.reset = Signal() self.capture = Signal() @@ -338,7 +340,7 @@ def get_tdi_delay(device): # ECP5 JTAG ---------------------------------------------------------------------------------------- -class ECP5JTAG(Module): +class ECP5JTAG(LiteXModule): def __init__(self, tck_delay_luts=8): self.reset = Signal() self.capture = Signal() @@ -389,7 +391,7 @@ def __init__(self, tck_delay_luts=8): # JTAG PHY ----------------------------------------------------------------------------------------- -class JTAGPHY(Module): +class JTAGPHY(LiteXModule): def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys", chain=1, platform=None): """JTAG PHY @@ -434,10 +436,10 @@ def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys", cha else: print(device) raise NotImplementedError - self.submodules.jtag = jtag + self.jtag = jtag # JTAG clock domain ------------------------------------------------------------------------ - self.clock_domains.cd_jtag = ClockDomain() + self.cd_jtag = ClockDomain() self.comb += ClockSignal("jtag").eq(jtag.tck) self.specials += AsyncResetSynchronizer(self.cd_jtag, ResetSignal(clock_domain)) @@ -447,8 +449,8 @@ def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys", cha tx_cdc = ClockDomainsRenamer({"write": clock_domain, "read": "jtag"})(tx_cdc) rx_cdc = stream.AsyncFIFO([("data", data_width)], 4) rx_cdc = ClockDomainsRenamer({"write": "jtag", "read": clock_domain})(rx_cdc) - self.submodules.tx_cdc = tx_cdc - self.submodules.rx_cdc = rx_cdc + self.tx_cdc = tx_cdc + self.rx_cdc = rx_cdc self.comb += [ sink.connect(tx_cdc.sink), rx_cdc.source.connect(source) @@ -506,7 +508,7 @@ def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys", cha # Efinix / TRION ----------------------------------------------------------------------------------- -class EfinixJTAG(Module): +class EfinixJTAG(LiteXModule): # id refer to the JTAG_USER{id} def __init__(self, platform, id=1): self.name = f"jtag_{id}" diff --git a/litex/soc/cores/led.py b/litex/soc/cores/led.py index 99f8f8168..94f45385e 100644 --- a/litex/soc/cores/led.py +++ b/litex/soc/cores/led.py @@ -9,6 +9,7 @@ from migen import * +from litex.gen import * from litex.gen.genlib.misc import WaitTimer from litex.soc.interconnect.csr import * @@ -19,7 +20,7 @@ _CHASER_MODE = 0 _CONTROL_MODE = 1 -class LedChaser(Module, AutoCSR): +class LedChaser(LiteXModule): def __init__(self, pads, sys_clk_freq, period=1e0, polarity=0): self.pads = pads self.polarity = polarity @@ -48,7 +49,7 @@ def __init__(self, pads, sys_clk_freq, period=1e0, polarity=0): def add_pwm(self, default_width=512, default_period=1024, with_csr=True): from litex.soc.cores.pwm import PWM - self.submodules.pwm = PWM( + self.pwm = PWM( with_csr = with_csr, default_enable = 1, default_width = default_width, @@ -60,7 +61,7 @@ def add_pwm(self, default_width=512, default_period=1024, with_csr=True): # WS2812/NeoPixel ---------------------------------------------------------------------------------- -class WS2812(Module): +class WS2812(LiteXModule): """WS2812/NeoPixel Led Driver. Description @@ -114,7 +115,7 @@ class WS2812(Module): ... ... It can be simply integrated in a LiteX SoC with: - self.submodules.ws2812 = WS2812(platform.request("x"), nleds=32, sys_clk_freq=sys_clk_freq) + self.ws2812 = WS2812(platform.request("x"), nleds=32, sys_clk_freq=sys_clk_freq) self.bus.add_slave(name="ws2812", slave=self.ws2812.bus, region=SoCRegion( origin = 0x2000_0000, size = 32*4, @@ -141,7 +142,7 @@ def __init__(self, pad, nleds, sys_clk_freq, bus_mastering=False, bus_base=None, self.specials += mem, port # Wishone Memory. - self.submodules.wb_mem = wishbone.SRAM( + self.wb_mem = wishbone.SRAM( mem_or_size = mem, read_only = False, bus = wishbone.Interface(data_width=32) @@ -176,7 +177,7 @@ def __init__(self, pad, nleds, sys_clk_freq, bus_mastering=False, bus_base=None, self.submodules += t1h_timer, t1l_timer # Main FSM. - self.submodules.fsm = fsm = FSM(reset_state="RST") + self.fsm = fsm = FSM(reset_state="RST") fsm.act("RST", NextValue(led_count, 0), trst_timer.wait.eq(xfer_done), diff --git a/litex/soc/cores/prbs.py b/litex/soc/cores/prbs.py index 0eb8be971..6870a5446 100644 --- a/litex/soc/cores/prbs.py +++ b/litex/soc/cores/prbs.py @@ -20,7 +20,7 @@ # PRBS Generators ---------------------------------------------------------------------------------- -class PRBSGenerator(Module): +class PRBSGenerator(LiteXModule): def __init__(self, n_out, n_state=23, taps=[17, 22]): self.o = Signal(n_out) @@ -56,7 +56,7 @@ def __init__(self, n_out): # PRBS TX ------------------------------------------------------------------------------------------ -class PRBSTX(Module): +class PRBSTX(LiteXModule): def __init__(self, width, reverse=False): self.config = Signal(2) self.i = Signal(width) @@ -98,7 +98,7 @@ def __init__(self, width, reverse=False): # PRBS Checkers ------------------------------------------------------------------------------------ -class PRBSChecker(Module): +class PRBSChecker(LiteXModule): def __init__(self, n_in, n_state=23, taps=[17, 22]): self.i = Signal(n_in) self.errors = Signal(n_in) @@ -139,7 +139,7 @@ def __init__(self, n_out): # PRBS RX ------------------------------------------------------------------------------------------ -class PRBSRX(Module): +class PRBSRX(LiteXModule): def __init__(self, width, reverse=False, with_errors_saturation=False): self.config = Signal(2) self.pause = Signal() diff --git a/litex/soc/cores/pwm.py b/litex/soc/cores/pwm.py index bdc762981..5bc650c9d 100644 --- a/litex/soc/cores/pwm.py +++ b/litex/soc/cores/pwm.py @@ -7,11 +7,13 @@ from migen import * from migen.genlib.cdc import MultiReg +from litex.gen import * + from litex.soc.interconnect.csr import * # Pulse Width Modulation --------------------------------------------------------------------------- -class PWM(Module, AutoCSR): +class PWM(LiteXModule): """Pulse Width Modulation Provides the minimal hardware to do Pulse Width Modulation. @@ -81,7 +83,7 @@ def add_csr(self, clock_domain): # Multi Channel Pulse Width Modulation ------------------------------------------------------------- -class MultiChannelPWM(Module, AutoCSR): +class MultiChannelPWM(LiteXModule): """Multi-Channel Pulse Width Modulation PWM module with Multi-Channel support. diff --git a/litex/soc/cores/spi_flash.py b/litex/soc/cores/spi_flash.py index 922cf90dc..97f407b25 100644 --- a/litex/soc/cores/spi_flash.py +++ b/litex/soc/cores/spi_flash.py @@ -78,9 +78,9 @@ def __init__(self, sys_clk_freq, spi_clk_freq=25e6): # Lattice ECP5 FPGAs SPI Flash (non-memory-mapped) ------------------------------------------------- -class ECP5SPIFlash(Module, AutoCSR): +class ECP5SPIFlash(LiteXModule): def __init__(self, pads, sys_clk_freq, spi_clk_freq=25e6): - self.submodules.spi = spi = SPIMaster(None, 40, sys_clk_freq, spi_clk_freq) + self.spi = spi = SPIMaster(None, 40, sys_clk_freq, spi_clk_freq) self.specials += Instance("USRMCLK", i_USRMCLKI = spi.pads.clk, i_USRMCLKTS = 0 diff --git a/litex/soc/cores/spi_opi.py b/litex/soc/cores/spi_opi.py index 4d5e7edf8..851a99fac 100644 --- a/litex/soc/cores/spi_opi.py +++ b/litex/soc/cores/spi_opi.py @@ -7,13 +7,15 @@ from migen.genlib.cdc import MultiReg from migen.genlib.fifo import SyncFIFOBuffered +from litex.gen import * + from litex.soc.interconnect import wishbone from litex.soc.interconnect.csr_eventmanager import * from litex.soc.integration.doc import AutoDoc, ModuleDoc -class S7SPIOPI(Module, AutoCSR, AutoDoc): +class S7SPIOPI(LiteXModule): def __init__(self, pads, dq_delay_taps = 0, sclk_name = "SCLK_ODDR", @@ -571,8 +573,8 @@ def __init__(self, pads, bus_ack_w = Signal() #--------- Page write data responder ----------------------- - self.submodules.txwr_fifo = SyncFIFOBuffered(width=16, depth=128) - self.submodules.pgwr = pgwr = FSM(reset_state="IDLE") + self.txwr_fifo = SyncFIFOBuffered(width=16, depth=128) + self.pgwr = pgwr = FSM(reset_state="IDLE") pgwr.act("IDLE", If(self.wdata.re, self.txwr_fifo.we.eq(1), @@ -605,7 +607,7 @@ def __init__(self, pads, ] #--------- OPI Rx Phy machine ------------------------------ - self.submodules.rxphy = rxphy = FSM(reset_state="IDLE") + self.rxphy = rxphy = FSM(reset_state="IDLE") rxphy_cnt = Signal(3) rxphy.act("IDLE", If(spi_mode, @@ -689,7 +691,7 @@ def __init__(self, pads, self.sync += txphy_bus.eq(bus.cyc & bus.stb & ~bus.we & ((bus.cti == 2) | (bus.cti == 0))) tx_resetcycle = Signal() - self.submodules.txphy = txphy = FSM(reset_state="RESET") + self.txphy = txphy = FSM(reset_state="RESET") txphy.act("RESET", NextValue(opi_rx_run, 0), NextValue(txphy_oe, 0), @@ -902,7 +904,7 @@ def __init__(self, pads, #--------- OPI CMD machine ------------------------------ - self.submodules.opicmd = opicmd = FSM(reset_state="RESET") + self.opicmd = opicmd = FSM(reset_state="RESET") opicmd.act("RESET", NextValue(txcmd_do, 0), NextValue(txcmd_oe, 0), @@ -1012,7 +1014,7 @@ def __init__(self, pads, ] self.comb += self.copi.eq(spi_so[7]) self.sync += spi_si.eq(Cat(self.cipo, spi_si[:-1])) - self.submodules.spiphy = spiphy = FSM(reset_state="RESET") + self.spiphy = spiphy = FSM(reset_state="RESET") spiphy.act("RESET", If(spi_req, NextState("REQ"), @@ -1078,7 +1080,7 @@ def __init__(self, pads, d_to_wb = Signal(32) # data going back to wishbone mac_count = Signal(5) new_cycle = Signal(1) - self.submodules.mac = mac = FSM(reset_state="RESET") + self.mac = mac = FSM(reset_state="RESET") mac.act("RESET", NextValue(spi_mode, 1), NextValue(addr_updated, 0), @@ -1379,7 +1381,7 @@ def __init__(self, pads, ecs_n = Signal() self.specials += MultiReg(pads.ecs_n, ecs_n) - self.submodules.ev = EventManager() + self.ev = EventManager() self.ev.ecc_error = EventSourceProcess(description="An ECC event has happened on the current block; triggered by falling edge of ECC_N") self.ev.finalize() self.comb += self.ev.ecc_error.trigger.eq(ecs_n) diff --git a/litex/soc/cores/timer.py b/litex/soc/cores/timer.py index da9dcea26..45a7d2472 100644 --- a/litex/soc/cores/timer.py +++ b/litex/soc/cores/timer.py @@ -9,13 +9,15 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect.csr import * from litex.soc.interconnect.csr_eventmanager import * from litex.soc.integration.doc import AutoDoc, ModuleDoc # Timer -------------------------------------------------------------------------------------------- -class Timer(Module, AutoCSR, AutoDoc): +class Timer(LiteXModule): with_uptime = False def __init__(self, width=32): self.intro = ModuleDoc("""Timer @@ -65,8 +67,8 @@ def __init__(self, width=32): self._value = CSRStatus(width, description="""Latched countdown value. This value is updated by writing to ``update_value``.""") - self.submodules.ev = EventManager() - self.ev.zero = EventSourceProcess(edge="rising") + self.ev = EventManager() + self.ev.zero = EventSourceProcess(edge="rising") self.ev.finalize() # # # diff --git a/litex/soc/cores/uart.py b/litex/soc/cores/uart.py index eec88784b..6ca6d4196 100644 --- a/litex/soc/cores/uart.py +++ b/litex/soc/cores/uart.py @@ -13,6 +13,7 @@ from migen.genlib.record import Record from migen.genlib.cdc import MultiReg +from litex.gen import * from litex.gen.genlib.misc import WaitTimer from litex.soc.interconnect.csr import * @@ -39,7 +40,7 @@ def __init__(self): class RS232PHYInterface(UARTInterface): pass -class RS232ClkPhaseAccum(Module): +class RS232ClkPhaseAccum(LiteXModule): def __init__(self, tuning_word, mode="tx"): assert mode in ["tx", "rx"] self.enable = Signal() @@ -52,7 +53,7 @@ def __init__(self, tuning_word, mode="tx"): self.sync += If(self.enable, Cat(phase, self.tick).eq(phase + tuning_word)) -class RS232PHYTX(Module): +class RS232PHYTX(LiteXModule): def __init__(self, pads, tuning_word): self.sink = sink = stream.Endpoint([("data", 8)]) @@ -69,7 +70,7 @@ def __init__(self, pads, tuning_word): # FSM - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", # Reset Count and set TX to Idle. NextValue(count, 0), @@ -102,7 +103,7 @@ def __init__(self, pads, tuning_word): ) -class RS232PHYRX(Module): +class RS232PHYRX(LiteXModule): def __init__(self, pads, tuning_word): self.source = source = stream.Endpoint([("data", 8)]) @@ -122,7 +123,7 @@ def __init__(self, pads, tuning_word): self.sync += rx_d.eq(rx) # FSM - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", # Reset Count. NextValue(count, 0), @@ -151,18 +152,18 @@ def __init__(self, pads, tuning_word): ) -class RS232PHY(Module, AutoCSR): +class RS232PHY(LiteXModule): def __init__(self, pads, clk_freq, baudrate=115200, with_dynamic_baudrate=False): tuning_word = int((baudrate/clk_freq)*2**32) if with_dynamic_baudrate: self._tuning_word = CSRStorage(32, reset=tuning_word) tuning_word = self._tuning_word.storage - self.submodules.tx = RS232PHYTX(pads, tuning_word) - self.submodules.rx = RS232PHYRX(pads, tuning_word) + self.tx = RS232PHYTX(pads, tuning_word) + self.rx = RS232PHYRX(pads, tuning_word) self.sink, self.source = self.tx.sink, self.rx.source -class RS232PHYMultiplexer(Module): +class RS232PHYMultiplexer(LiteXModule): def __init__(self, phys, phy): self.sel = Signal(max=len(phys)) @@ -180,7 +181,7 @@ def __init__(self, phys, phy): self.comb += Case(self.sel, cases) -class RS232PHYModel(Module): +class RS232PHYModel(LiteXModule): def __init__(self, pads): self.sink = stream.Endpoint([("data", 8)]) self.source = stream.Endpoint([("data", 8)]) @@ -213,7 +214,7 @@ def UARTPHY(pads, clk_freq, baudrate): else: return RS232PHY(pads, clk_freq, baudrate) -class UART(Module, AutoCSR, UARTInterface): +class UART(LiteXModule, UARTInterface): def __init__(self, phy=None, tx_fifo_depth = 16, rx_fifo_depth = 16, @@ -223,7 +224,7 @@ def __init__(self, phy=None, self._txfull = CSRStatus(description="TX FIFO Full.") self._rxempty = CSRStatus(description="RX FIFO Empty.") - self.submodules.ev = EventManager() + self.ev = EventManager() self.ev.tx = EventSourceProcess(edge="rising") self.ev.rx = EventSourceProcess(edge="rising") self.ev.finalize() @@ -243,7 +244,7 @@ def __init__(self, phy=None, # TX # -- - self.submodules.tx_fifo = tx_fifo = _get_uart_fifo(tx_fifo_depth, source_cd=phy_cd) + self.tx_fifo = tx_fifo = _get_uart_fifo(tx_fifo_depth, source_cd=phy_cd) self.comb += [ # CSR --> FIFO. tx_fifo.sink.valid.eq(self._rxtx.re), @@ -262,7 +263,7 @@ def __init__(self, phy=None, # RX # -- - self.submodules.rx_fifo = rx_fifo = _get_uart_fifo(rx_fifo_depth, sink_cd=phy_cd) + self.rx_fifo = rx_fifo = _get_uart_fifo(rx_fifo_depth, sink_cd=phy_cd) self.comb += [ # Sink --> FIFO. self.sink.connect(rx_fifo.sink), @@ -292,7 +293,7 @@ def add_auto_tx_flush(self, sys_clk_freq, timeout=1e-2, interval=2): # Flush TX FIFO when Source.ready is inactive for timeout (with interval cycles between # each ready). - self.submodules.timer = timer = WaitTimer(int(timeout*sys_clk_freq)) + self.timer = timer = WaitTimer(int(timeout*sys_clk_freq)) self.comb += timer.wait.eq(~self.source.ready) self.sync += flush_count.eq(flush_count + 1) self.comb += If(timer.done, flush_ep.ready.eq(flush_count == 0)) @@ -305,7 +306,7 @@ def add_auto_tx_flush(self, sys_clk_freq, timeout=1e-2, interval=2): CMD_WRITE_BURST_FIXED = 0x03 CMD_READ_BURST_FIXED = 0x04 -class Stream2Wishbone(Module): +class Stream2Wishbone(LiteXModule): def __init__(self, phy=None, clk_freq=None, data_width=32, address_width=32): self.sink = sink = stream.Endpoint([("data", 8)]) if phy is None else phy.source self.source = source = stream.Endpoint([("data", 8)]) if phy is None else phy.sink @@ -328,8 +329,8 @@ def __init__(self, phy=None, clk_freq=None, data_width=32, address_width=32): addr_bytes_count_done = (addr_bytes_count == (address_width//8 - 1)) words_count_done = (words_count == (length - 1)) - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="RECEIVE-CMD")) - self.submodules.timer = timer = WaitTimer(int(100e-3*clk_freq)) + self.fsm = fsm = ResetInserter()(FSM(reset_state="RECEIVE-CMD")) + self.timer = timer = WaitTimer(int(100e-3*clk_freq)) self.comb += timer.wait.eq(~fsm.ongoing("RECEIVE-CMD")) self.comb += fsm.reset.eq(timer.done) fsm.act("RECEIVE-CMD", @@ -435,12 +436,12 @@ def __init__(self, phy=None, clk_freq=None, data_width=32, address_width=32): class UARTBone(Stream2Wishbone): def __init__(self, phy, clk_freq, cd="sys"): if cd == "sys": - self.submodules.phy = phy + self.phy = phy Stream2Wishbone.__init__(self, self.phy, clk_freq=clk_freq) else: - self.submodules.phy = ClockDomainsRenamer(cd)(phy) - self.submodules.tx_cdc = stream.ClockDomainCrossing([("data", 8)], cd_from="sys", cd_to=cd) - self.submodules.rx_cdc = stream.ClockDomainCrossing([("data", 8)], cd_from=cd, cd_to="sys") + self.phy = ClockDomainsRenamer(cd)(phy) + self.tx_cdc = stream.ClockDomainCrossing([("data", 8)], cd_from="sys", cd_to=cd) + self.rx_cdc = stream.ClockDomainCrossing([("data", 8)], cd_from=cd, cd_to="sys") self.comb += self.phy.source.connect(self.rx_cdc.sink) self.comb += self.tx_cdc.source.connect(self.phy.sink) Stream2Wishbone.__init__(self, clk_freq=clk_freq) @@ -449,12 +450,12 @@ def __init__(self, phy, clk_freq, cd="sys"): class UARTWishboneBridge(UARTBone): def __init__(self, pads, clk_freq, baudrate=115200, cd="sys"): - self.submodules.phy = RS232PHY(pads, clk_freq, baudrate) + self.phy = RS232PHY(pads, clk_freq, baudrate) UARTBone.__init__(self, self.phy, clk_freq, cd) # UART Multiplexer --------------------------------------------------------------------------------- -class UARTMultiplexer(Module): +class UARTMultiplexer(LiteXModule): def __init__(self, uarts, uart): self.sel = Signal(max=len(uarts)) @@ -480,7 +481,7 @@ class UARTCrossover(UART): def __init__(self, **kwargs): assert kwargs.get("phy", None) == None UART.__init__(self, **kwargs) - self.submodules.xover = UART(tx_fifo_depth=1, rx_fifo_depth=16, rx_fifo_rx_we=True) + self.xover = UART(tx_fifo_depth=1, rx_fifo_depth=16, rx_fifo_rx_we=True) self.comb += [ self.source.connect(self.xover.sink), self.xover.source.connect(self.sink) diff --git a/litex/soc/cores/usb_fifo.py b/litex/soc/cores/usb_fifo.py index 7a6b37f65..2ee0de2c9 100644 --- a/litex/soc/cores/usb_fifo.py +++ b/litex/soc/cores/usb_fifo.py @@ -10,6 +10,8 @@ from migen.fhdl.specials import Tristate from migen.genlib.cdc import MultiReg +from litex.gen import * + from litex.soc.interconnect import stream from litex.build.io import SDRTristate @@ -39,7 +41,7 @@ def anti_starvation(module, timeout): # FT245 Synchronous FIFO Mode ---------------------------------------------------------------------- -class FT245PHYSynchronous(Module): +class FT245PHYSynchronous(LiteXModule): # FIXME: Check/Improve sampling timings. def __init__(self, pads, clk_freq, fifo_depth = 64, @@ -60,12 +62,12 @@ def __init__(self, pads, clk_freq, # Read CDC/FIFO (FTDI --> SoC). # ----------------------------- - self.submodules.read_cdc = stream.ClockDomainCrossing(phy_description(dw), + self.read_cdc = stream.ClockDomainCrossing(phy_description(dw), cd_from = "usb", cd_to = "sys", with_common_rst = True ) - self.submodules.read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) + self.read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) self.comb += self.read_cdc.source.connect(self.read_fifo.sink) self.comb += self.read_fifo.source.connect(self.source) read_fifo_almost_full = (self.read_fifo.level > (fifo_depth - 4)) @@ -74,8 +76,8 @@ def __init__(self, pads, clk_freq, # Write FIFO/CDC (SoC --> FTDI). # ------------------------------ - self.submodules.write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) - self.submodules.write_cdc = stream.ClockDomainCrossing(phy_description(dw), + self.write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) + self.write_cdc = stream.ClockDomainCrossing(phy_description(dw), cd_from = "sys", cd_to = "usb", with_common_rst = True @@ -124,7 +126,7 @@ def __init__(self, pads, clk_freq, # ----------------- fsm = FSM(reset_state="READ") fsm = ClockDomainsRenamer("usb")(fsm) - self.submodules.fsm = fsm + self.fsm = fsm fsm.act("READ", # Arbitration. read_time_en.eq(1), @@ -190,11 +192,11 @@ def get_litescope_probes(self): # FT245 Asynchronous FIFO Mode --------------------------------------------------------------------- -class FT245PHYAsynchronous(Module): +class FT245PHYAsynchronous(LiteXModule): def __init__(self, pads, clk_freq, - fifo_depth = 8, - read_time = 128, - write_time = 128): + fifo_depth = 8, + read_time = 128, + write_time = 128): dw = len(pads.data) self.clk_freq = clk_freq diff --git a/litex/soc/cores/usb_ohci.py b/litex/soc/cores/usb_ohci.py index 5948779ec..894217323 100644 --- a/litex/soc/cores/usb_ohci.py +++ b/litex/soc/cores/usb_ohci.py @@ -12,13 +12,15 @@ from litex import get_data_mod +from litex.gen import * + from litex.soc.interconnect import wishbone from litex.build.io import SDRTristate # USB OHCI ----------------------------------------------------------------------------------------- -class USBOHCI(Module): +class USBOHCI(LiteXModule): def __init__(self, platform, pads, usb_clk_freq=48e6, dma_data_width=32): self.pads = pads self.usb_clk_freq = int(usb_clk_freq) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 50a2f9edf..97227ee09 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -190,7 +190,7 @@ # DVI Color <-> channel mapping -------------------------------------------------------------------- _dvi_c2d = {"b": 0, "g": 1, "r": 2} -class VideoTimingGenerator(Module, AutoCSR): +class VideoTimingGenerator(LiteXModule): def __init__(self, default_video_timings="800x600@60Hz"): # Check / Get Video Timings (can be str or dict) if isinstance(default_video_timings, str): @@ -251,7 +251,7 @@ def __init__(self, default_video_timings="800x600@60Hz"): vactive = Signal() fsm = FSM(reset_state="IDLE") fsm = ResetInserter()(fsm) - self.submodules.fsm = fsm + self.fsm = fsm self.comb += fsm.reset.eq(~enable) fsm.act("IDLE", NextValue(hactive, 0), @@ -292,7 +292,7 @@ def __init__(self, default_video_timings="800x600@60Hz"): # Video Patterns ----------------------------------------------------------------------------------- -class ColorBarsPattern(Module): +class ColorBarsPattern(LiteXModule): """Color Bars Pattern""" def __init__(self): self.enable = Signal(reset=1) @@ -310,7 +310,7 @@ def __init__(self): fsm = FSM(reset_state="IDLE") fsm = ResetInserter()(fsm) - self.submodules.fsm = fsm + self.fsm = fsm self.comb += fsm.reset.eq(~self.enable) fsm.act("IDLE", NextValue(pix, 0), @@ -380,7 +380,7 @@ def import_bdf_font(filename): bitmap_index = 0 return font -class CSIInterpreter(Module): +class CSIInterpreter(LiteXModule): # FIXME: Very basic/minimal implementation for now. esc_start = 0x1b csi_start = ord("[") @@ -403,7 +403,7 @@ def __init__(self, enable=True): csi_bytes = Array([Signal(8) for _ in range(8)]) csi_final = Signal(8) - self.submodules.fsm = fsm = FSM(reset_state="RECOPY") + self.fsm = fsm = FSM(reset_state="RECOPY") fsm.act("RECOPY", sink.connect(source), If(sink.valid & (sink.data == self.esc_start), @@ -453,7 +453,7 @@ def __init__(self, enable=True): NextState("RECOPY") ) -class VideoTerminal(Module): +class VideoTerminal(LiteXModule): def __init__(self, hres=800, vres=600, with_csi_interpreter=True): self.enable = Signal(reset=1) self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) @@ -492,12 +492,12 @@ def __init__(self, hres=800, vres=600, with_csi_interpreter=True): # ------------------- # Optional CSI Interpreter. - self.submodules.csi_interpreter = CSIInterpreter(enable=with_csi_interpreter) + self.csi_interpreter = CSIInterpreter(enable=with_csi_interpreter) self.comb += uart_sink.connect(self.csi_interpreter.sink) uart_sink = self.csi_interpreter.source self.comb += term_wrport.dat_w[font_width:].eq(self.csi_interpreter.color) - self.submodules.uart_fifo = stream.SyncFIFO([("data", 8)], 8) + self.uart_fifo = stream.SyncFIFO([("data", 8)], 8) self.comb += uart_sink.connect(self.uart_fifo.sink) uart_sink = self.uart_fifo.source @@ -505,7 +505,7 @@ def __init__(self, hres=800, vres=600, with_csi_interpreter=True): x_term = term_wrport.adr[:7] y_term = term_wrport.adr[7:] y_term_rollover = Signal() - self.submodules.uart_fsm = uart_fsm = FSM(reset_state="RESET") + self.uart_fsm = uart_fsm = FSM(reset_state="RESET") uart_fsm.act("RESET", NextValue(x_term, 0), NextValue(y_term, 0), @@ -644,7 +644,7 @@ def __init__(self, hres=800, vres=600, with_csi_interpreter=True): # Video FrameBuffer -------------------------------------------------------------------------------- -class VideoFrameBuffer(Module, AutoCSR): +class VideoFrameBuffer(LiteXModule): """Video FrameBuffer""" def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False, format="rgb888"): self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) @@ -660,7 +660,7 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 # Video DMA. from litedram.frontend.dma import LiteDRAMDMAReader - self.submodules.dma = LiteDRAMDMAReader(dram_port, fifo_depth=fifo_depth//(dram_port.data_width//8), fifo_buffered=True) + self.dma = LiteDRAMDMAReader(dram_port, fifo_depth=fifo_depth//(dram_port.data_width//8), fifo_buffered=True) self.dma.add_csr( default_base = base, default_length = hres*vres*depth//8, # 32-bit RGB-888 or 16-bit RGB-565 @@ -671,19 +671,19 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 # If DRAM Data Width > depth and Video clock is faster than sys_clk: if (dram_port.data_width > depth) and clock_faster_than_sys: # Do Clock Domain Crossing first... - self.submodules.cdc = stream.ClockDomainCrossing([("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain) + self.cdc = stream.ClockDomainCrossing([("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain) self.comb += self.dma.source.connect(self.cdc.sink) # ... and then Data-Width Conversion. - self.submodules.conv = ClockDomainsRenamer(clock_domain)(stream.Converter(dram_port.data_width, depth)) + self.conv = ClockDomainsRenamer(clock_domain)(stream.Converter(dram_port.data_width, depth)) self.comb += self.cdc.source.connect(self.conv.sink) video_pipe_source = self.conv.source # Elsif DRAM Data Width <= depth or Video clock is slower than sys_clk: else: # Do Data-Width Conversion first... - self.submodules.conv = stream.Converter(dram_port.data_width, depth) + self.conv = stream.Converter(dram_port.data_width, depth) self.comb += self.dma.source.connect(self.conv.sink) # ... and then Clock Domain Crossing. - self.submodules.cdc = stream.ClockDomainCrossing([("data", depth)], cd_from="sys", cd_to=clock_domain) + self.cdc = stream.ClockDomainCrossing([("data", depth)], cd_from="sys", cd_to=clock_domain) self.comb += self.conv.source.connect(self.cdc.sink) if (dram_port.data_width < depth) and (depth == 32): # FIXME. self.comb += [ @@ -722,7 +722,7 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 # Generic (Very Generic PHY supporting VGA/DVI and variations). -class VideoGenericPHY(Module): +class VideoGenericPHY(LiteXModule): def __init__(self, pads, clock_domain="sys", with_clk_ddr_output=True): self.sink = sink = stream.Endpoint(video_data_layout) @@ -767,15 +767,15 @@ class VideoDVIPHY(VideoGenericPHY): pass # HDMI (Generic). -class VideoHDMI10to1Serializer(Module): +class VideoHDMI10to1Serializer(LiteXModule): def __init__(self, data_i, data_o, clock_domain): # Clock Domain Crossing. - self.submodules.cdc = stream.ClockDomainCrossing([("data", 10)], cd_from=clock_domain, cd_to=clock_domain + "5x") + self.cdc = stream.ClockDomainCrossing([("data", 10)], cd_from=clock_domain, cd_to=clock_domain + "5x") self.comb += self.cdc.sink.valid.eq(1) self.comb += self.cdc.sink.data.eq(data_i) # 10:2 Gearbox. - self.submodules.gearbox = ClockDomainsRenamer(clock_domain + "5x")(stream.Gearbox(i_dw=10, o_dw=2, msb_first=False)) + self.gearbox = ClockDomainsRenamer(clock_domain + "5x")(stream.Gearbox(i_dw=10, o_dw=2, msb_first=False)) self.comb += self.cdc.source.connect(self.gearbox.sink) # 2:1 Output DDR. @@ -787,7 +787,7 @@ def __init__(self, data_i, data_o, clock_domain): o = data_o, ) -class VideoHDMIPHY(Module): +class VideoHDMIPHY(LiteXModule): def __init__(self, pads, clock_domain="sys", pn_swap=[]): self.sink = sink = stream.Endpoint(video_data_layout) @@ -835,7 +835,7 @@ def __init__(self, pads, clock_domain="sys", pn_swap=[]): # HDMI (Gowin). -class VideoGowinHDMIPHY(Module): +class VideoGowinHDMIPHY(LiteXModule): def __init__(self, pads, clock_domain="sys", pn_swap=[]): self.sink = sink = stream.Endpoint(video_data_layout) @@ -880,7 +880,7 @@ def __init__(self, pads, clock_domain="sys", pn_swap=[]): # HDMI (Xilinx Spartan6). -class VideoS6HDMIPHY(Module): +class VideoS6HDMIPHY(LiteXModule): def __init__(self, pads, clock_domain="sys"): self.sink = sink = stream.Endpoint(video_data_layout) @@ -918,7 +918,7 @@ def __init__(self, pads, clock_domain="sys"): # HDMI (Xilinx 7-Series). -class VideoS7HDMI10to1Serializer(Module): +class VideoS7HDMI10to1Serializer(LiteXModule): def __init__(self, data_i, data_o, clock_domain): # Note: 2 OSERDESE2 are coupled for 10:1 Serialization (8:1 Max with one). @@ -960,7 +960,7 @@ def __init__(self, data_i, data_o, clock_domain): ) -class VideoS7HDMIPHY(Module): +class VideoS7HDMIPHY(LiteXModule): def __init__(self, pads, clock_domain="sys"): self.sink = sink = stream.Endpoint(video_data_layout) @@ -997,7 +997,7 @@ def __init__(self, pads, clock_domain="sys"): self.specials += Instance("OBUFDS", i_I=pad_o, o_O=pad_p, o_OB=pad_n) -class VideoS7GTPHDMIPHY(Module): +class VideoS7GTPHDMIPHY(LiteXModule): def __init__(self, pads, sys_clk_freq, clock_domain="sys", clk_freq=148.5e6, refclk=None): assert sys_clk_freq >= clk_freq self.sink = sink = stream.Endpoint(video_data_layout) @@ -1028,7 +1028,7 @@ def __init__(self, pads, sys_clk_freq, clock_domain="sys", clk_freq=148.5e6, ref o_O = refclk_se ) refclk = refclk_se - self.submodules.pll = pll = GTPQuadPLL(refclk, clk_freq, 1.485e9) + self.pll = pll = GTPQuadPLL(refclk, clk_freq, 1.485e9) # Encode/Serialize Datas. for color, channel in _dvi_c2d.items(): From b35c6580e86e8de52fcdbaafcbe97a5722daccba Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 15 Jul 2023 21:39:46 +0200 Subject: [PATCH 101/454] soc/cores/clock: Switch to LiteXModule. --- litex/soc/cores/clock/efinix.py | 2 +- litex/soc/cores/clock/gowin_gw1n.py | 4 ++-- litex/soc/cores/clock/intel_common.py | 4 +++- litex/soc/cores/clock/lattice_ecp5.py | 8 +++++--- litex/soc/cores/clock/lattice_ice40.py | 4 +++- litex/soc/cores/clock/lattice_nx.py | 8 +++++--- litex/soc/cores/clock/xilinx_common.py | 4 +++- litex/soc/cores/clock/xilinx_s7.py | 4 +++- litex/soc/cores/clock/xilinx_us.py | 6 ++++-- litex/soc/cores/clock/xilinx_usp.py | 6 ++++-- 10 files changed, 33 insertions(+), 17 deletions(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index fc05120aa..9b07aa4ba 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -15,7 +15,7 @@ # Efinix / TRIONPLL ---------------------------------------------------------------------------------- -class EFINIXPLL(Module): +class EFINIXPLL(LiteXModule): nclkouts_max = 3 def __init__(self, platform, n=0, version="V1_V2"): self.logger = logging.getLogger("EFINIXPLL") diff --git a/litex/soc/cores/clock/gowin_gw1n.py b/litex/soc/cores/clock/gowin_gw1n.py index b61894aff..2907b5d19 100644 --- a/litex/soc/cores/clock/gowin_gw1n.py +++ b/litex/soc/cores/clock/gowin_gw1n.py @@ -13,7 +13,7 @@ # GoWin / GW1NOSC ---------------------------------------------------------------------------------- -class GW1NOSC(Module): +class GW1NOSC(LiteXModule): osc_div_range = (2, 128) def __init__(self, device, freq, margin=1e-2): self.logger = logging.getLogger("GW1NOSC") @@ -47,7 +47,7 @@ def __init__(self, device, freq, margin=1e-2): # GoWin / GW1NPLL ---------------------------------------------------------------------------------- -class GW1NPLL(Module): +class GW1NPLL(LiteXModule): nclkouts_max = 4 def __init__(self, devicename, device, vco_margin=0): diff --git a/litex/soc/cores/clock/intel_common.py b/litex/soc/cores/clock/intel_common.py index cba985567..d5ea7d012 100644 --- a/litex/soc/cores/clock/intel_common.py +++ b/litex/soc/cores/clock/intel_common.py @@ -12,6 +12,8 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.gen import * + from litex.build.io import DifferentialInput from litex.soc.interconnect.csr import * @@ -24,7 +26,7 @@ def geometric_mean(vals): return reduce(mul, vals, 1) ** (1 / len(vals)) -class IntelClocking(Module, AutoCSR): +class IntelClocking(LiteXModule): def __init__(self, vco_margin=0): self.vco_margin = vco_margin self.reset = Signal() diff --git a/litex/soc/cores/clock/lattice_ecp5.py b/litex/soc/cores/clock/lattice_ecp5.py index 3ae2d0a8a..ea69b945f 100644 --- a/litex/soc/cores/clock/lattice_ecp5.py +++ b/litex/soc/cores/clock/lattice_ecp5.py @@ -8,11 +8,13 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.gen import * + from litex.soc.cores.clock.common import * # Lattice / ECP5 PLL ------------------------------------------------------------------------------- -class ECP5PLL(Module): +class ECP5PLL(LiteXModule): nclkouts_max = 4 clki_div_range = (1, 128+1) clkfb_div_range = (1, 128+1) @@ -171,7 +173,7 @@ def do_finalize(self): # Lattice / ECP5 Dynamic Delay --------------------------------------------------------------------- -class ECP5DynamicDelay(Module): +class ECP5DynamicDelay(LiteXModule): tap_delay = 25e-12 ntaps = 128 @@ -203,7 +205,7 @@ def __init__(self, i=None, o=None, taps=None): # FSM. self.comb += done.eq( self.taps == curr_taps) self.comb += change.eq(self.taps != curr_taps) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(change, NextState("DELAYF-RST") diff --git a/litex/soc/cores/clock/lattice_ice40.py b/litex/soc/cores/clock/lattice_ice40.py index 9a56fccdd..ee6b0f6ba 100644 --- a/litex/soc/cores/clock/lattice_ice40.py +++ b/litex/soc/cores/clock/lattice_ice40.py @@ -7,6 +7,8 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.gen import * + from litex.soc.cores.clock.common import * # Lattice / iCE40 ---------------------------------------------------------------------------------- @@ -15,7 +17,7 @@ # - add phase support. # - add support for GENCLK_HALF to be able to generate clock down to 8MHz. -class iCE40PLL(Module): +class iCE40PLL(LiteXModule): nclkouts_max = 1 divr_range = (0, 16) divf_range = (0, 128) diff --git a/litex/soc/cores/clock/lattice_nx.py b/litex/soc/cores/clock/lattice_nx.py index 986bd5ffa..429b49172 100644 --- a/litex/soc/cores/clock/lattice_nx.py +++ b/litex/soc/cores/clock/lattice_nx.py @@ -13,18 +13,20 @@ from migen import * +from litex.gen import * + from litex.soc.cores.clock.common import * io_i2 = namedtuple('io_i2',['io', 'i2', 'IPP_CTRL', 'BW_CTL_BIAS', 'IPP_SEL']) nx_pll_param_permutation = namedtuple("nx_pll_param_permutation",[ - "C1","C2","C3","C4","C5","C6", - "IPP_CTRL","BW_CTL_BIAS","IPP_SEL","CSET","CRIPPLE","V2I_PP_RES","IPI_CMP"]) + "C1","C2","C3","C4","C5","C6", + "IPP_CTRL","BW_CTL_BIAS","IPP_SEL","CSET","CRIPPLE","V2I_PP_RES","IPI_CMP"]) # Lattice / NX OSCA -------------------------------------------------------------------------------- # NOTE This clock has +/- 15% accuracy -class NXOSCA(Module): +class NXOSCA(LiteXModule): nclkouts_max = 2 clk_hf_div_range = (0, 255) clk_hf_freq_range = (1.76, 450e6) diff --git a/litex/soc/cores/clock/xilinx_common.py b/litex/soc/cores/clock/xilinx_common.py index e79ed45ae..4de2cb596 100644 --- a/litex/soc/cores/clock/xilinx_common.py +++ b/litex/soc/cores/clock/xilinx_common.py @@ -7,6 +7,8 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.gen import * + from litex.build.io import DifferentialInput from litex.soc.interconnect.csr import * @@ -15,7 +17,7 @@ # Xilinx / Generic --------------------------------------------------------------------------------- -class XilinxClocking(Module, AutoCSR): +class XilinxClocking(LiteXModule): clkfbout_mult_frange = (2, 64+1) clkout_divide_range = (1, 128+1) diff --git a/litex/soc/cores/clock/xilinx_s7.py b/litex/soc/cores/clock/xilinx_s7.py index 86d6ca0e6..1a520772f 100644 --- a/litex/soc/cores/clock/xilinx_s7.py +++ b/litex/soc/cores/clock/xilinx_s7.py @@ -6,6 +6,8 @@ from migen import * +from litex.gen import * + from litex.soc.cores.clock.common import * from litex.soc.cores.clock.xilinx_common import * @@ -104,7 +106,7 @@ def do_finalize(self): self.specials += Instance("MMCME2_ADV", **self.params) -class S7IDELAYCTRL(Module): +class S7IDELAYCTRL(LiteXModule): def __init__(self, cd, reset_cycles=16): reset_counter = Signal(log2_int(reset_cycles), reset=reset_cycles - 1) ic_reset = Signal(reset=1) diff --git a/litex/soc/cores/clock/xilinx_us.py b/litex/soc/cores/clock/xilinx_us.py index 34666c1ca..cd9a2cde0 100644 --- a/litex/soc/cores/clock/xilinx_us.py +++ b/litex/soc/cores/clock/xilinx_us.py @@ -4,6 +4,8 @@ # Copyright (c) 2018-2020 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause +from litex.gen import * + from litex.soc.cores.clock.common import * from litex.soc.cores.clock.xilinx_common import * @@ -107,9 +109,9 @@ def do_finalize(self): self.specials += Instance("MMCME2_ADV", **self.params) -class USIDELAYCTRL(Module): +class USIDELAYCTRL(LiteXModule): def __init__(self, cd_ref, cd_sys, reset_cycles=64, ready_cycles=64): - self.clock_domains.cd_ic = ClockDomain() + self.cd_ic = ClockDomain() ic_reset_counter = Signal(max=reset_cycles, reset=reset_cycles-1) ic_reset = Signal(reset=1) cd_ref_sync = getattr(self.sync, cd_ref.name) diff --git a/litex/soc/cores/clock/xilinx_usp.py b/litex/soc/cores/clock/xilinx_usp.py index 6e3c689a1..11fbb2ed7 100644 --- a/litex/soc/cores/clock/xilinx_usp.py +++ b/litex/soc/cores/clock/xilinx_usp.py @@ -4,6 +4,8 @@ # Copyright (c) 2018-2020 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause +from litex.gen import * + from litex.soc.cores.clock.common import * from litex.soc.cores.clock.xilinx_common import * @@ -107,9 +109,9 @@ def do_finalize(self): self.specials += Instance("MMCME2_ADV", **self.params) -class USPIDELAYCTRL(Module): +class USPIDELAYCTRL(LiteXModule): def __init__(self, cd_ref, cd_sys, reset_cycles=64, ready_cycles=64): - self.clock_domains.cd_ic = ClockDomain() + self.cd_ic = ClockDomain() ic_reset_counter = Signal(max=reset_cycles, reset=reset_cycles-1) ic_reset = Signal(reset=1) cd_ref_sync = getattr(self.sync, cd_ref.name) From 028f7eb72f88a0368e8272cce95d552cc6e8749a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 17 Jul 2023 09:12:25 +0200 Subject: [PATCH 102/454] cores/ram: Switch to LiteXModule. --- litex/soc/cores/ram/lattice_ice40.py | 5 ++++- litex/soc/cores/ram/lattice_nx.py | 5 ++++- litex/soc/cores/ram/xilinx_fifo_sync_macro.py | 12 ++++++++++-- litex/soc/cores/ram/xilinx_usp_hbm2.py | 2 +- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/litex/soc/cores/ram/lattice_ice40.py b/litex/soc/cores/ram/lattice_ice40.py index ad0acee74..08ea05967 100644 --- a/litex/soc/cores/ram/lattice_ice40.py +++ b/litex/soc/cores/ram/lattice_ice40.py @@ -7,6 +7,9 @@ # SPDX-License-Identifier: BSD-2-Clause from migen import * + +from litex.gen import * + from litex.soc.interconnect import wishbone kB = 1024 @@ -22,7 +25,7 @@ """ -class Up5kSPRAM(Module): +class Up5kSPRAM(LiteXModule): def __init__(self, width=32, size=64*kB): self.bus = wishbone.Interface(width) diff --git a/litex/soc/cores/ram/lattice_nx.py b/litex/soc/cores/ram/lattice_nx.py index 7dce4089f..836c1a314 100644 --- a/litex/soc/cores/ram/lattice_nx.py +++ b/litex/soc/cores/ram/lattice_nx.py @@ -8,6 +8,9 @@ # SPDX-License-Identifier: BSD-2-Clause from migen import * + +from litex.gen import * + from litex.soc.interconnect import wishbone kB = 1024 @@ -48,7 +51,7 @@ def initval_parameters(contents, width): return parameters -class NXLRAM(Module): +class NXLRAM(LiteXModule): def __init__(self, width=32, size=128*kB, init=[]): self.bus = wishbone.Interface(width) assert width in [32, 64] diff --git a/litex/soc/cores/ram/xilinx_fifo_sync_macro.py b/litex/soc/cores/ram/xilinx_fifo_sync_macro.py index a1a5ae04f..89ea80f84 100644 --- a/litex/soc/cores/ram/xilinx_fifo_sync_macro.py +++ b/litex/soc/cores/ram/xilinx_fifo_sync_macro.py @@ -1,8 +1,16 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2022 Antmicro +# SPDX-License-Identifier: BSD-2-Clause + from migen import * +from litex.gen import * + from litex.soc.interconnect.stream import SyncFIFO -class FIFOSyncMacro(Module, Record): +class FIFOSyncMacro(LiteXModule, Record): """FIFOSyncMacro Provides an equivalent of Xilinx' FIFO_SYNC_MACRO which is a unimacro dedicated for 7 series @@ -86,7 +94,7 @@ def __init__(self, fifo_size="18Kb", data_width=32, almost_empty_offset=0, almos self.fifo_depth = fifo_depth = (int)(fifo_size * 1024 / macro_data_width) - self.submodules.fifo = fifo = ResetInserter()(SyncFIFO([("data", data_width)], fifo_depth)) + self.fifo = fifo = ResetInserter()(SyncFIFO([("data", data_width)], fifo_depth)) self.comb += [ fifo.reset.eq(self.reset), diff --git a/litex/soc/cores/ram/xilinx_usp_hbm2.py b/litex/soc/cores/ram/xilinx_usp_hbm2.py index b0ed356bd..270379917 100644 --- a/litex/soc/cores/ram/xilinx_usp_hbm2.py +++ b/litex/soc/cores/ram/xilinx_usp_hbm2.py @@ -19,7 +19,7 @@ # Ultrascale + HBM2 IP Wrapper --------------------------------------------------------------------- -class USPHBM2(Module, AutoCSR): +class USPHBM2(LiteXModule): """Xilinx Virtex US+ High Bandwidth Memory 2 IP wrapper""" def __init__(self, platform, hbm_ip_name="hbm_0"): self.platform = platform From 39ff69ade7fa5cacf35220e99d1aaa9c7d92f836 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 17 Jul 2023 09:14:47 +0200 Subject: [PATCH 103/454] cores/spi: Switch to LiteXModule. --- litex/soc/cores/spi/spi_bone.py | 4 +++- litex/soc/cores/spi/spi_master.py | 6 ++++-- litex/soc/cores/spi/spi_slave.py | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/spi/spi_bone.py b/litex/soc/cores/spi/spi_bone.py index 11506c72f..e0df08e20 100644 --- a/litex/soc/cores/spi/spi_bone.py +++ b/litex/soc/cores/spi/spi_bone.py @@ -9,6 +9,8 @@ from migen.fhdl.specials import Tristate, TSTriple from migen.genlib.cdc import MultiReg +from litex.gen import * + from litex.soc.integration.doc import ModuleDoc, AutoDoc from litex.soc.interconnect import wishbone, stream @@ -117,7 +119,7 @@ class SPI2WireDocumentation(ModuleDoc): # SPIBone Core ------------------------------------------------------------------------------------- -class SPIBone(Module, ModuleDoc, AutoDoc): +class SPIBone(LiteXModule, ModuleDoc): """Wishbone Bridge over SPI This module allows for accessing a Wishbone bridge over a {}-wire protocol. diff --git a/litex/soc/cores/spi/spi_master.py b/litex/soc/cores/spi/spi_master.py index 6a0763af4..377cb4782 100644 --- a/litex/soc/cores/spi/spi_master.py +++ b/litex/soc/cores/spi/spi_master.py @@ -9,11 +9,13 @@ from migen import * from migen.genlib.cdc import MultiReg +from litex.gen import * + from litex.soc.interconnect.csr import * # SPI Master --------------------------------------------------------------------------------------- -class SPIMaster(Module, AutoCSR): +class SPIMaster(LiteXModule): """4-wire SPI Master Provides a simple and minimal hardware SPI Master with CPOL=0, CPHA=0 and build time @@ -70,7 +72,7 @@ def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True, ] # Control FSM ------------------------------------------------------------------------------ - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", self.done.eq(1), If(self.start, diff --git a/litex/soc/cores/spi/spi_slave.py b/litex/soc/cores/spi/spi_slave.py index 6dfa03323..2b7c4564a 100644 --- a/litex/soc/cores/spi/spi_slave.py +++ b/litex/soc/cores/spi/spi_slave.py @@ -9,6 +9,8 @@ from migen import * from migen.genlib.cdc import MultiReg +from litex.gen import * + from litex.soc.interconnect.csr import * # SPI Slave ---------------------------------------------------------------------------------------- @@ -60,7 +62,7 @@ def __init__(self, pads, data_width): self.comb += clk_fall.eq(~clk & clk_d) # Control FSM ------------------------------------------------------------------------------ - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(cs, self.start.eq(1), From 3fc16f54f1232207e101e8131fc8b82f81abcc99 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 17 Jul 2023 09:26:58 +0200 Subject: [PATCH 104/454] soc/cores/cpu: Switch to LiteXModule. --- litex/soc/cores/cpu/__init__.py | 4 +++- litex/soc/cores/cpu/cv32e40p/core.py | 30 ++++++++++++++------------ litex/soc/cores/cpu/cv32e41p/core.py | 16 ++++++++------ litex/soc/cores/cpu/cva5/core.py | 3 +++ litex/soc/cores/cpu/eos_s3/core.py | 4 ++-- litex/soc/cores/cpu/femtorv/core.py | 4 +++- litex/soc/cores/cpu/firev/core.py | 4 +++- litex/soc/cores/cpu/gowin_emcu/core.py | 4 +++- litex/soc/cores/cpu/ibex/core.py | 6 +++--- litex/soc/cores/cpu/lm32/core.py | 2 ++ litex/soc/cores/cpu/marocchino/core.py | 2 ++ litex/soc/cores/cpu/microwatt/core.py | 8 +++---- litex/soc/cores/cpu/minerva/core.py | 2 ++ litex/soc/cores/cpu/mor1kx/core.py | 2 ++ litex/soc/cores/cpu/naxriscv/core.py | 2 +- litex/soc/cores/cpu/neorv32/core.py | 2 +- litex/soc/cores/cpu/openc906/core.py | 4 +++- litex/soc/cores/cpu/picorv32/core.py | 2 ++ litex/soc/cores/cpu/serv/core.py | 2 ++ litex/soc/cores/cpu/vexriscv/core.py | 4 +++- litex/soc/cores/cpu/zynq7000/core.py | 4 +++- litex/soc/cores/cpu/zynqmp/core.py | 6 +++++- 22 files changed, 77 insertions(+), 40 deletions(-) diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index 52c192d6e..0ebc65923 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -12,9 +12,11 @@ from migen import * +from litex.gen import * + # CPU (Generic) ------------------------------------------------------------------------------------ -class CPU(Module): +class CPU(LiteXModule): category = None family = None name = None diff --git a/litex/soc/cores/cpu/cv32e40p/core.py b/litex/soc/cores/cpu/cv32e40p/core.py index 80d5bba3f..694e0460f 100644 --- a/litex/soc/cores/cpu/cv32e40p/core.py +++ b/litex/soc/cores/cpu/cv32e40p/core.py @@ -10,6 +10,8 @@ from migen import * from migen.fhdl.specials import Tristate +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone, stream from litex.soc.interconnect.csr import * @@ -84,14 +86,14 @@ def add_manifest_sources(platform, manifest): # OBI <> Wishbone ---------------------------------------------------------------------------------- -class OBI2Wishbone(Module): +class OBI2Wishbone(LiteXModule): def __init__(self, obi, wb): addr = Signal.like(obi.addr) be = Signal.like(obi.be) we = Signal.like(obi.we) wdata = Signal.like(obi.wdata) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", # On OBI request: If(obi.req, @@ -134,9 +136,9 @@ def __init__(self, obi, wb): ) ) -class Wishbone2OBI(Module): +class Wishbone2OBI(LiteXModule): def __init__(self, wb, obi): - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(wb.cyc & wb.stb, obi.req.eq(1), @@ -158,9 +160,9 @@ def __init__(self, wb, obi): # Wishbone <> APB ---------------------------------------------------------------------------------- -class Wishbone2APB(Module): +class Wishbone2APB(LiteXModule): def __init__(self, wb, apb): - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(wb.cyc & wb.stb, NextState("ACK"), @@ -182,7 +184,7 @@ def __init__(self, wb, apb): # Trace Collector ---------------------------------------------------------------------------------- -class TraceCollector(Module, AutoCSR): +class TraceCollector(LiteXModule): def __init__(self, trace_depth=16384): self.bus = bus = wishbone.Interface() self.sink = sink = stream.Endpoint([("data", 32)]) @@ -228,7 +230,7 @@ def __init__(self, trace_depth=16384): # Trace Debugger ----------------------------------------------------------------------------------- -class TraceDebugger(Module): +class TraceDebugger(LiteXModule): def __init__(self): self.bus = wishbone.Interface() self.source = source = stream.Endpoint([("data", 32)]) @@ -236,7 +238,7 @@ def __init__(self): apb = Record(apb_layout) - self.submodules.bus_conv = Wishbone2APB(self.bus, apb) + self.bus_conv = Wishbone2APB(self.bus, apb) self.trace_params = dict( # Clk / Rst. @@ -278,7 +280,7 @@ def add_sources(platform): # Debug Module ------------------------------------------------------------------------------------- -class DebugModule(Module): +class DebugModule(LiteXModule): jtag_layout = [ ("tck", 1), ("tms", 1), @@ -295,8 +297,8 @@ def __init__(self, pads=None): dmbus = Record(obi_layout) sbbus = Record(obi_layout) - self.submodules.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus) - self.submodules.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus) + self.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus) + self.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus) self.debug_req = Signal() self.ndmreset = Signal() @@ -390,8 +392,8 @@ def __init__(self, platform, variant="standard"): dbus = Record(obi_layout) # OBI <> Wishbone. - self.submodules.ibus_conv = OBI2Wishbone(ibus, self.ibus) - self.submodules.dbus_conv = OBI2Wishbone(dbus, self.dbus) + self.ibus_conv = OBI2Wishbone(ibus, self.ibus) + self.dbus_conv = OBI2Wishbone(dbus, self.dbus) self.comb += [ ibus.we.eq(0), diff --git a/litex/soc/cores/cpu/cv32e41p/core.py b/litex/soc/cores/cpu/cv32e41p/core.py index 98b3e1a18..ec8e76c6c 100644 --- a/litex/soc/cores/cpu/cv32e41p/core.py +++ b/litex/soc/cores/cpu/cv32e41p/core.py @@ -10,6 +10,8 @@ from migen import * from migen.fhdl.specials import Tristate +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone, stream from litex.soc.interconnect.csr import * @@ -78,7 +80,7 @@ def __init__(self, obi, wb): we = Signal.like(obi.we) wdata = Signal.like(obi.wdata) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", # On OBI request: If(obi.req, @@ -123,7 +125,7 @@ def __init__(self, obi, wb): class Wishbone2OBI(Module): def __init__(self, wb, obi): - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(wb.cyc & wb.stb, obi.req.eq(1), @@ -147,7 +149,7 @@ def __init__(self, wb, obi): class Wishbone2APB(Module): def __init__(self, wb, apb): - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(wb.cyc & wb.stb, NextState("ACK"), @@ -186,8 +188,8 @@ def __init__(self, pads=None): dmbus = Record(obi_layout) sbbus = Record(obi_layout) - self.submodules.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus) - self.submodules.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus) + self.sbbus_conv = OBI2Wishbone(sbbus, self.sbbus) + self.dmbus_conv = Wishbone2OBI(self.dmbus, dmbus) self.debug_req = Signal() self.ndmreset = Signal() @@ -276,8 +278,8 @@ def __init__(self, platform, variant="standard"): dbus = Record(obi_layout) # OBI <> Wishbone. - self.submodules.ibus_conv = OBI2Wishbone(ibus, self.ibus) - self.submodules.dbus_conv = OBI2Wishbone(dbus, self.dbus) + self.ibus_conv = OBI2Wishbone(ibus, self.ibus) + self.dbus_conv = OBI2Wishbone(dbus, self.dbus) self.comb += [ ibus.we.eq(0), diff --git a/litex/soc/cores/cpu/cva5/core.py b/litex/soc/cores/cpu/cva5/core.py index b69d9d900..f973ca2b9 100644 --- a/litex/soc/cores/cpu/cva5/core.py +++ b/litex/soc/cores/cpu/cva5/core.py @@ -9,6 +9,9 @@ from migen import * from litex import get_data_mod + +from litex.gen import * + from litex.soc.interconnect import wishbone from litex.soc.interconnect.csr import * from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 diff --git a/litex/soc/cores/cpu/eos_s3/core.py b/litex/soc/cores/cpu/eos_s3/core.py index 59deead2d..7289e9252 100644 --- a/litex/soc/cores/cpu/eos_s3/core.py +++ b/litex/soc/cores/cpu/eos_s3/core.py @@ -59,8 +59,8 @@ def __init__(self, platform, variant, *args, **kwargs): eos_s3_0_rst = Signal() eos_s3_1_clk = Signal() eos_s3_1_rst = Signal() - self.clock_domains.cd_eos_s3_0 = ClockDomain() - self.clock_domains.cd_eos_s3_1 = ClockDomain() + self.cd_eos_s3_0 = ClockDomain() + self.cd_eos_s3_1 = ClockDomain() self.specials += Instance("gclkbuff", i_A = eos_s3_0_clk, o_Z = ClockSignal("eos_s3_0") diff --git a/litex/soc/cores/cpu/femtorv/core.py b/litex/soc/cores/cpu/femtorv/core.py index 2d85e8857..20d86e379 100644 --- a/litex/soc/cores/cpu/femtorv/core.py +++ b/litex/soc/cores/cpu/femtorv/core.py @@ -8,6 +8,8 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 @@ -114,7 +116,7 @@ def __init__(self, platform, variant="standard"): write = mbus.wmask != 0 read = mbus.rstrb - self.submodules.fsm = fsm = FSM(reset_state="WAIT") + self.fsm = fsm = FSM(reset_state="WAIT") fsm.act("WAIT", # Latch Address + Bytes to Words conversion. NextValue(idbus.adr, mbus.addr[2:]), diff --git a/litex/soc/cores/cpu/firev/core.py b/litex/soc/cores/cpu/firev/core.py index 048bf85ab..0a15d0184 100644 --- a/litex/soc/cores/cpu/firev/core.py +++ b/litex/soc/cores/cpu/firev/core.py @@ -8,6 +8,8 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 @@ -96,7 +98,7 @@ def __init__(self, platform, variant="standard"): # Adapt FireV Mem Bus to Wishbone. # -------------------------------- - self.submodules.fsm = fsm = FSM(reset_state="WAIT") + self.fsm = fsm = FSM(reset_state="WAIT") fsm.act("WAIT", If(mbus.out_ram_in_valid, idbus.stb.eq(1), diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 8709334c5..ce492b39c 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -6,6 +6,8 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect import wishbone, ahb from litex.soc.cores.cpu import CPU @@ -17,7 +19,7 @@ def __init__(self, bus): read = Signal() self.comb += bus.resp.eq(0) - self.submodules.fsm = fsm = FSM() + self.fsm = fsm = FSM() fsm.act("IDLE", bus.readyout.eq(1), If(bus.sel & bus.trans[1], diff --git a/litex/soc/cores/cpu/ibex/core.py b/litex/soc/cores/cpu/ibex/core.py index 495d2d46b..358356f40 100644 --- a/litex/soc/cores/cpu/ibex/core.py +++ b/litex/soc/cores/cpu/ibex/core.py @@ -52,7 +52,7 @@ def __init__(self, obi, wb): we = Signal.like(obi.we) wdata = Signal.like(obi.wdata) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", # On OBI request: If(obi.req, @@ -131,8 +131,8 @@ def __init__(self, platform, variant="standard"): dbus = Record(obi_layout) # OBI <> Wishbone. - self.submodules.ibus_conv = OBI2Wishbone(ibus, self.ibus) - self.submodules.dbus_conv = OBI2Wishbone(dbus, self.dbus) + self.ibus_conv = OBI2Wishbone(ibus, self.ibus) + self.dbus_conv = OBI2Wishbone(dbus, self.dbus) self.comb += [ ibus.we.eq(0), diff --git a/litex/soc/cores/cpu/lm32/core.py b/litex/soc/cores/cpu/lm32/core.py index 389331f65..ac23717e7 100644 --- a/litex/soc/cores/cpu/lm32/core.py +++ b/litex/soc/cores/cpu/lm32/core.py @@ -12,6 +12,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU diff --git a/litex/soc/cores/cpu/marocchino/core.py b/litex/soc/cores/cpu/marocchino/core.py index 29f0865ce..61cdb1e22 100644 --- a/litex/soc/cores/cpu/marocchino/core.py +++ b/litex/soc/cores/cpu/marocchino/core.py @@ -11,6 +11,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU diff --git a/litex/soc/cores/cpu/microwatt/core.py b/litex/soc/cores/cpu/microwatt/core.py index cc9208f0c..e0e7778c5 100644 --- a/litex/soc/cores/cpu/microwatt/core.py +++ b/litex/soc/cores/cpu/microwatt/core.py @@ -132,7 +132,7 @@ def __init__(self, platform, variant="standard"): ) # VHDL to Verilog Converter. - self.submodules.cpu_vhd2v_converter = VHD2VConverter(platform, + self.cpu_vhd2v_converter = VHD2VConverter(platform, top_entity = "microwatt_wrapper", build_dir = os.path.abspath(os.path.dirname(__file__)), force_convert = ("ghdl" in self.variant), @@ -147,7 +147,7 @@ def set_reset_address(self, reset_address): def add_soc_components(self, soc): if "irq" in self.variant: - self.submodules.xics = XICSSlave( + self.xics = XICSSlave( platform = self.platform, variant = self.variant, core_irq_out = self.core_ext_irq, @@ -293,12 +293,12 @@ def __init__(self, platform, core_irq_out=Signal(), int_level_in=Signal(16), var ) # VHDL to Verilog Converter. - self.submodules.icp_vhd2v_converter = VHD2VConverter(platform, + self.icp_vhd2v_converter = VHD2VConverter(platform, top_entity = "xics_icp_wrapper", build_dir = os.path.abspath(os.path.dirname(__file__)), force_convert = ("ghdl" in self.variant), ) - self.submodules.ics_vhd2v_converter = VHD2VConverter(platform, + self.ics_vhd2v_converter = VHD2VConverter(platform, top_entity = "xics_ics_wrapper", build_dir = os.path.abspath(os.path.dirname(__file__)), force_convert = ("ghdl" in self.variant), diff --git a/litex/soc/cores/cpu/minerva/core.py b/litex/soc/cores/cpu/minerva/core.py index e8cb53e7c..f0ad4324e 100644 --- a/litex/soc/cores/cpu/minerva/core.py +++ b/litex/soc/cores/cpu/minerva/core.py @@ -10,6 +10,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 diff --git a/litex/soc/cores/cpu/mor1kx/core.py b/litex/soc/cores/cpu/mor1kx/core.py index 9915c18d2..4da94af21 100644 --- a/litex/soc/cores/cpu/mor1kx/core.py +++ b/litex/soc/cores/cpu/mor1kx/core.py @@ -11,6 +11,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 56052b874..51725bbac 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -369,7 +369,7 @@ def add_soc_components(self, soc): if NaxRiscv.jtag_instruction or NaxRiscv.jtag_tap: # Create PoR Clk Domain for debug_reset. - self.clock_domains.cd_debug_por = ClockDomain() + self.cd_debug_por = ClockDomain() self.comb += self.cd_debug_por.clk.eq(ClockSignal("sys")) # Create PoR debug_reset. diff --git a/litex/soc/cores/cpu/neorv32/core.py b/litex/soc/cores/cpu/neorv32/core.py index 68bccd447..14ab85694 100644 --- a/litex/soc/cores/cpu/neorv32/core.py +++ b/litex/soc/cores/cpu/neorv32/core.py @@ -95,7 +95,7 @@ def __init__(self, platform, variant="standard"): i_wb_err_i = idbus.err, ) - self.submodules.vhd2v_converter = VHD2VConverter(platform, + self.vhd2v_converter = VHD2VConverter(platform, top_entity = "neorv32_litex_core_complex", build_dir = os.path.abspath(os.path.dirname(__file__)), work_package = "neorv32", diff --git a/litex/soc/cores/cpu/openc906/core.py b/litex/soc/cores/cpu/openc906/core.py index a798099b8..e0a16f61b 100644 --- a/litex/soc/cores/cpu/openc906/core.py +++ b/litex/soc/cores/cpu/openc906/core.py @@ -9,6 +9,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import axi @@ -35,7 +37,7 @@ class Wishbone2APB(Module): def __init__(self, wb, apb): assert wb.data_width == 32 - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(wb.cyc & wb.stb, NextState("ACK"), diff --git a/litex/soc/cores/cpu/picorv32/core.py b/litex/soc/cores/cpu/picorv32/core.py index 66cb3b99f..c42043da3 100644 --- a/litex/soc/cores/cpu/picorv32/core.py +++ b/litex/soc/cores/cpu/picorv32/core.py @@ -12,6 +12,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index 8a0dff165..982f8f3dc 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -9,6 +9,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index 2fe72d921..86fbaac0c 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -14,6 +14,8 @@ from migen import * +from litex.gen import * + from litex import get_data_mod from litex.soc.interconnect import wishbone @@ -192,7 +194,7 @@ def set_reset_address(self, reset_address): self.cpu_params.update(i_externalResetVector=Signal(32, reset=reset_address)) def add_timer(self): - self.submodules.timer = VexRiscvTimer() + self.timer = VexRiscvTimer() self.cpu_params.update(i_timerInterrupt=self.timer.interrupt) def add_debug(self): diff --git a/litex/soc/cores/cpu/zynq7000/core.py b/litex/soc/cores/cpu/zynq7000/core.py index cd5de084a..afd94559e 100644 --- a/litex/soc/cores/cpu/zynq7000/core.py +++ b/litex/soc/cores/cpu/zynq7000/core.py @@ -11,6 +11,8 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.gen import * + from litex.soc.interconnect import axi from litex.soc.cores.cpu import CPU @@ -55,7 +57,7 @@ def __init__(self, platform, variant, *args, **kwargs): # # # # PS7 Clocking. - self.clock_domains.cd_ps7 = ClockDomain() + self.cd_ps7 = ClockDomain() # PS7 (Minimal) ---------------------------------------------------------------------------- self.ps7_name = None diff --git a/litex/soc/cores/cpu/zynqmp/core.py b/litex/soc/cores/cpu/zynqmp/core.py index 3be75ff76..f143d0356 100644 --- a/litex/soc/cores/cpu/zynqmp/core.py +++ b/litex/soc/cores/cpu/zynqmp/core.py @@ -6,10 +6,14 @@ from migen import * +from litex.gen import * + from litex.soc.cores.cpu import CPU from litex.soc.interconnect import axi +# Zynq MP ------------------------------------------------------------------------------------------ + class ZynqMP(CPU): variants = ["standard"] category = "hardcore" @@ -44,7 +48,7 @@ def __init__(self, platform, variant, *args, **kwargs): self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). self.axi_gp_masters = [None] * 3 # General Purpose AXI Masters. - self.clock_domains.cd_ps = ClockDomain() + self.cd_ps = ClockDomain() self.ps_name = "ps" self.ps_tcl = [] From 3d101b9749820d366619ed311b187d94fc63baa4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 17 Jul 2023 11:14:17 +0200 Subject: [PATCH 105/454] integration/export: When csr_base is specified, make CSR regions definition relative to it. Useful for PCIe based systems when internal CSR base is automatically added by the logic. --- litex/soc/integration/export.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/litex/soc/integration/export.py b/litex/soc/integration/export.py index ecd474669..3a00b88f7 100644 --- a/litex/soc/integration/export.py +++ b/litex/soc/integration/export.py @@ -257,13 +257,14 @@ def get_csr_header(regions, constants, csr_base=None, with_csr_base_define=True, r += "#ifndef CSR_ACCESSORS_DEFINED\n" r += "#include \n" r += "#endif /* ! CSR_ACCESSORS_DEFINED */\n" - csr_base = csr_base if csr_base is not None else regions[next(iter(regions))].origin + _csr_base = regions[next(iter(regions))].origin + csr_base = csr_base if csr_base is not None else _csr_base if with_csr_base_define: - r += "#ifndef CSR_BASE\n" + r += "\n#ifndef CSR_BASE\n" r += f"#define CSR_BASE {hex(csr_base)}L\n" r += "#endif\n" for name, region in regions.items(): - origin = region.origin - csr_base + origin = region.origin - _csr_base r += "\n/* "+name+" */\n" r += f"#define CSR_{name.upper()}_BASE {_get_csr_addr(csr_base, origin, with_csr_base_define)}\n" if not isinstance(region.obj, Memory): From 79a82dc732477acb430cf86561427e29c4fe544d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 17 Jul 2023 11:27:07 +0200 Subject: [PATCH 106/454] tools/litex_json2dts_linux: Remove duplicated clock definition. Keep clock definition introduced by 9b67898e99b87283e3ca4b8425defed4cb5ddf09. --- litex/tools/litex_json2dts_linux.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/litex/tools/litex_json2dts_linux.py b/litex/tools/litex_json2dts_linux.py index 7d0f1ccc7..f64124199 100755 --- a/litex/tools/litex_json2dts_linux.py +++ b/litex/tools/litex_json2dts_linux.py @@ -246,18 +246,6 @@ def generate_dts(d, initrd_start=None, initrd_size=None, initrd=None, root_devic }; """ - # Clock ---------------------------------------------------------------------------------------- - - dts += """ - clocks {{ - sys_clk: litex_sys_clk {{ - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <{sys_clk_freq}>; - }}; - }}; -""".format(sys_clk_freq=d["constants"]["config_clock_frequency"]) - # Voltage Regulator for LiteSDCard (if applicable) -------------------------------------------- if "sdcore" in d["csr_bases"]: dts += """ From 6ab156e2253b3a832203d726fdb04f069894adf8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 17 Jul 2023 11:48:39 +0200 Subject: [PATCH 107/454] soc/cores: Fix regressions. --- litex/soc/cores/cpu/naxriscv/core.py | 8 ++++---- litex/soc/cores/spi/spi_slave.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 51725bbac..9c4308f9b 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -355,7 +355,7 @@ def add_soc_components(self, soc): self.jtag_reset = Signal() self.jtag_tdo = Signal() self.jtag_tdi = Signal() - + self.cpu_params.update( i_jtag_instruction_clk = self.jtag_clk, i_jtag_instruction_enable = self.jtag_enable, @@ -414,7 +414,7 @@ def add_soc_components(self, soc): o_peripheral_clint_rresp = clintbus.r.resp, ) soc.bus.add_slave("clint", clintbus, region=SoCRegion(origin=soc.mem_map.get("clint"), size=0x1_0000, cached=False)) - self.soc = soc # FIXME: Save SoC instance to retrieve the final mem layout on finalization. + self.soc_bus = soc.bus # FIXME: Save SoC Bus instance to retrieve the final mem layout on finalization. def add_memory_buses(self, address_width, data_width): nax_data_width = 64 @@ -493,9 +493,9 @@ def do_finalize(self): # p : peripheral # m : memory NaxRiscv.memory_regions = [] - for name, region in self.soc.bus.io_regions.items(): + for name, region in self.soc_bus.io_regions.items(): NaxRiscv.memory_regions.append( (region.origin, region.size, "io", "p") ) # IO is only allowed on the p bus - for name, region in self.soc.bus.regions.items(): + for name, region in self.soc_bus.regions.items(): if region.linker: # remove virtual regions continue if len(self.memory_buses) and name == 'main_ram': # m bus diff --git a/litex/soc/cores/spi/spi_slave.py b/litex/soc/cores/spi/spi_slave.py index 2b7c4564a..609877596 100644 --- a/litex/soc/cores/spi/spi_slave.py +++ b/litex/soc/cores/spi/spi_slave.py @@ -15,7 +15,7 @@ # SPI Slave ---------------------------------------------------------------------------------------- -class SPISlave(Module): +class SPISlave(LiteXModule): """4-wire SPI Slave Provides a simple and minimal hardware SPI Slave with CPOL=0, CPHA=0 and build time configurable From 69c6fa11d21ec8c2f4816905089d4cf46981e873 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 17 Jul 2023 17:08:35 +0200 Subject: [PATCH 108/454] build/lattice/common/lattice_ecp5_trellis_special_overrides: Add missing DifferentialOutput. --- litex/build/lattice/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/build/lattice/common.py b/litex/build/lattice/common.py index 68fdaf83b..3f3f78e63 100644 --- a/litex/build/lattice/common.py +++ b/litex/build/lattice/common.py @@ -178,6 +178,7 @@ def lower(dr): DDRInput: LatticeECP5DDRInput, DDROutput: LatticeECP5DDROutput, DifferentialInput: LatticeECP5DifferentialInput, + DifferentialOutput: LatticeECP5DifferentialOutput, } From f6da67fb38fb758679cb9292802b5a7f5115f1e7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 10:35:10 +0200 Subject: [PATCH 109/454] soc/add_pcie: Add optional data_width parameter. --- CHANGES.md | 1 + litex/soc/integration/soc.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2953cf799..7bdc601d6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -43,6 +43,7 @@ - liteeth/core/icmp : Added fifo_depth parameter on LiteEthICMPEcho. - gen/fhdl/verilog : Improved signal sort by name instead of duid to improve reproducibility. - litedram/frontend/dma : Added last generation on end of DMA for LiteDRAMDMAReader. + - litepcie/frontend/dma : Added optional integrated data-width converter and data_width parameters to simplify integration/user logic. [> Changed ---------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index ed7cd4b5c..f48665b39 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1970,7 +1970,7 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) self.sata_phy.crg.cd_sata_rx.clk) # Add PCIe ------------------------------------------------------------------------------------- - def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, address_width=32, + def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, address_width=32, data_width=None, with_dma_buffering = True, dma_buffering_depth=1024, with_dma_loopback = True, with_dma_synchronizer = False, @@ -2036,7 +2036,8 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre with_synchronizer = with_dma_synchronizer, with_monitor = with_dma_monitor, with_status = with_dma_status, - address_width = address_width + address_width = address_width, + data_width = data_width, ) self.add_module(name=f"{name}_dma{i}", module=dma) self.msis[f"{name.upper()}_DMA{i}_WRITER"] = dma.writer.irq From 6e78db6767a42ecd8c71ad02737686418f585893 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 15:15:44 +0200 Subject: [PATCH 110/454] soc/add_bus_master: Use name where possible to avoid automatic naming and improve log readability. --- litex/soc/integration/soc.py | 12 ++++++------ litex/tools/litex_sim.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index f48665b39..cef8ceefa 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1746,7 +1746,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, self.check_if_exists(name) etherbone = LiteEthEtherbone(ethcore.udp, udp_port, buffer_depth=buffer_depth, cd=etherbone_cd) self.add_module(name=name, module=etherbone) - self.bus.add_master(master=etherbone.wishbone.bus) + self.bus.add_master(name=name, master=etherbone.wishbone.bus) # Timing constraints if with_timing_constraints: @@ -1862,7 +1862,7 @@ def add_sdcard(self, name="sdcard", mode="read+write", use_emulator=False, softw self.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness) self.comb += self.sdcore.source.connect(self.sdblock2mem.sink) dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master("sdblock2mem", master=bus) + dma_bus.add_master(name="sdblock2mem", master=bus) # Mem2Block DMA. if "write" in mode: @@ -1870,7 +1870,7 @@ def add_sdcard(self, name="sdcard", mode="read+write", use_emulator=False, softw self.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness) self.comb += self.sdmem2block.source.connect(self.sdcore.sink) dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master("sdmem2block", master=bus) + dma_bus.add_master(name="sdmem2block", master=bus) # Interrupts. self.sdirq = EventManager() @@ -1935,7 +1935,7 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) bus = bus, endianness = self.cpu.endianness) dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master("sata_sector2mem", master=bus) + dma_bus.add_master(name="sata_sector2mem", master=bus) # Mem2Sector DMA. if "write" in mode: @@ -1945,7 +1945,7 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) port = self.sata_crossbar.get_port(), endianness = self.cpu.endianness) dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master("sata_mem2sector", master=bus) + dma_bus.add_master(name="sata_mem2sector", master=bus) # Interrupts. self.sata_irq = EventManager() @@ -2001,7 +2001,7 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre self.check_if_exists(f"{name}_mmap") mmap = LitePCIeWishboneMaster(self.pcie_endpoint, base_address=self.mem_map["csr"]) self.add_module(name=f"{name}_mmap", module=mmap) - self.bus.add_master(master=mmap.wishbone) + self.bus.add_master(name=f"{name}_mmap", master=mmap.wishbone) # MSI. if with_msi: diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index e7a950fb7..fabc0468d 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -255,7 +255,7 @@ def __init__(self, self.udp = LiteEthUDP(self.ip, etherbone_ip_address, dw=8) # Etherbone self.etherbone = LiteEthEtherbone(self.udp, 1234, mode="master") - self.bus.add_master(master=self.etherbone.wishbone.bus) + self.bus.add_master(name="etherbone", master=self.etherbone.wishbone.bus) # Ethernet --------------------------------------------------------------------------------- elif with_ethernet: From f995d74e5540f8639b29327a4fffec0f6cf50edb Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 15:36:18 +0200 Subject: [PATCH 111/454] soc/add_uartbone: Rename name parameter to uart_name to allow multiple uartbone (also for consistency with other cores) and other minor cleanups. --- CHANGES.md | 1 + litex/soc/integration/soc.py | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7bdc601d6..07ec80fae 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -48,6 +48,7 @@ [> Changed ---------- - litex/gen : Added local version of genlib.cdc/misc to better decouple with Migen and prepare Amaranth's compat use. + - soc/add_uartbone : Renamed name parameter to uart_name (for consistency with other cores). [> 2023.04, released on May 8th 2023 ------------------------------------ diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index cef8ceefa..fa306c302 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -966,7 +966,7 @@ def add_ram(self, name, origin, size, contents=[], mode="rwx"): bursting = self.bus.bursting ) ram = ram_cls(size, bus=ram_bus, init=contents, read_only=("w" not in mode), name=name) - self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode)) + self.bus.add_slave(name=name, slave=ram.bus, region=SoCRegion(origin=origin, size=size, mode=mode)) self.check_if_exists(name) self.logger.info("RAM {} {} {}.".format( colorer(name), @@ -997,7 +997,7 @@ def add_csr_bridge(self, name="csr", origin=None, register=False): "axi-lite": axi.AXILite2CSR, "axi" : axi.AXILite2CSR, # Note: CSR is a slow bus so using AXI-Lite is fine. }[self.bus.standard] - csr_bridge_name = name + "_bridge" + csr_bridge_name = f"{name}_bridge" self.check_if_exists(csr_bridge_name) csr_bridge = csr_bridge_cls( bus_csr = csr_bus.Interface( @@ -1127,7 +1127,7 @@ def add_cpu(self, name="vexriscv", variant="standard", reset_address=None, cfu=N bursting = self.bus.bursting ) dma_bus = wishbone.Interface(data_width=self.bus.data_width) - self.dma_bus.add_slave("dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only + self.dma_bus.add_slave(name="dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus) # Connect SoCController's reset to CPU reset. @@ -1430,17 +1430,19 @@ def add_uart(self, name="uart", uart_name="serial", baudrate=115200, fifo_depth= self.add_constant("UART_POLLING") # Add UARTbone --------------------------------------------------------------------------------- - def add_uartbone(self, name="serial", clk_freq=None, baudrate=115200, cd="sys"): + def add_uartbone(self, name="uartbone", uart_name="serial", clk_freq=None, baudrate=115200, cd="sys"): # Imports. from litex.soc.cores import uart # Core. if clk_freq is None: clk_freq = self.sys_clk_freq - self.check_if_exists("uartbone") - self.uartbone_phy = uart.UARTPHY(self.platform.request(name), clk_freq, baudrate) - self.uartbone = uart.UARTBone(phy=self.uartbone_phy, clk_freq=clk_freq, cd=cd) - self.bus.add_master(name="uartbone", master=self.uartbone.wishbone) + self.check_if_exists(name) + uartbone_phy = uart.UARTPHY(self.platform.request(uart_name), clk_freq, baudrate) + uartbone = uart.UARTBone(phy=uartbone_phy, clk_freq=clk_freq, cd=cd) + self.add_module(name=f"{name}_phy", module=uartbone_phy) + self.add_module(name=name, module=uartbone) + self.bus.add_master(name=name, master=uartbone.wishbone) # Add JTAGbone --------------------------------------------------------------------------------- def add_jtagbone(self, name="jtagbone", chain=1): @@ -1612,7 +1614,7 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, # Create Wishbone Slave. wb_sdram = wishbone.Interface(data_width=self.bus.data_width) - self.bus.add_slave("main_ram", wb_sdram) + self.bus.add_slave(name="main_ram", slave=wb_sdram) # L2 Cache if l2_cache_size != 0: @@ -1771,13 +1773,13 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, # PHY. spiflash_phy = phy if spiflash_phy is None: - self.check_if_exists(name + "_phy") + self.check_if_exists(f"{name}_phy") spiflash_pads = self.platform.request(name if mode == "1x" else name + mode) spiflash_phy = LiteSPIPHY(spiflash_pads, module, device=self.platform.device, default_divisor=int(self.sys_clk_freq/clk_freq), rate=rate) self.add_module(name=f"{name}_phy", module=spiflash_phy) # Core. - self.check_if_exists(name + "_mmap") + self.check_if_exists(f"{name}_mmap") spiflash_core = LiteSPI(spiflash_phy, mmap_endianness=self.cpu.endianness, **kwargs) self.add_module(name=f"{name}_core", module=spiflash_core) spiflash_region = SoCRegion(origin=self.mem_map.get(name, None), size=module.total_size) From e364316814b90366c050da45211f36a6142b9a83 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 15:58:48 +0200 Subject: [PATCH 112/454] soc/add_sata: Use name parameter to allow multiple sata instances. --- litex/soc/integration/soc.py | 60 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index fa306c302..d1a4e629c 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1917,59 +1917,69 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) assert self.clk_freq >= sata_clk_freq/2 # FIXME: /2 for 16-bit data-width, add support for 32-bit. # Core. - self.check_if_exists("sata_core") - self.sata_core = LiteSATACore(phy) + self.check_if_exists(f"{name}_core") + sata_core = LiteSATACore(phy) + self.add_module(name=f"{name}_core", module=sata_core) # Crossbar. - self.check_if_exists("sata_crossbar") - self.sata_crossbar = LiteSATACrossbar(self.sata_core) + self.check_if_exists(f"{name}_crossbar") + sata_crossbar = LiteSATACrossbar(sata_core) + self.add_module(name=f"{name}_crossbar", module=sata_crossbar) # Identify. if with_identify: - sata_identify = LiteSATAIdentify(self.sata_crossbar.get_port()) - self.sata_identify = LiteSATAIdentifyCSR(sata_identify) + self.check_if_exists(f"{name}_identify") + _sata_identify = LiteSATAIdentify(sata_crossbar.get_port()) + sata_identify = LiteSATAIdentifyCSR(_sata_identify) + self.add_module(name=f"{name}_identify", module=sata_identify) # Sector2Mem DMA. if "read" in mode: + self.check_if_exists(f"{name}_sector2mem") bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) - self.sata_sector2mem = LiteSATASector2MemDMA( - port = self.sata_crossbar.get_port(), + sata_sector2mem = LiteSATASector2MemDMA( + port = sata_crossbar.get_port(), bus = bus, endianness = self.cpu.endianness) - dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master(name="sata_sector2mem", master=bus) + self.add_module(name=f"{name}_sector2mem", module=sata_sector2mem) + dma_bus = getattr(self, "dma_bus", self.bus) + dma_bus.add_master(name=f"{name}_sector2mem", master=bus) # Mem2Sector DMA. if "write" in mode: + self.check_if_exists(f"{name}_mem2sector") bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) - self.sata_mem2sector = LiteSATAMem2SectorDMA( + sata_mem2sector = LiteSATAMem2SectorDMA( bus = bus, - port = self.sata_crossbar.get_port(), + port = sata_crossbar.get_port(), endianness = self.cpu.endianness) - dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master(name="sata_mem2sector", master=bus) + self.add_module(name=f"{name}_mem2sector", module=sata_mem2sector) + dma_bus = getattr(self, "dma_bus", self.bus) + dma_bus.add_master(name=f"{name}_mem2sector", master=bus) # Interrupts. - self.sata_irq = EventManager() + sata_irq = EventManager() + self.add_module(name=f"{name}_irq", module=sata_irq) if "read" in mode: - self.sata_irq.sector2mem_dma = EventSourcePulse(description="Sector2Mem DMA terminated.") + sata_irq.sector2mem_dma = EventSourcePulse(description="Sector2Mem DMA terminated.") if "write" in mode: - self.sata_irq.mem2sector_dma = EventSourcePulse(description="Mem2Sector DMA terminated.") - self.sata_irq.finalize() + sata_irq.mem2sector_dma = EventSourcePulse(description="Mem2Sector DMA terminated.") + sata_irq.finalize() if "read" in mode: - self.comb += self.sata_irq.sector2mem_dma.trigger.eq(self.sata_sector2mem.irq) + self.comb += sata_irq.sector2mem_dma.trigger.eq(sata_sector2mem.irq) if "write" in mode: - self.comb += self.sata_irq.mem2sector_dma.trigger.eq(self.sata_mem2sector.irq) + self.comb += sata_irq.mem2sector_dma.trigger.eq(sata_mem2sector.irq) if self.irq.enabled: - self.irq.add("sata_irq", use_loc_if_exists=True) + self.irq.add(f"{name}_irq", use_loc_if_exists=True) # Timing constraints. - self.platform.add_period_constraint(self.sata_phy.crg.cd_sata_tx.clk, 1e9/sata_clk_freq) - self.platform.add_period_constraint(self.sata_phy.crg.cd_sata_rx.clk, 1e9/sata_clk_freq) + self.platform.add_period_constraint(phy.crg.cd_sata_tx.clk, 1e9/sata_clk_freq) + self.platform.add_period_constraint(phy.crg.cd_sata_rx.clk, 1e9/sata_clk_freq) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, - self.sata_phy.crg.cd_sata_tx.clk, - self.sata_phy.crg.cd_sata_rx.clk) + phy.crg.cd_sata_tx.clk, + phy.crg.cd_sata_rx.clk, + ) # Add PCIe ------------------------------------------------------------------------------------- def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, address_width=32, data_width=None, From 0152e7de8e7d3c35a345d8823f0943bd5a76734c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 16:28:22 +0200 Subject: [PATCH 113/454] soc/add_sata: Use name parameter to allow multiple sdcard instances. --- litex/soc/integration/soc.py | 61 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index d1a4e629c..fe7f62020 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1834,7 +1834,7 @@ def add_spi_sdcard(self, name="spisdcard", spi_clk_freq=400e3, with_tristate=Fal self.add_constant("SPISDCARD_DEBUG") # Add SDCard ----------------------------------------------------------------------------------- - def add_sdcard(self, name="sdcard", mode="read+write", use_emulator=False, software_debug=False): + def add_sdcard(self, name="sdcard", sdcard_name="sdcard", mode="read+write", use_emulator=False, software_debug=False): # Imports. from litesdcard.emulator import SDEmulator from litesdcard.phy import SDPHY @@ -1850,53 +1850,61 @@ def add_sdcard(self, name="sdcard", mode="read+write", use_emulator=False, softw self.submodules += sdemulator sdcard_pads = sdemulator.pads else: - sdcard_pads = self.platform.request(name) + sdcard_pads = self.platform.request(sdcard_name) # Core. - self.check_if_exists("sdphy") - self.check_if_exists("sdcore") - self.sdphy = SDPHY(sdcard_pads, self.platform.device, self.clk_freq, cmd_timeout=10e-1, data_timeout=10e-1) - self.sdcore = SDCore(self.sdphy) + self.check_if_exists(f"{name}_phy") + self.check_if_exists(f"{name}_core") + sdcard_phy = SDPHY(sdcard_pads, self.platform.device, self.clk_freq, cmd_timeout=10e-1, data_timeout=10e-1) + sdcard_core = SDCore(sdcard_phy) + self.add_module(name=f"{name}_phy", module=sdcard_phy) + self.add_module(name=f"{name}_core", module=sdcard_core) # Block2Mem DMA. if "read" in mode: + self.check_if_exists(f"{name}_block2mem") bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) - self.sdblock2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness) - self.comb += self.sdcore.source.connect(self.sdblock2mem.sink) - dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master(name="sdblock2mem", master=bus) + sdcard_block2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness) + self.add_module(name=f"{name}_block2mem", module=sdcard_block2mem) + self.comb += sdcard_core.source.connect(sdcard_block2mem.sink) + dma_bus = getattr(self, "dma_bus", self.bus) + dma_bus.add_master(name=f"{name}_block2mem", master=bus) # Mem2Block DMA. if "write" in mode: + self.check_if_exists(f"{name}_mem2block") bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) - self.sdmem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness) - self.comb += self.sdmem2block.source.connect(self.sdcore.sink) - dma_bus = self.bus if not hasattr(self, "dma_bus") else self.dma_bus - dma_bus.add_master(name="sdmem2block", master=bus) + sdcard_mem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness) + self.add_module(name=f"{name}_mem2block", module=sdcard_mem2block) + self.comb += sdcard_mem2block.source.connect(sdcard_core.sink) + dma_bus = getattr(self, "dma_bus", self.bus) + dma_bus.add_master(name=f"{name}_mem2block", master=bus) # Interrupts. - self.sdirq = EventManager() - self.sdirq.card_detect = EventSourcePulse(description="SDCard has been ejected/inserted.") + self.check_if_exists(f"{name}_irq") + sdcard_irq = EventManager() + self.add_module(name=f"{name}_irq", module=sdcard_irq) + sdcard_irq.card_detect = EventSourcePulse(description="SDCard has been ejected/inserted.") if "read" in mode: - self.sdirq.block2mem_dma = EventSourcePulse(description="Block2Mem DMA terminated.") + sdcard_irq.block2mem_dma = EventSourcePulse(description="Block2Mem DMA terminated.") if "write" in mode: - self.sdirq.mem2block_dma = EventSourcePulse(description="Mem2Block DMA terminated.") - self.sdirq.cmd_done = EventSourceLevel(description="Command completed.") - self.sdirq.finalize() + sdcard_irq.mem2block_dma = EventSourcePulse(description="Mem2Block DMA terminated.") + sdcard_irq.cmd_done = EventSourceLevel(description="Command completed.") + sdcard_irq.finalize() if "read" in mode: - self.comb += self.sdirq.block2mem_dma.trigger.eq(self.sdblock2mem.irq) + self.comb += sdcard_irq.block2mem_dma.trigger.eq(sdcard_block2mem.irq) if "write" in mode: - self.comb += self.sdirq.mem2block_dma.trigger.eq(self.sdmem2block.irq) + self.comb += sdcard_irq.mem2block_dma.trigger.eq(sdcard_mem2block.irq) self.comb += [ - self.sdirq.card_detect.trigger.eq(self.sdphy.card_detect_irq), - self.sdirq.cmd_done.trigger.eq(self.sdcore.cmd_event.fields.done) + sdcard_irq.card_detect.trigger.eq(sdcard_phy.card_detect_irq), + sdcard_irq.cmd_done.trigger.eq(sdcard_core.cmd_event.fields.done) ] if self.irq.enabled: - self.irq.add("sdirq", use_loc_if_exists=True) + self.irq.add(f"{name}_irq", use_loc_if_exists=True) # Debug. if software_debug: - self.add_constant("SDCARD_DEBUG") + self.add_constant(f"{name}_DEBUG") # Add SATA ------------------------------------------------------------------------------------- def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True): @@ -1958,6 +1966,7 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) dma_bus.add_master(name=f"{name}_mem2sector", master=bus) # Interrupts. + self.check_if_exists(f"{name}_irq") sata_irq = EventManager() self.add_module(name=f"{name}_irq", module=sata_irq) if "read" in mode: From 6693a723d10eaf009c1e4a174a0932b698d4724a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 16:28:51 +0200 Subject: [PATCH 114/454] software: Update to new sdcard core name. --- litex/soc/software/bios/cmds/cmd_litesdcard.c | 12 +-- litex/soc/software/liblitesdcard/sdcard.c | 76 +++++++++---------- litex/soc/software/liblitesdcard/sdcard.h | 2 +- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/litex/soc/software/bios/cmds/cmd_litesdcard.c b/litex/soc/software/bios/cmds/cmd_litesdcard.c index a206c7c52..f5a0ccf3e 100644 --- a/litex/soc/software/bios/cmds/cmd_litesdcard.c +++ b/litex/soc/software/bios/cmds/cmd_litesdcard.c @@ -16,10 +16,10 @@ * Detect SDcard * */ -#ifdef CSR_SDPHY_BASE +#ifdef CSR_SDCARD_PHY_BASE static void sdcard_detect_handler(int nb_params, char **params) { - uint8_t cd = sdphy_card_detect_read(); + uint8_t cd = sdcard_phy_card_detect_read(); printf("SDCard %sinserted.\n", cd ? "not " : ""); } @@ -32,7 +32,7 @@ define_command(sdcard_detect, sdcard_detect_handler, "Detect SDCard", LITESDCARD * Initialize SDcard * */ -#ifdef CSR_SDCORE_BASE +#ifdef CSR_SDCARD_CORE_BASE static void sdcard_init_handler(int nb_params, char **params) { printf("Initialize SDCard... "); @@ -51,7 +51,7 @@ define_command(sdcard_init, sdcard_init_handler, "Initialize SDCard", LITESDCARD * Set SDcard clock frequency * */ -#ifdef CSR_SDCORE_BASE +#ifdef CSR_SDCARD_CORE_BASE static void sdcard_freq_handler(int nb_params, char **params) { unsigned int freq; @@ -79,7 +79,7 @@ define_command(sdcard_freq, sdcard_freq_handler, "Set SDCard clock freq", LITESD * Perform SDcard block read * */ -#ifdef CSR_SDBLOCK2MEM_BASE +#ifdef CSR_SDCARD_BLOCK2MEM_BASE static void sdcard_read_handler(int nb_params, char **params) { unsigned int block; @@ -110,7 +110,7 @@ define_command(sdcard_read, sdcard_read_handler, "Read SDCard block", LITESDCARD * Perform SDcard block write * */ -#ifdef CSR_SDMEM2BLOCK_BASE +#ifdef CSR_SDCARD_MEM2BLOCK_BASE static void sdcard_write_handler(int nb_params, char **params) { int i; diff --git a/litex/soc/software/liblitesdcard/sdcard.c b/litex/soc/software/liblitesdcard/sdcard.c index 6557d3a63..a76aad853 100644 --- a/litex/soc/software/liblitesdcard/sdcard.c +++ b/litex/soc/software/liblitesdcard/sdcard.c @@ -18,7 +18,7 @@ #include #include "sdcard.h" -#ifdef CSR_SDCORE_BASE +#ifdef CSR_SDCARD_CORE_BASE //#define SDCARD_DEBUG //#define SDCARD_CMD23_SUPPORT /* SET_BLOCK_COUNT */ @@ -44,14 +44,14 @@ int sdcard_wait_cmd_done(void) { printf("cmdevt: wait for event & 0x1\n"); #endif for (;;) { - event = sdcore_cmd_event_read(); + event = sdcard_core_cmd_event_read(); busy_wait_us(10); if (event & 0x1) break; } #ifdef SDCARD_DEBUG printf("cmdevt: %08x\n", event); - csr_rd_buf_uint32(CSR_SDCORE_CMD_RESPONSE_ADDR, + csr_rd_buf_uint32(CSR_SDCARD_CORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); printf("%08x %08x %08x %08x\n", r[0], r[1], r[2], r[3]); #endif @@ -68,7 +68,7 @@ int sdcard_wait_data_done(void) { printf("dataevt: wait for event & 0x1\n"); #endif for (;;) { - event = sdcore_data_event_read(); + event = sdcard_core_data_event_read(); if (event & 0x1) break; busy_wait_us(10); @@ -116,7 +116,7 @@ void sdcard_set_clk_freq(unsigned long clk_freq, int show) { else printf("%ld KHz\n", clk_freq/1000); } - sdphy_clocker_divider_write(divider); + sdcard_phy_clocker_divider_write(divider); } /*-----------------------------------------------------------------------*/ @@ -124,9 +124,9 @@ void sdcard_set_clk_freq(unsigned long clk_freq, int show) { /*-----------------------------------------------------------------------*/ static inline int sdcard_send_command(uint32_t arg, uint8_t cmd, uint8_t rsp) { - sdcore_cmd_argument_write(arg); - sdcore_cmd_command_write((cmd << 8) | rsp); - sdcore_cmd_send_write(1); + sdcard_core_cmd_argument_write(arg); + sdcard_core_cmd_command_write((cmd << 8) | rsp); + sdcard_core_cmd_send_write(1); return sdcard_wait_cmd_done(); } @@ -212,8 +212,8 @@ int sdcard_switch(unsigned int mode, unsigned int group, unsigned int value) { #ifdef SDCARD_DEBUG printf("CMD6: SWITCH_FUNC\n"); #endif - sdcore_block_length_write(64); - sdcore_block_count_write(1); + sdcard_core_block_length_write(64); + sdcard_core_block_count_write(1); while (sdcard_send_command(arg, 6, (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); @@ -224,8 +224,8 @@ int sdcard_app_send_scr(void) { #ifdef SDCARD_DEBUG printf("CMD51: APP_SEND_SCR\n"); #endif - sdcore_block_length_write(8); - sdcore_block_count_write(1); + sdcard_core_block_length_write(8); + sdcard_core_block_count_write(1); while (sdcard_send_command(0, 51, (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); @@ -243,8 +243,8 @@ int sdcard_write_single_block(unsigned int blockaddr) { #ifdef SDCARD_DEBUG printf("CMD24: WRITE_SINGLE_BLOCK\n"); #endif - sdcore_block_length_write(512); - sdcore_block_count_write(1); + sdcard_core_block_length_write(512); + sdcard_core_block_count_write(1); while (sdcard_send_command(blockaddr, 24, (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5) | SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); @@ -255,8 +255,8 @@ int sdcard_write_multiple_block(unsigned int blockaddr, unsigned int blockcnt) { #ifdef SDCARD_DEBUG printf("CMD25: WRITE_MULTIPLE_BLOCK\n"); #endif - sdcore_block_length_write(512); - sdcore_block_count_write(blockcnt); + sdcard_core_block_length_write(512); + sdcard_core_block_count_write(blockcnt); while (sdcard_send_command(blockaddr, 25, (SDCARD_CTRL_DATA_TRANSFER_WRITE << 5) | SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); @@ -267,8 +267,8 @@ int sdcard_read_single_block(unsigned int blockaddr) { #ifdef SDCARD_DEBUG printf("CMD17: READ_SINGLE_BLOCK\n"); #endif - sdcore_block_length_write(512); - sdcore_block_count_write(1); + sdcard_core_block_length_write(512); + sdcard_core_block_count_write(1); while (sdcard_send_command(blockaddr, 17, (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); @@ -279,8 +279,8 @@ int sdcard_read_multiple_block(unsigned int blockaddr, unsigned int blockcnt) { #ifdef SDCARD_DEBUG printf("CMD18: READ_MULTIPLE_BLOCK\n"); #endif - sdcore_block_length_write(512); - sdcore_block_count_write(blockcnt); + sdcard_core_block_length_write(512); + sdcard_core_block_count_write(blockcnt); while (sdcard_send_command(blockaddr, 18, (SDCARD_CTRL_DATA_TRANSFER_READ << 5) | SDCARD_CTRL_RESPONSE_SHORT) != SD_OK); @@ -310,7 +310,7 @@ int sdcard_set_block_count(unsigned int blockcnt) { uint16_t sdcard_decode_rca(void) { uint32_t r[SD_CMD_RESPONSE_SIZE/4]; - csr_rd_buf_uint32(CSR_SDCORE_CMD_RESPONSE_ADDR, + csr_rd_buf_uint32(CSR_SDCARD_CORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); return (r[3] >> 16) & 0xffff; } @@ -318,7 +318,7 @@ uint16_t sdcard_decode_rca(void) { #ifdef SDCARD_DEBUG void sdcard_decode_cid(void) { uint32_t r[SD_CMD_RESPONSE_SIZE/4]; - csr_rd_buf_uint32(CSR_SDCORE_CMD_RESPONSE_ADDR, + csr_rd_buf_uint32(CSR_SDCARD_CORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); printf( "CID Register: 0x%08x%08x%08x%08x\n" @@ -351,7 +351,7 @@ void sdcard_decode_cid(void) { void sdcard_decode_csd(void) { uint32_t r[SD_CMD_RESPONSE_SIZE/4]; - csr_rd_buf_uint32(CSR_SDCORE_CMD_RESPONSE_ADDR, + csr_rd_buf_uint32(CSR_SDCARD_CORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); /* FIXME: only support CSR structure version 2.0 */ printf( @@ -385,7 +385,7 @@ int sdcard_init(void) { for (timeout=1000; timeout>0; timeout--) { /* Set SDCard in SPI Mode (generate 80 dummy clocks) */ - sdphy_init_initialize_write(1); + sdcard_phy_init_initialize_write(1); busy_wait(1); /* Set SDCard in Idle state */ @@ -408,7 +408,7 @@ int sdcard_init(void) { for (timeout=1000; timeout>0; timeout--) { sdcard_app_cmd(0); if (sdcard_app_send_op_cond(1) == SD_OK) { - csr_rd_buf_uint32(CSR_SDCORE_CMD_RESPONSE_ADDR, + csr_rd_buf_uint32(CSR_SDCARD_CORE_CMD_RESPONSE_ADDR, r, SD_CMD_RESPONSE_SIZE/4); if (r[3] & 0x80000000) /* Busy bit, set when init is complete */ @@ -472,7 +472,7 @@ int sdcard_init(void) { return 1; } -#ifdef CSR_SDBLOCK2MEM_BASE +#ifdef CSR_SDCARD_BLOCK2MEM_BASE void sdcard_read(uint32_t block, uint32_t count, uint8_t* buf) { @@ -484,10 +484,10 @@ void sdcard_read(uint32_t block, uint32_t count, uint8_t* buf) nblocks = 1; #endif /* Initialize DMA Writer */ - sdblock2mem_dma_enable_write(0); - sdblock2mem_dma_base_write((uint64_t)(uintptr_t) buf); - sdblock2mem_dma_length_write(512*nblocks); - sdblock2mem_dma_enable_write(1); + sdcard_block2mem_dma_enable_write(0); + sdcard_block2mem_dma_base_write((uint64_t)(uintptr_t) buf); + sdcard_block2mem_dma_length_write(512*nblocks); + sdcard_block2mem_dma_enable_write(1); /* Read Block(s) from SDCard */ #ifdef SDCARD_CMD23_SUPPORT @@ -499,7 +499,7 @@ void sdcard_read(uint32_t block, uint32_t count, uint8_t* buf) sdcard_read_single_block(block); /* Wait for DMA Writer to complete */ - while ((sdblock2mem_dma_done_read() & 0x1) == 0); + while ((sdcard_block2mem_dma_done_read() & 0x1) == 0); /* Stop transmission (Only for multiple block reads) */ if (nblocks > 1) @@ -520,7 +520,7 @@ void sdcard_read(uint32_t block, uint32_t count, uint8_t* buf) #endif -#ifdef CSR_SDMEM2BLOCK_BASE +#ifdef CSR_SDCARD_MEM2BLOCK_BASE void sdcard_write(uint32_t block, uint32_t count, uint8_t* buf) { @@ -532,10 +532,10 @@ void sdcard_write(uint32_t block, uint32_t count, uint8_t* buf) nblocks = 1; #endif /* Initialize DMA Reader */ - sdmem2block_dma_enable_write(0); - sdmem2block_dma_base_write((uint64_t)(uintptr_t) buf); - sdmem2block_dma_length_write(512*nblocks); - sdmem2block_dma_enable_write(1); + sdcard_mem2block_dma_enable_write(0); + sdcard_mem2block_dma_base_write((uint64_t)(uintptr_t) buf); + sdcard_mem2block_dma_length_write(512*nblocks); + sdcard_mem2block_dma_enable_write(1); /* Write Block(s) to SDCard */ #ifdef SDCARD_CMD23_SUPPORT @@ -551,7 +551,7 @@ void sdcard_write(uint32_t block, uint32_t count, uint8_t* buf) sdcard_stop_transmission(); /* Wait for DMA Reader to complete */ - while ((sdmem2block_dma_done_read() & 0x1) == 0); + while ((sdcard_mem2block_dma_done_read() & 0x1) == 0); /* Update Block/Buffer/Count */ block += nblocks; @@ -594,4 +594,4 @@ void fatfs_set_ops_sdcard(void) { FfDiskOps = &SdCardDiskOps; } -#endif /* CSR_SDCORE_BASE */ +#endif /* CSR_SDCARD_CORE_BASE */ diff --git a/litex/soc/software/liblitesdcard/sdcard.h b/litex/soc/software/liblitesdcard/sdcard.h index d8aa74b9b..8a132fcda 100644 --- a/litex/soc/software/liblitesdcard/sdcard.h +++ b/litex/soc/software/liblitesdcard/sdcard.h @@ -14,7 +14,7 @@ extern "C" { #define CLKGEN_STATUS_PROGDONE 0x2 #define CLKGEN_STATUS_LOCKED 0x4 -#ifdef CSR_SDCORE_BASE +#ifdef CSR_SDCARD_CORE_BASE #define SD_CMD_RESPONSE_SIZE 16 From c00f61d9d777a134e7f7cb1585582d7de69e00f8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 16:29:05 +0200 Subject: [PATCH 115/454] tools: Update to new sdcard core name. --- litex/tools/litex_json2dts_linux.py | 26 +++++++++++++------------- litex/tools/litex_json2dts_zephyr.py | 20 ++++++++++---------- litex/tools/litex_json2renode.py | 14 +++++++------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/litex/tools/litex_json2dts_linux.py b/litex/tools/litex_json2dts_linux.py index f64124199..bef068663 100755 --- a/litex/tools/litex_json2dts_linux.py +++ b/litex/tools/litex_json2dts_linux.py @@ -423,26 +423,26 @@ def generate_dts(d, initrd_start=None, initrd_size=None, initrd=None, root_devic dts += """ mmc0: mmc@{mmc_csr_base:x} {{ compatible = "litex,mmc"; - reg = <0x{sdphy_csr_base:x} 0x100>, - <0x{sdcore_csr_base:x} 0x100>, - <0x{sdblock2mem:x} 0x100>, - <0x{sdmem2block:x} 0x100>, - <0x{sdirq:x} 0x100>; + reg = <0x{sdcard_phy_csr_base:x} 0x100>, + <0x{sdcard_core_csr_base:x} 0x100>, + <0x{sdcard_block2mem:x} 0x100>, + <0x{sdcard_mem2block:x} 0x100>, + <0x{sdcard_irq:x} 0x100>; reg-names = "phy", "core", "reader", "writer", "irq"; clocks = <&sys_clk>; vmmc-supply = <&vreg_mmc>; bus-width = <0x04>; - {sdirq_interrupt} + {sdcard_irq_interrupt} status = "okay"; }}; """.format( - mmc_csr_base = d["csr_bases"]["sdphy"], - sdphy_csr_base = d["csr_bases"]["sdphy"], - sdcore_csr_base = d["csr_bases"]["sdcore"], - sdblock2mem = d["csr_bases"]["sdblock2mem"], - sdmem2block = d["csr_bases"]["sdmem2block"], - sdirq = d["csr_bases"]["sdirq"], - sdirq_interrupt = "" if polling else "interrupts = <{}>;".format(d["constants"]["sdirq_interrupt"]) + mmc_csr_base = d["csr_bases"]["sdcard_phy"], + sdcard_phy_csr_base = d["csr_bases"]["sdcard_phy"], + sdcard_core_csr_base = d["csr_bases"]["sdcard_core"], + sdcard_block2mem = d["csr_bases"]["sdcard_block2mem"], + sdcard_mem2block = d["csr_bases"]["sdcard_mem2block"], + sdcard_irq = d["csr_bases"]["sdcard_irq"], + sdcard_irq_interrupt = "" if polling else "interrupts = <{}>;".format(d["constants"]["sdcard_irq_interrupt"]) ) # Leds ----------------------------------------------------------------------------------------- diff --git a/litex/tools/litex_json2dts_zephyr.py b/litex/tools/litex_json2dts_zephyr.py index a064a3d45..485fe9aef 100755 --- a/litex/tools/litex_json2dts_zephyr.py +++ b/litex/tools/litex_json2dts_zephyr.py @@ -212,33 +212,33 @@ def peripheral_handler(name, parm, csr): 'alias': 'spi0', 'config_entry': 'SPI_LITESPI' }, - 'sdblock2mem': { + 'sdcard_block2mem': { 'handler': peripheral_handler, - 'alias': 'sdblock2mem', + 'alias': 'sdcard_block2mem', 'size': 0x18, 'config_entry': 'SD_LITESD' }, - 'sdcore': { + 'sdcard_core': { 'handler': peripheral_handler, - 'alias': 'sdcore', + 'alias': 'sdcard_core', 'size': 0x2C, 'config_entry': 'SD_LITESD' }, - 'sdirq': { + 'sdcard_irq': { 'handler': peripheral_handler, - 'alias': 'sdirq', + 'alias': 'sdcard_irq', 'size': 0x0C, 'config_entry': 'SD_LITESD' }, - 'sdmem2block': { + 'sdcard_mem2block': { 'handler': peripheral_handler, - 'alias': 'sdmem2block', + 'alias': 'sdcard_mem2block', 'size': 0x18, 'config_entry': 'SD_LITESD' }, - 'sdphy': { + 'sdcard_phy': { 'handler': peripheral_handler, - 'alias': 'sdphy', + 'alias': 'sdcard_phy', 'size': 0x10, 'config_entry': 'SD_LITESD' }, diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 08a5440b5..21f2e2582 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -420,9 +420,9 @@ def generate_mmc(csr, name, **kwargs): # FIXME: Get litex to generate CSR region size into output information # currently only a base address is present peripheral = get_descriptor(csr, name) - core = get_descriptor(csr, 'sdcore', 0x100) - reader = get_descriptor(csr, 'sdblock2mem', 0x100) - writer = get_descriptor(csr, 'sdmem2block', 0x100) + core = get_descriptor(csr, 'sdcard_core', 0x100) + reader = get_descriptor(csr, 'sdcard_block2mem', 0x100) + writer = get_descriptor(csr, 'sdcard_mem2block', 0x100) result = """ mmc_controller: SD.LiteSDCard{} @ {{ @@ -645,7 +645,7 @@ def handled_peripheral(csr, name, **kwargs): 'handler': generate_peripheral, 'model': 'I2C.LiteX_I2C' }, - 'sdphy': { + 'sdcard_phy': { 'handler': generate_mmc, }, 'spisdcard': { @@ -675,13 +675,13 @@ def handled_peripheral(csr, name, **kwargs): 'handler': handled_peripheral # by generate_ethmac }, # handled by generate_mmc - 'sdblock2mem': { + 'sdcard_block2mem': { 'handler': handled_peripheral }, - 'sdmem2block': { + 'sdcard_mem2block': { 'handler': handled_peripheral }, - 'sdcore': { + 'sdcard_core': { 'handler': handled_peripheral }, } From aae15737cdd5596c831e1956823f7768820a11db Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 20 Jul 2023 16:30:48 +0200 Subject: [PATCH 116/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 07ec80fae..5c12793eb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -44,6 +44,7 @@ - gen/fhdl/verilog : Improved signal sort by name instead of duid to improve reproducibility. - litedram/frontend/dma : Added last generation on end of DMA for LiteDRAMDMAReader. - litepcie/frontend/dma : Added optional integrated data-width converter and data_width parameters to simplify integration/user logic. + - soc/add_uartbone/sata/sdcard : Added support for multiple instances in gateware as for the other cores. [> Changed ---------- From 330d61d2bdb58a2e3f8a079b00aa4b05b461d313 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 21 Jul 2023 14:50:38 +0200 Subject: [PATCH 117/454] soc/add_pcie: Remove MSI workaround on Ultrascale(+) now that root cause is understood/fixed (thanks @smunaut). --- CHANGES.md | 1 + litex/soc/integration/soc.py | 10 +--------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5c12793eb..3df19a536 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ - liteiclink/serwb : Fixed 7-Series initialization corner cases. - liteeth/core/icmp : Fixed length check on LiteEthICMPEcho before passing data to buffer. - LiteXModule/CSR : Fixed CSR collection order causing CSR clock domain to be changed. + - litepcie/US(P) : Fixed root cause of possible MSI deadlock. [> Added -------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index fe7f62020..60b95fa30 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -2035,16 +2035,8 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre if msi_type == "msi-x": msi = LitePCIeMSIX(endpoint=self.pcie_endpoint, width=msi_width) self.add_module(name=f"{name}_msi", module=msi) - # FIXME: On Ultrascale/Ultrascale+ limit rate of IRQs to 1MHz (to prevent issue with - # IRQs stalled). if msi_type in ["msi", "msi-multi-vector"]: - if isinstance(phy, (USPCIEPHY, USPPCIEPHY)): - msi_timer = WaitTimer(int(self.sys_clk_freq/1e6)) - self.add_module(name=f"{name}_msi_timer", module=msi_timer) - self.comb += msi_timer.wait.eq(~msi_timer.done) - self.comb += If(msi_timer.done, msi.source.connect(phy.msi)) - else: - self.comb += msi.source.connect(phy.msi) + self.comb += msi.source.connect(phy.msi) self.msis = {} # DMAs. From 35cd744adc2c3dda44bf9cff42d220b95b46cdfc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 21 Jul 2023 15:16:42 +0200 Subject: [PATCH 118/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 3df19a536..ee72b1eaf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -46,6 +46,7 @@ - litedram/frontend/dma : Added last generation on end of DMA for LiteDRAMDMAReader. - litepcie/frontend/dma : Added optional integrated data-width converter and data_width parameters to simplify integration/user logic. - soc/add_uartbone/sata/sdcard : Added support for multiple instances in gateware as for the other cores. + - liteeth_gen : Added raw UDP port support. [> Changed ---------- From 0f1fdea893921ff5bb3e73bd503bbe80fdfbf9ee Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 21 Jul 2023 19:53:10 +0200 Subject: [PATCH 119/454] build/xilinx/vivado: Also generate design checkpoint after synthesis and placement. This help exploring/constraining complex designs by using Vivado GUI and design checkpoint. --- CHANGES.md | 1 + litex/build/xilinx/vivado.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index ee72b1eaf..74346a571 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -47,6 +47,7 @@ - litepcie/frontend/dma : Added optional integrated data-width converter and data_width parameters to simplify integration/user logic. - soc/add_uartbone/sata/sdcard : Added support for multiple instances in gateware as for the other cores. - liteeth_gen : Added raw UDP port support. + - build/vivado : Added .dcp generation also after synthesis and placement. [> Changed ---------- diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 073dacd31..9b51b65ad 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -298,6 +298,7 @@ def build_project(self): tcl.append(f"report_timing_summary -file {self._build_name}_timing_synth.rpt") tcl.append(f"report_utilization -hierarchical -file {self._build_name}_utilization_hierarchical_synth.rpt") tcl.append(f"report_utilization -file {self._build_name}_utilization_synth.rpt") + tcl.append(f"write_checkpoint -force {self._build_name}_synth.dcp") # Optimize tcl.append("\n# Optimize design\n") @@ -323,6 +324,7 @@ def build_project(self): tcl.append(f"report_io -file {self._build_name}_io.rpt") tcl.append(f"report_control_sets -verbose -file {self._build_name}_control_sets.rpt") tcl.append(f"report_clock_utilization -file {self._build_name}_clock_utilization.rpt") + tcl.append(f"write_checkpoint -force {self._build_name}_place.dcp") # Add pre-routing commands tcl.append("\n# Add pre-routing commands\n") From 66b44ecd6074c88541d640d3e14053148e53d335 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 26 Jul 2023 12:26:16 +0200 Subject: [PATCH 120/454] soc/add_uart: Fix stub behavior (sink/source swap), thanks @zyp. --- CHANGES.md | 1 + litex/soc/integration/soc.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 74346a571..8b552109b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - liteeth/core/icmp : Fixed length check on LiteEthICMPEcho before passing data to buffer. - LiteXModule/CSR : Fixed CSR collection order causing CSR clock domain to be changed. - litepcie/US(P) : Fixed root cause of possible MSI deadlock. + - soc/add_uart : Fixed stub behavior (sink/source swap). [> Added -------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 60b95fa30..f87106496 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1394,7 +1394,7 @@ def add_uart(self, name="uart", uart_name="serial", baudrate=115200, fifo_depth= # Stub / Stream. elif uart_name in ["stub", "stream"]: uart = UART(tx_fifo_depth=0, rx_fifo_depth=0) - self.comb += uart.sink.ready.eq(uart_name == "stub") + self.comb += uart.source.ready.eq(uart_name == "stub") # UARTBone. elif uart_name in ["uartbone"]: From 20ce982da20c2cfb6b0b7ea634b922cccb7b739f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 26 Jul 2023 16:30:52 +0200 Subject: [PATCH 121/454] software/bios: Fix missing CSR_SDCARD_CORE_BASE update. --- litex/soc/software/bios/boot.c | 4 ++-- litex/soc/software/bios/cmds/cmd_boot.c | 2 +- litex/soc/software/bios/main.c | 2 +- litex/soc/software/liblitesdcard/sdcard.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index 39233fcee..5ade1c89c 100755 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -657,7 +657,7 @@ void flashboot(void) /* SDCard Boot */ /*-----------------------------------------------------------------------*/ -#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) +#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCARD_CORE_BASE) static int copy_file_from_sdcard_to_ram(const char * filename, unsigned long ram_address) { @@ -814,7 +814,7 @@ void sdcardboot(void) printf("Booting from SDCard in SPI-Mode...\n"); fatfs_set_ops_spisdcard(); /* use spisdcard disk access ops */ #endif -#ifdef CSR_SDCORE_BASE +#ifdef CSR_SDCARD_CORE_BASE printf("Booting from SDCard in SD-Mode...\n"); fatfs_set_ops_sdcard(); /* use sdcard disk access ops */ #endif diff --git a/litex/soc/software/bios/cmds/cmd_boot.c b/litex/soc/software/bios/cmds/cmd_boot.c index ed3061cb0..0a9b0df63 100644 --- a/litex/soc/software/bios/cmds/cmd_boot.c +++ b/litex/soc/software/bios/cmds/cmd_boot.c @@ -122,7 +122,7 @@ define_command(netboot, netboot, "Boot via Ethernet (TFTP)", BOOT_CMDS); * Boot software from SDcard * */ -#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) +#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCARD_CORE_BASE) define_command(sdcardboot, sdcardboot, "Boot from SDCard", BOOT_CMDS); #endif diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index eadda868d..69fbd22af 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -63,7 +63,7 @@ static void boot_sequence(void) #ifdef ROM_BOOT_ADDRESS romboot(); #endif -#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE) +#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCARD_CORE_BASE) sdcardboot(); #endif #if defined(CSR_SATA_SECTOR2MEM_BASE) diff --git a/litex/soc/software/liblitesdcard/sdcard.h b/litex/soc/software/liblitesdcard/sdcard.h index 8a132fcda..b6e25833e 100644 --- a/litex/soc/software/liblitesdcard/sdcard.h +++ b/litex/soc/software/liblitesdcard/sdcard.h @@ -109,7 +109,7 @@ void sdcard_read(uint32_t sector, uint32_t count, uint8_t* buf); void sdcard_write(uint32_t sector, uint32_t count, uint8_t* buf); void fatfs_set_ops_sdcard(void); -#endif /* CSR_SDCORE_BASE */ +#endif /* CSR_SDCARD_CORE_BASE */ #ifdef __cplusplus } From 72a1592beefd2224871d83248bae80168028f961 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 13:27:15 +0200 Subject: [PATCH 122/454] litex/gen: Add initial/minimal LiteXContext to easily get build context from modules. Still a PoC and need to think a bit more about it, but will allow fixing AsyncFIFO issue on Efinix FPGAs. --- litex/build/generic_platform.py | 7 ++++++- litex/build/generic_toolchain.py | 5 +++++ litex/gen/common.py | 10 ++++++++++ litex/soc/integration/soc.py | 5 ++++- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/litex/build/generic_platform.py b/litex/build/generic_platform.py index f79b7f5d6..6e3734f5c 100644 --- a/litex/build/generic_platform.py +++ b/litex/build/generic_platform.py @@ -13,6 +13,7 @@ from migen.fhdl.structure import Signal, Cat from migen.genlib.record import Record +from litex.gen import LiteXContext from litex.gen.fhdl import verilog from litex.build.io import CRG @@ -327,7 +328,7 @@ def get_platform_commands(self): # Generic Platform --------------------------------------------------------------------------------- class GenericPlatform: - device_family = None + device_family = None _bitstream_ext = None # None by default, overridden by vendor platform, may # be a string when same extension is used for sram and # flash. A dict must be provided otherwise @@ -349,6 +350,10 @@ def __init__(self, device, io, connectors=[], name=None): self.finalized = False self.use_default_clk = False + # Set Platform/Device to LiteXContext. + LiteXContext.platform = self + LiteXContext.device = device + def request(self, *args, **kwargs): return self.constraint_manager.request(*args, **kwargs) diff --git a/litex/build/generic_toolchain.py b/litex/build/generic_toolchain.py index 8ad3fef9b..46a01e459 100644 --- a/litex/build/generic_toolchain.py +++ b/litex/build/generic_toolchain.py @@ -10,6 +10,8 @@ from migen.fhdl.structure import _Fragment +from litex.gen import LiteXContext + # Generic Toolchain -------------------------------------------------------------------------------- class GenericToolchain: @@ -28,6 +30,9 @@ def __init__(self): self._vns = None self._synth_opts = "" + # Set Toolchain to LiteXContext. + LiteXContext.toolchain = self + @property def support_mixed_language(self): return self._support_mixed_language diff --git a/litex/gen/common.py b/litex/gen/common.py index 81c2fca88..ce286c965 100644 --- a/litex/gen/common.py +++ b/litex/gen/common.py @@ -30,6 +30,16 @@ def reverse_bytes(s): return Cat(*[s[i*8:min((i + 1)*8, len(s))] for i in reversed(range(n))]) +# Context ------------------------------------------------------------------------------------------ + +# FIXME: PoC to fix Efinix AsyncFIFO issue, think a bit more about it to see how to do it properly. + +class LiteXContext: + platform = None + toolchain = None + device = None + soc = None + # Signals ------------------------------------------------------------------------------------------ class Open(Signal): pass diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index f87106496..fc749cb8e 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -17,7 +17,7 @@ from migen import * from litex.gen import colorer -from litex.gen import LiteXModule +from litex.gen import LiteXModule, LiteXContext from litex.gen.genlib.misc import WaitTimer from litex.gen.fhdl.hierarchy import LiteXHierarchyExplorer @@ -863,6 +863,9 @@ def __init__(self, platform, sys_clk_freq, self.constants = {} self.csr_regions = {} + # Set SoC to LiteXContext. + LiteXContext.soc = self + # SoC Bus Handler -------------------------------------------------------------------------- self.bus = SoCBusHandler( standard = bus_standard, From 924da55ea0034c8fd4e33880f1165f61ca013ee9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 13:29:05 +0200 Subject: [PATCH 123/454] stream/AsyncFIFO: Add a minimum of 2 buffers on Efinix FPGAs to fix issues on hardware. Root cause still need to be understand, but when testing with another AsyncFIFO (from verilog axis), the behavior was similar. So is it an Efinity issue? Constraint issue? --- litex/soc/interconnect/stream.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index 94c571c5a..1a05cc3e4 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -13,6 +13,8 @@ from migen.genlib import fifo from migen.genlib.cdc import MultiReg, PulseSynchronizer, AsyncResetSynchronizer +from litex.gen import LiteXContext + from litex.soc.interconnect.csr import * # Endpoint ----------------------------------------------------------------------------------------- @@ -234,10 +236,19 @@ class AsyncFIFO(_FIFOWrapper): def __init__(self, layout, depth=None, buffered=False): depth = 4 if depth is None else depth assert depth >= 4 + nbuffers = 0 + if buffered: + nbuffers = 1 + from litex.build.efinix import EfinixPlatform + if isinstance(LiteXContext.platform, EfinixPlatform): + nbuffers = 2 # Minimum of 2 buffers required on Efinix FPGAs. _FIFOWrapper.__init__(self, - fifo_class = fifo.AsyncFIFOBuffered if buffered else fifo.AsyncFIFO, + fifo_class = fifo.AsyncFIFOBuffered if nbuffers > 0 else fifo.AsyncFIFO, layout = layout, - depth = depth) + depth = depth + ) + if nbuffers > 1: + ClockDomainsRenamer("read")(BufferizeEndpoints({"source": DIR_SOURCE})(self)) # ClockDomainCrossing ------------------------------------------------------------------------------ From bbf944c3ba9b6078ebdfdeb4060dc8e420609804 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 13:55:20 +0200 Subject: [PATCH 124/454] build/efinix/efinity: Fix build with 2023.1. --- litex/build/efinix/efinity.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index bba1981bf..0f6919070 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -217,7 +217,7 @@ def build_project(self): root.attrib["xmlns:efx"] = "http://www.efinixinc.com/enf_proj" root.attrib["name"] = self._build_name root.attrib["location"] = str(pathlib.Path().resolve()) - root.attrib["sw_version"] = "2022.1.226" # TODO: read it from sw_version.txt + root.attrib["sw_version"] = "2023.1.150" # TODO: read it from sw_version.txt root.attrib["last_change_date"] = f"Date : {now.strftime('%Y-%m-%d %H:%M')}" # Add Device. @@ -269,6 +269,9 @@ def build_project(self): if self.ifacewriter.fix_xml: self.ifacewriter.fix_xml_values() + # FIXME: peri.xml is generated from Efinity, why does it require patching? + tools.replace_in_file(f"{self._build_name}.peri.xml", 'adv_out_phase_shift="0.0"', 'adv_out_phase_shift="0"') + def build_script(self): return "" # not used From 74401d6f03231f1012cc4a10398ae95b2c38631e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 13:58:45 +0200 Subject: [PATCH 125/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 8b552109b..13913636d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ - LiteXModule/CSR : Fixed CSR collection order causing CSR clock domain to be changed. - litepcie/US(P) : Fixed root cause of possible MSI deadlock. - soc/add_uart : Fixed stub behavior (sink/source swap). + - build/efinix : Fixed AsyncFIFO issues (Minimum of 2 buffer stages). [> Added -------- @@ -49,6 +50,7 @@ - soc/add_uartbone/sata/sdcard : Added support for multiple instances in gateware as for the other cores. - liteeth_gen : Added raw UDP port support. - build/vivado : Added .dcp generation also after synthesis and placement. + - gen: : Added initial LiteXContext to easily get build properties (platform, device, toolchain, etc...) [> Changed ---------- From 095cfb781151bea54867a257f9511a5f058282d2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 15:02:37 +0200 Subject: [PATCH 126/454] litex/gen: Split common in common/context/reduce/signal. --- litex/gen/__init__.py | 5 +++++ litex/gen/common.py | 51 ------------------------------------------- litex/gen/context.py | 17 +++++++++++++++ litex/gen/reduce.py | 33 ++++++++++++++++++++++++++++ litex/gen/signal.py | 21 ++++++++++++++++++ 5 files changed, 76 insertions(+), 51 deletions(-) create mode 100644 litex/gen/context.py create mode 100644 litex/gen/reduce.py create mode 100644 litex/gen/signal.py diff --git a/litex/gen/__init__.py b/litex/gen/__init__.py index 507ac7efe..e329fc4cd 100644 --- a/litex/gen/__init__.py +++ b/litex/gen/__init__.py @@ -1,3 +1,8 @@ from litex.gen.sim import * + from litex.gen.common import * +from litex.gen.signal import * +from litex.gen.reduce import * +from litex.gen.context import * + from litex.gen.fhdl.module import * diff --git a/litex/gen/common.py b/litex/gen/common.py index ce286c965..150f06940 100644 --- a/litex/gen/common.py +++ b/litex/gen/common.py @@ -24,58 +24,7 @@ def colorer(s, color="bright"): def reverse_bits(s): return s[::-1] - def reverse_bytes(s): n = (len(s) + 7)//8 return Cat(*[s[i*8:min((i + 1)*8, len(s))] for i in reversed(range(n))]) - -# Context ------------------------------------------------------------------------------------------ - -# FIXME: PoC to fix Efinix AsyncFIFO issue, think a bit more about it to see how to do it properly. - -class LiteXContext: - platform = None - toolchain = None - device = None - soc = None - -# Signals ------------------------------------------------------------------------------------------ - -class Open(Signal): pass - -class Unsigned(Signal): - def __init__(self, bits=1, *args, **kwargs): - assert isinstance(bits, int) - Signal.__init__(self, bits_sign=(bits, 0), *args, **kwargs) - -class Signed(Signal): - def __init__(self, bits=1, *args, **kwargs): - assert isinstance(bits, int) - Signal.__init__(self, bits_sign=(bits, 1), *args, **kwargs) - -# Reduction ---------------------------------------------------------------------------------------- - -from functools import reduce -from operator import and_, or_, not_, xor, add - -def Reduce(operator, value): - # List of supported Operators. - operators = { - "AND" : and_, - "OR" : or_, - "NOR" : not_, - "XOR" : xor, - "ADD" : add, - } - - # Switch to upper-case. - operator = operator.upper() - - # Check if provided operator is supported. - if operator not in operators.keys(): - supported = ", ".join(operators.keys()) - raise ValueError(f"Reduce does not support {operator} operator; supported: {supported}.") - - # Return Python's reduction. - return reduce(operators[operator], value) diff --git a/litex/gen/context.py b/litex/gen/context.py new file mode 100644 index 000000000..39ffa51f0 --- /dev/null +++ b/litex/gen/context.py @@ -0,0 +1,17 @@ +# +# This file is part of LiteX. +# +# This file is Copyright (c) 2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +# LiteX Context ------------------------------------------------------------------------------------ + +# FIXME: PoC to fix Efinix AsyncFIFO issue, think a bit more about it to see how to do it properly. + +class LiteXContext: + platform = None + toolchain = None + device = None + soc = None diff --git a/litex/gen/reduce.py b/litex/gen/reduce.py new file mode 100644 index 000000000..63fc7e29d --- /dev/null +++ b/litex/gen/reduce.py @@ -0,0 +1,33 @@ +# +# This file is part of LiteX. +# +# This file is Copyright (c) 2022 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +from functools import reduce +from operator import and_, or_, not_, xor, add + +# Reduction ---------------------------------------------------------------------------------------- + +def Reduce(operator, value): + # List of supported Operators. + operators = { + "AND" : and_, + "OR" : or_, + "NOR" : not_, + "XOR" : xor, + "ADD" : add, + } + + # Switch to upper-case. + operator = operator.upper() + + # Check if provided operator is supported. + if operator not in operators.keys(): + supported = ", ".join(operators.keys()) + raise ValueError(f"Reduce does not support {operator} operator; supported: {supported}.") + + # Return Python's reduction. + return reduce(operators[operator], value) diff --git a/litex/gen/signal.py b/litex/gen/signal.py new file mode 100644 index 000000000..0714aa423 --- /dev/null +++ b/litex/gen/signal.py @@ -0,0 +1,21 @@ +# +# This file is part of LiteX. +# +# This file is Copyright (c) 2022 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +# Signals ------------------------------------------------------------------------------------------ + +class Open(Signal): pass + +class Unsigned(Signal): + def __init__(self, bits=1, *args, **kwargs): + assert isinstance(bits, int) + Signal.__init__(self, bits_sign=(bits, 0), *args, **kwargs) + +class Signed(Signal): + def __init__(self, bits=1, *args, **kwargs): + assert isinstance(bits, int) + Signal.__init__(self, bits_sign=(bits, 1), *args, **kwargs) From ed12f8787d6922bc18c8abc26a1346e56de5e6b6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 27 Jul 2023 16:18:30 +0200 Subject: [PATCH 127/454] litex/gen: Add some comments. --- litex/gen/common.py | 5 ++++- litex/gen/context.py | 14 ++++++++++++-- litex/gen/signal.py | 16 +++++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/litex/gen/common.py b/litex/gen/common.py index 150f06940..3a963fff6 100644 --- a/litex/gen/common.py +++ b/litex/gen/common.py @@ -6,9 +6,10 @@ from migen import * -# Generic Helpers ---------------------------------------------------------------------------------- +# Coloring Helpers --------------------------------------------------------------------------------- def colorer(s, color="bright"): + """Apply ANSI colors to a string.""" header = { "bright": "\x1b[1m", "green": "\x1b[32m", @@ -22,9 +23,11 @@ def colorer(s, color="bright"): # Bit/Bytes Reversing ------------------------------------------------------------------------------ def reverse_bits(s): + """Return a signal with reversed bit order.""" return s[::-1] def reverse_bytes(s): + """Return a signal with reversed byte order.""" n = (len(s) + 7)//8 return Cat(*[s[i*8:min((i + 1)*8, len(s))] for i in reversed(range(n))]) diff --git a/litex/gen/context.py b/litex/gen/context.py index 39ffa51f0..8846283a1 100644 --- a/litex/gen/context.py +++ b/litex/gen/context.py @@ -8,9 +8,19 @@ # LiteX Context ------------------------------------------------------------------------------------ -# FIXME: PoC to fix Efinix AsyncFIFO issue, think a bit more about it to see how to do it properly. - class LiteXContext: + """ + A context for LiteX-related settings. + + This class serves as a container for the platform, toolchain, device, + and system-on-a-chip (SoC) information for a given LiteX project. + + Attributes: + platform : The FPGA Platform of the project. + toolchain : The FPGA Toolchain to be used for synthesis and place-and-route. + device : The FPGA Device of the LiteX project. + soc : The FPGA SoC of the LiteX project. + """ platform = None toolchain = None device = None diff --git a/litex/gen/signal.py b/litex/gen/signal.py index 0714aa423..e87d33146 100644 --- a/litex/gen/signal.py +++ b/litex/gen/signal.py @@ -8,14 +8,28 @@ # Signals ------------------------------------------------------------------------------------------ -class Open(Signal): pass +class Open(Signal): + """A base Signal class, representing an open signal.""" + pass class Unsigned(Signal): + """ + A Signal subclass for unsigned signals. + + Args: + bits (int): Number of bits of the signal. Defaults to 1. + """ def __init__(self, bits=1, *args, **kwargs): assert isinstance(bits, int) Signal.__init__(self, bits_sign=(bits, 0), *args, **kwargs) class Signed(Signal): + """ + A Signal subclass for signed signals. + + Args: + bits (int): Number of bits of the signal. Defaults to 1. + """ def __init__(self, bits=1, *args, **kwargs): assert isinstance(bits, int) Signal.__init__(self, bits_sign=(bits, 1), *args, **kwargs) From 717fb131fd39a13b27d256becaf50a5b451f31af Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 09:15:22 +0200 Subject: [PATCH 128/454] interconnect/axi: Switch to LiteXModule. --- litex/soc/interconnect/axi/axi_full.py | 39 +++++------ .../interconnect/axi/axi_full_to_axi_lite.py | 10 +-- .../interconnect/axi/axi_full_to_wishbone.py | 8 ++- litex/soc/interconnect/axi/axi_lite.py | 64 +++++++++---------- litex/soc/interconnect/axi/axi_lite_to_csr.py | 6 +- .../interconnect/axi/axi_lite_to_wishbone.py | 10 +-- litex/soc/interconnect/axi/axi_stream.py | 4 +- 7 files changed, 75 insertions(+), 66 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index f14d94438..e3cdd4af7 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2018-2022 Florent Kermarrec +# Copyright (c) 2018-2023 Florent Kermarrec # Copyright (c) 2020 Antmicro # SPDX-License-Identifier: BSD-2-Clause @@ -10,6 +10,7 @@ from migen import * from migen.genlib import roundrobin +from litex.gen import * from litex.gen.genlib.misc import WaitTimer from litex.build.generic_platform import * @@ -137,7 +138,7 @@ def layout_flat(self): # AXI Bursts to Beats ------------------------------------------------------------------------------ -class AXIBurst2Beat(Module): +class AXIBurst2Beat(LiteXModule): def __init__(self, ax_burst, ax_beat, capabilities={BURST_FIXED, BURST_INCR, BURST_WRAP}): assert BURST_FIXED in capabilities @@ -189,7 +190,7 @@ def __init__(self, ax_burst, ax_beat, capabilities={BURST_FIXED, BURST_INCR, BUR # AXI Data-Width Converter ------------------------------------------------------------------------- -class AXIUpConverter(Module): +class AXIUpConverter(LiteXModule): def __init__(self, axi_from, axi_to): dw_from = len(axi_from.r.data) dw_to = len(axi_to.r.data) @@ -246,7 +247,7 @@ def __init__(self, axi_from, axi_to): self.comb += axi_from.r.user.eq(axi_to.r.user) self.comb += axi_from.r.dest.eq(axi_to.r.dest) -class AXIDownConverter(Module): +class AXIDownConverter(LiteXModule): def __init__(self, axi_from, axi_to): dw_from = len(axi_from.r.data) dw_to = len(axi_to.r.data) @@ -338,7 +339,7 @@ def convert_size(ax_from, ax_to): self.sync += axi_from.r.dest.eq(axi_to.r.dest) self.sync += axi_from.r.id.eq(axi_to.r.id) -class AXIConverter(Module): +class AXIConverter(LiteXModule): """AXI data width converter""" def __init__(self, master, slave): self.master = master @@ -359,7 +360,7 @@ def __init__(self, master, slave): # AXI Timeout -------------------------------------------------------------------------------------- -class AXITimeout(Module): +class AXITimeout(LiteXModule): """Protect master against slave timeouts (master _has_ to respond correctly)""" def __init__(self, master, cycles): self.error = Signal() @@ -388,7 +389,7 @@ def channel_fsm(timer, wait_cond, error, response): fsm.act("RESPOND", *response) return fsm - self.submodules.wr_fsm = channel_fsm( + self.wr_fsm = channel_fsm( timer = wr_timer, wait_cond = (master.aw.valid & ~master.aw.ready) | (master.w.valid & ~master.w.ready), error = wr_error, @@ -402,7 +403,7 @@ def channel_fsm(timer, wait_cond, error, response): ) ]) - self.submodules.rd_fsm = channel_fsm( + self.rd_fsm = channel_fsm( timer = rd_timer, wait_cond = master.ar.valid & ~master.ar.ready, error = rd_error, @@ -419,7 +420,7 @@ def channel_fsm(timer, wait_cond, error, response): # AXI Interconnect Components ---------------------------------------------------------------------- -class _AXIRequestCounter(Module): +class _AXIRequestCounter(LiteXModule): def __init__(self, request, response, max_requests=256): self.counter = counter = Signal(max=max_requests) self.full = full = Signal() @@ -443,7 +444,7 @@ def __init__(self, request, response, max_requests=256): ), ] -class AXIArbiter(Module): +class AXIArbiter(LiteXModule): """AXI arbiter Arbitrate between master interfaces and connect one to the target. New master will not be @@ -451,8 +452,8 @@ class AXIArbiter(Module): done separately. """ def __init__(self, masters, target): - self.submodules.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) - self.submodules.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) + self.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) + self.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) def get_sig(interface, channel, name): return getattr(getattr(interface, channel), name) @@ -477,11 +478,11 @@ def get_sig(interface, channel, name): self.comb += dest.eq(source) # Allow to change rr.grant only after all requests from a master have been responded to. - self.submodules.wr_lock = wr_lock = _AXIRequestCounter( + self.wr_lock = wr_lock = _AXIRequestCounter( request = target.aw.valid & target.aw.ready, response = target.b.valid & target.b.ready ) - self.submodules.rd_lock = rd_lock = _AXIRequestCounter( + self.rd_lock = rd_lock = _AXIRequestCounter( request = target.ar.valid & target.ar.ready, response = target.r.valid & target.r.ready & target.r.last ) @@ -498,7 +499,7 @@ def get_sig(interface, channel, name): self.rr_read.request.eq(Cat(*[m.ar.valid | m.r.valid for m in masters])), ] -class AXIDecoder(Module): +class AXIDecoder(LiteXModule): """AXI decoder Decode master access to particular slave based on its decoder function. @@ -611,12 +612,12 @@ class AXIInterconnectShared(Module): def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) shared = AXIInterface(data_width=data_width) - self.submodules.arbiter = AXIArbiter(masters, shared) - self.submodules.decoder = AXIDecoder(shared, slaves) + self.arbiter = AXIArbiter(masters, shared) + self.decoder = AXIDecoder(shared, slaves) if timeout_cycles is not None: - self.submodules.timeout = AXITimeout(shared, timeout_cycles) + self.timeout = AXITimeout(shared, timeout_cycles) -class AXICrossbar(Module): +class AXICrossbar(LiteXModule): """AXI crossbar MxN crossbar for M masters and N slaves. diff --git a/litex/soc/interconnect/axi/axi_full_to_axi_lite.py b/litex/soc/interconnect/axi/axi_full_to_axi_lite.py index 6bb03d5ba..10749a663 100644 --- a/litex/soc/interconnect/axi/axi_full_to_axi_lite.py +++ b/litex/soc/interconnect/axi/axi_full_to_axi_lite.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2018-2022 Florent Kermarrec +# Copyright (c) 2018-2023 Florent Kermarrec # Copyright (c) 2020 Antmicro # SPDX-License-Identifier: BSD-2-Clause @@ -9,6 +9,8 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect import stream from litex.soc.interconnect.axi.axi_common import * @@ -17,7 +19,7 @@ # AXI to AXI-Lite ---------------------------------------------------------------------------------- -class AXI2AXILite(Module): +class AXI2AXILite(LiteXModule): # Note: Since this AXI bridge will mostly be used to target buses that are not supporting # simultaneous writes/reads, to reduce ressource usage the AXIBurst2Beat module is shared # between writes/reads. @@ -37,7 +39,7 @@ def __init__(self, axi, axi_lite): _cmd_done = Signal() _last_ar_aw_n = Signal() - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(_cmd_done, 0), If(axi.ar.valid & axi.aw.valid, @@ -121,7 +123,7 @@ def __init__(self, axi, axi_lite): # AXI-Lite to AXI ---------------------------------------------------------------------------------- -class AXILite2AXI(Module): +class AXILite2AXI(LiteXModule): def __init__(self, axi_lite, axi, write_id=0, read_id=0, prot=0, burst_type="INCR"): assert isinstance(axi_lite, AXILiteInterface) assert isinstance(axi, AXIInterface) diff --git a/litex/soc/interconnect/axi/axi_full_to_wishbone.py b/litex/soc/interconnect/axi/axi_full_to_wishbone.py index 7fe47e28b..d77a3522e 100644 --- a/litex/soc/interconnect/axi/axi_full_to_wishbone.py +++ b/litex/soc/interconnect/axi/axi_full_to_wishbone.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2018-2022 Florent Kermarrec +# Copyright (c) 2018-2023 Florent Kermarrec # Copyright (c) 2020 Antmicro # SPDX-License-Identifier: BSD-2-Clause @@ -9,6 +9,8 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect.axi.axi_common import * from litex.soc.interconnect.axi.axi_lite import * from litex.soc.interconnect.axi.axi_full_to_axi_lite import * @@ -16,7 +18,7 @@ # AXI to Wishbone ---------------------------------------------------------------------------------- -class AXI2Wishbone(Module): +class AXI2Wishbone(LiteXModule): def __init__(self, axi, wishbone, base_address=0x00000000): axi_lite = AXILiteInterface(axi.data_width, axi.address_width) axi2axi_lite = AXI2AXILite(axi, axi_lite) @@ -25,7 +27,7 @@ def __init__(self, axi, wishbone, base_address=0x00000000): # Wishbone to AXI ---------------------------------------------------------------------------------- -class Wishbone2AXI(Module): +class Wishbone2AXI(LiteXModule): def __init__(self, wishbone, axi, base_address=0x00000000): axi_lite = AXILiteInterface(axi.data_width, axi.address_width) wishbone2axi_lite = Wishbone2AXILite(wishbone, axi_lite, base_address) diff --git a/litex/soc/interconnect/axi/axi_lite.py b/litex/soc/interconnect/axi/axi_lite.py index b336efec5..595eaf50a 100644 --- a/litex/soc/interconnect/axi/axi_lite.py +++ b/litex/soc/interconnect/axi/axi_lite.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2018-2022 Florent Kermarrec +# Copyright (c) 2018-2023 Florent Kermarrec # Copyright (c) 2020 Antmicro # SPDX-License-Identifier: BSD-2-Clause @@ -10,6 +10,8 @@ from migen import * from migen.genlib import roundrobin +from litex.gen import * + from litex.gen.genlib.misc import WaitTimer from litex.build.generic_platform import * @@ -184,7 +186,7 @@ def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we= # AXI-Lite SRAM ------------------------------------------------------------------------------------ -class AXILiteSRAM(Module): +class AXILiteSRAM(LiteXModule): def __init__(self, mem_or_size, read_only=None, init=None, bus=None, name=None): if bus is None: bus = AXILiteInterface() @@ -223,12 +225,12 @@ def __init__(self, mem_or_size, read_only=None, init=None, bus=None, name=None): port_dat_r = port.dat_r, port_dat_w = port.dat_w if not read_only else None, port_we = port.we if not read_only else None) - self.submodules.fsm = fsm + self.fsm = fsm self.comb += comb # AXI-Lite Data-Width Converter -------------------------------------------------------------------- -class _AXILiteDownConverterWrite(Module): +class _AXILiteDownConverterWrite(LiteXModule): def __init__(self, master, slave): assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface) dw_from = len(master.w.data) @@ -252,9 +254,7 @@ def __init__(self, master, slave): ] # Control Path - fsm = FSM(reset_state="IDLE") - fsm = ResetInserter()(fsm) - self.submodules.fsm = fsm + self.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) # Reset the converter state if master breaks a request, we can do that as # aw.valid and w.valid are kept high in CONVERT and RESPOND-SLAVE, and # acknowledged only when moving to RESPOND-MASTER, and then b.valid is 1. @@ -319,7 +319,7 @@ def __init__(self, master, slave): ) ) -class _AXILiteDownConverterRead(Module): +class _AXILiteDownConverterRead(LiteXModule): def __init__(self, master, slave): assert isinstance(master, AXILiteInterface) and isinstance(slave, AXILiteInterface) dw_from = len(master.r.data) @@ -344,9 +344,7 @@ def __init__(self, master, slave): ] # Control Path - fsm = FSM(reset_state="IDLE") - fsm = ResetInserter()(fsm) - self.submodules.fsm = fsm + self.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) # Reset the converter state if master breaks a request, we can do that as # ar.valid is high in CONVERT and RESPOND-SLAVE, and r.valid in RESPOND-MASTER. self.comb += fsm.reset.eq(~(master.ar.valid | master.r.valid)) @@ -390,12 +388,12 @@ def __init__(self, master, slave): ) ) -class AXILiteDownConverter(Module): +class AXILiteDownConverter(LiteXModule): def __init__(self, master, slave): - self.submodules.write = _AXILiteDownConverterWrite(master, slave) - self.submodules.read = _AXILiteDownConverterRead(master, slave) + self.write = _AXILiteDownConverterWrite(master, slave) + self.read = _AXILiteDownConverterRead(master, slave) -class AXILiteUpConverter(Module): +class AXILiteUpConverter(LiteXModule): # TODO: we could try joining multiple master accesses into single slave access would require # checking if address changes and a way to flush on single access def __init__(self, master, slave): @@ -453,7 +451,7 @@ def __init__(self, master, slave): self.comb += Case(wr_word, wr_cases) self.comb += Case(rd_word, rd_cases) -class AXILiteConverter(Module): +class AXILiteConverter(LiteXModule): """AXILite data width converter""" def __init__(self, master, slave): self.master = master @@ -474,7 +472,7 @@ def __init__(self, master, slave): # AXI-Lite Clock Domain Crossing ------------------------------------------------------------------- -class AXILiteClockDomainCrossing(Module): +class AXILiteClockDomainCrossing(LiteXModule): """AXILite Clock Domain Crossing""" def __init__(self, master, slave, cd_from="sys", cd_to="sys"): # Same Clock Domain, direct connection. @@ -516,7 +514,7 @@ def __init__(self, master, slave, cd_from="sys", cd_to="sys"): # AXI-Lite Timeout --------------------------------------------------------------------------------- -class AXILiteTimeout(Module): +class AXILiteTimeout(LiteXModule): """Protect master against slave timeouts (master _has_ to respond correctly)""" def __init__(self, master, cycles): self.error = Signal() @@ -545,7 +543,7 @@ def channel_fsm(timer, wait_cond, error, response): fsm.act("RESPOND", *response) return fsm - self.submodules.wr_fsm = channel_fsm( + self.wr_fsm = channel_fsm( timer = wr_timer, wait_cond = (master.aw.valid & ~master.aw.ready) | (master.w.valid & ~master.w.ready), error = wr_error, @@ -559,7 +557,7 @@ def channel_fsm(timer, wait_cond, error, response): ) ]) - self.submodules.rd_fsm = channel_fsm( + self.rd_fsm = channel_fsm( timer = rd_timer, wait_cond = master.ar.valid & ~master.ar.ready, error = rd_error, @@ -575,7 +573,7 @@ def channel_fsm(timer, wait_cond, error, response): # AXI-Lite Interconnect Components ----------------------------------------------------------------- -class _AXILiteRequestCounter(Module): +class _AXILiteRequestCounter(LiteXModule): def __init__(self, request, response, max_requests=256): self.counter = counter = Signal(max=max_requests) self.full = full = Signal() @@ -599,7 +597,7 @@ def __init__(self, request, response, max_requests=256): ), ] -class AXILiteArbiter(Module): +class AXILiteArbiter(LiteXModule): """AXI Lite arbiter Arbitrate between master interfaces and connect one to the target. New master will not be @@ -607,8 +605,8 @@ class AXILiteArbiter(Module): done separately. """ def __init__(self, masters, target): - self.submodules.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) - self.submodules.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) + self.rr_write = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) + self.rr_read = roundrobin.RoundRobin(len(masters), roundrobin.SP_CE) def get_sig(interface, channel, name): return getattr(getattr(interface, channel), name) @@ -633,11 +631,11 @@ def get_sig(interface, channel, name): self.comb += dest.eq(source) # Allow to change rr.grant only after all requests from a master have been responded to. - self.submodules.wr_lock = wr_lock = _AXILiteRequestCounter( + self.wr_lock = wr_lock = _AXILiteRequestCounter( request = target.aw.valid & target.aw.ready, response = target.b.valid & target.b.ready ) - self.submodules.rd_lock = rd_lock = _AXILiteRequestCounter( + self.rd_lock = rd_lock = _AXILiteRequestCounter( request = target.ar.valid & target.ar.ready, response = target.r.valid & target.r.ready ) @@ -654,7 +652,7 @@ def get_sig(interface, channel, name): self.rr_read.request.eq(Cat(*[m.ar.valid | m.r.valid for m in masters])), ] -class AXILiteDecoder(Module): +class AXILiteDecoder(LiteXModule): """AXI Lite decoder Decode master access to particular slave based on its decoder function. @@ -757,22 +755,22 @@ def get_check_parameters(ports): return data_width -class AXILiteInterconnectPointToPoint(Module): +class AXILiteInterconnectPointToPoint(LiteXModule): """AXI Lite point to point interconnect""" def __init__(self, master, slave): self.comb += master.connect(slave) -class AXILiteInterconnectShared(Module): +class AXILiteInterconnectShared(LiteXModule): """AXI Lite shared interconnect""" def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) shared = AXILiteInterface(data_width=data_width) - self.submodules.arbiter = AXILiteArbiter(masters, shared) - self.submodules.decoder = AXILiteDecoder(shared, slaves) + self.arbiter = AXILiteArbiter(masters, shared) + self.decoder = AXILiteDecoder(shared, slaves) if timeout_cycles is not None: - self.submodules.timeout = AXILiteTimeout(shared, timeout_cycles) + self.timeout = AXILiteTimeout(shared, timeout_cycles) -class AXILiteCrossbar(Module): +class AXILiteCrossbar(LiteXModule): """AXI Lite crossbar MxN crossbar for M masters and N slaves. diff --git a/litex/soc/interconnect/axi/axi_lite_to_csr.py b/litex/soc/interconnect/axi/axi_lite_to_csr.py index 0508c8775..b21dfa5b8 100644 --- a/litex/soc/interconnect/axi/axi_lite_to_csr.py +++ b/litex/soc/interconnect/axi/axi_lite_to_csr.py @@ -9,6 +9,8 @@ from migen import * +from litex.gen import * + from litex.build.generic_platform import * from litex.soc.interconnect.axi.axi_common import * @@ -16,7 +18,7 @@ # AXI-Lite to CSR ---------------------------------------------------------------------------------- -class AXILite2CSR(Module): +class AXILite2CSR(LiteXModule): def __init__(self, axi_lite=None, bus_csr=None, register=False): # TODO: unused register argument if axi_lite is None: @@ -33,5 +35,5 @@ def __init__(self, axi_lite=None, bus_csr=None, register=False): port_dat_r = self.csr.dat_r, port_dat_w = self.csr.dat_w, port_we = self.csr.we) - self.submodules.fsm = fsm + self.fsm = fsm self.comb += comb diff --git a/litex/soc/interconnect/axi/axi_lite_to_wishbone.py b/litex/soc/interconnect/axi/axi_lite_to_wishbone.py index 09ebf08c0..fa56b5c95 100644 --- a/litex/soc/interconnect/axi/axi_lite_to_wishbone.py +++ b/litex/soc/interconnect/axi/axi_lite_to_wishbone.py @@ -9,11 +9,13 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect.axi.axi_lite import * # AXI-Lite to Wishbone ----------------------------------------------------------------------------- -class AXILite2Wishbone(Module): +class AXILite2Wishbone(LiteXModule): def __init__(self, axi_lite, wishbone, base_address=0x00000000): wishbone_adr_shift = log2_int(axi_lite.data_width//8) assert axi_lite.data_width == len(wishbone.dat_r) @@ -26,7 +28,7 @@ def __init__(self, axi_lite, wishbone, base_address=0x00000000): self.comb += _r_addr.eq(axi_lite.ar.addr - base_address) self.comb += _w_addr.eq(axi_lite.aw.addr - base_address) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(axi_lite.ar.valid & axi_lite.aw.valid, # If last access was a read, do a write @@ -88,7 +90,7 @@ def __init__(self, axi_lite, wishbone, base_address=0x00000000): # Wishbone to AXI-Lite ----------------------------------------------------------------------------- -class Wishbone2AXILite(Module): +class Wishbone2AXILite(LiteXModule): def __init__(self, wishbone, axi_lite, base_address=0x00000000): wishbone_adr_shift = log2_int(axi_lite.data_width//8) assert axi_lite.data_width == len(wishbone.dat_r) @@ -99,7 +101,7 @@ def __init__(self, wishbone, axi_lite, base_address=0x00000000): _addr = Signal(len(wishbone.adr)) self.comb += _addr.eq(wishbone.adr - base_address//4) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(_cmd_done, 0), NextValue(_data_done, 0), diff --git a/litex/soc/interconnect/axi/axi_stream.py b/litex/soc/interconnect/axi/axi_stream.py index 4e187687c..0b87c4fd0 100644 --- a/litex/soc/interconnect/axi/axi_stream.py +++ b/litex/soc/interconnect/axi/axi_stream.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2018-2022 Florent Kermarrec +# Copyright (c) 2018-2023 Florent Kermarrec # Copyright (c) 2020 Antmicro # SPDX-License-Identifier: BSD-2-Clause @@ -9,6 +9,8 @@ from migen import * +from litex.gen import * + from litex.soc.interconnect import stream from litex.build.generic_platform import * From ff18374c529fd029262714957096e93100b732aa Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 09:15:52 +0200 Subject: [PATCH 129/454] interconnect/axi/axi_common: Document helper functions. --- litex/soc/interconnect/axi/axi_common.py | 57 +++++++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_common.py b/litex/soc/interconnect/axi/axi_common.py index 41b666436..f050b1c7d 100644 --- a/litex/soc/interconnect/axi/axi_common.py +++ b/litex/soc/interconnect/axi/axi_common.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2018-2022 Florent Kermarrec +# Copyright (c) 2018-2023 Florent Kermarrec # Copyright (c) 2020 Antmicro # SPDX-License-Identifier: BSD-2-Clause @@ -42,6 +42,21 @@ # AXI Connection Helpers --------------------------------------------------------------------------- def connect_axi(master, slave, keep=None, omit=None): + """ + Connect AXI master to slave channels. + + This function connects the AXI channels from the master and slave taking into account their + respective roles for each channel type. + + Parameters: + master : AXI master interface. + slave : AXI slave interface. + keep : Optional parameter to keep some signals while connecting. + omit : Optional parameter to omit some signals while connecting. + + Returns: + list: List of statements to create the necessary connections. + """ channel_modes = { "aw": "master", "w" : "master", @@ -59,6 +74,21 @@ def connect_axi(master, slave, keep=None, omit=None): return r def connect_to_pads(bus, pads, mode="master", axi_full=False): + """ + Connect to pads (I/O pins) on the Platform. + + This function connects the AXI bus signals to the respective pads on the Platform, taking into + account their roles (master or slave) for each channel type. + + Parameters: + bus : AXI bus interface. + pads : FPGA pad interface. + mode : Role for connection (master or slave). + axi_full : Boolean flag to indicate if AXI full is being used. + + Returns: + list: List of statements to create the necessary connections. + """ assert mode in ["slave", "master"] r = [] def swap_mode(mode): return "master" if mode == "slave" else "slave" @@ -69,11 +99,13 @@ def swap_mode(mode): return "master" if mode == "slave" else "slave" "ar": mode, "r" : swap_mode(mode), } + # Loop to connect each channel. for channel, mode in channel_modes.items(): ch = getattr(bus, channel) sig_list = [("valid", 1)] + ch.description.payload_layout + ch.description.param_layout if channel in ["w", "r"] and axi_full: sig_list += [("last", 1)] + # Loop to connect each signal within a channel. for name, width in sig_list: if (name == "dest"): continue # No DEST. @@ -95,19 +127,40 @@ def swap_mode(mode): return "master" if mode == "slave" else "slave" return r def axi_layout_flat(axi): - # yields tuples (channel, name, direction) + """ + Generator that yields a flat layout of each AXI signal's channel, name, and direction. + + This function is a generator that iterates over each AXI channel ("aw", "w", "b", "ar", "r"), + then over each group in the channel's layout. + + Parameters: + axi: AXI interface object. + + Yields: + tuple: A tuple of (channel, name, direction), where: + - channel is the name of the AXI channel, + - name is the name of the signal within that channel, + - direction is the direction of the signal (DIR_M_TO_S or DIR_S_TO_M). + """ + + # Helper function to correctly set the direction for "b" and "r" channels. def get_dir(channel, direction): if channel in ["b", "r"]: return {DIR_M_TO_S: DIR_S_TO_M, DIR_S_TO_M: DIR_M_TO_S}[direction] return direction + + # Iterate over each channel. for ch in ["aw", "w", "b", "ar", "r"]: channel = getattr(axi, ch) + + # Iterate over each group in the channel's layout. for group in channel.layout: if len(group) == 3: name, _, direction = group yield ch, name, get_dir(ch, direction) else: _, subgroups = group + # Iterate over each subgroup in the group. for subgroup in subgroups: name, _, direction = subgroup yield ch, name, get_dir(ch, direction) From ff67781f11953e405f1b8f3e63db4d47a9824e53 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 28 Jul 2023 09:26:53 +0200 Subject: [PATCH 130/454] interconnect/axi/axi_common: Document constants. --- litex/soc/interconnect/axi/axi_common.py | 31 ++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_common.py b/litex/soc/interconnect/axi/axi_common.py index f050b1c7d..4ec78b208 100644 --- a/litex/soc/interconnect/axi/axi_common.py +++ b/litex/soc/interconnect/axi/axi_common.py @@ -19,24 +19,25 @@ # AXI Constants ------------------------------------------------------------------------------------ -BURST_FIXED = 0b00 -BURST_INCR = 0b01 -BURST_WRAP = 0b10 -BURST_RESERVED = 0b11 +BURST_FIXED = 0b00 # FIXED : No address increment in burst. +BURST_INCR = 0b01 # INCR : Increment address per transfer in burst. +BURST_WRAP = 0b10 # WRAP : Wrap address back to boundary after set transfers. +BURST_RESERVED = 0b11 # RESERVED : Future use. -RESP_OKAY = 0b00 -RESP_EXOKAY = 0b01 -RESP_SLVERR = 0b10 -RESP_DECERR = 0b11 +RESP_OKAY = 0b00 # OKAY : Operation completed successfully. +RESP_EXOKAY = 0b01 # EXOKAY : Operation success, exclusive access granted. +RESP_SLVERR = 0b10 # SLVERR : Slave not responding/cannot complete request. +RESP_DECERR = 0b11 # DECERR : Decoding error occurred, operation not routed to a slave. +# AXI transaction size (AXSIZE) constants (left: bytes, right: AXI representation). AXSIZE = { - 1 : 0b000, - 2 : 0b001, - 4 : 0b010, - 8 : 0b011, - 16 : 0b100, - 32 : 0b110, - 64 : 0b111, + 1 : 0b000, # 1-byte transaction. + 2 : 0b001, # 2-byte transaction. + 4 : 0b010, # 4-byte transaction. + 8 : 0b011, # 8-byte transaction. + 16 : 0b100, # 16-byte transaction. + 32 : 0b110, # 32-byte transaction. + 64 : 0b111, # 64-byte transaction. } # AXI Connection Helpers --------------------------------------------------------------------------- From 91e1e53662c1fcf0d61208698d033efdd6947395 Mon Sep 17 00:00:00 2001 From: rowanG077 Date: Sun, 30 Jul 2023 00:24:26 +0200 Subject: [PATCH 131/454] soc/interconnect/stream: BufferizeEndpoints params BufferizeEndpoints params now includes parameters which to pipeline the valid/data or ready path --- litex/soc/interconnect/stream.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index 1a05cc3e4..a0465a549 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -985,7 +985,7 @@ def do_finalize(self): # Add buffers on Endpoints (can be used to improve timings) class BufferizeEndpoints(ModuleTransformer): - def __init__(self, endpoint_dict): + def __init__(self, endpoint_dict, pipe_valid=True, pipe_ready=False): self.endpoint_dict = endpoint_dict def transform_instance(self, submodule): @@ -993,13 +993,20 @@ def transform_instance(self, submodule): endpoint = getattr(submodule, name) # add buffer on sinks if direction == DIR_SINK: - buf = Buffer(endpoint.description) + buf = Buffer( + endpoint.description, + pipe_valid=pipe_valid, + pipe_ready=pipe_ready + ) submodule.submodules += buf setattr(submodule, name, buf.sink) submodule.comb += buf.source.connect(endpoint) # add buffer on sources elif direction == DIR_SOURCE: - buf = Buffer(endpoint.description) + buf = Buffer(endpoint.description, + pipe_valid=pipe_valid, + pipe_ready=pipe_ready + ) submodule.submodules += buf submodule.comb += endpoint.connect(buf.sink) setattr(submodule, name, buf.source) From b2e4b221456a4b66b2bc17c4e4354581f5f0a1b5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 30 Jul 2023 15:12:01 +0200 Subject: [PATCH 132/454] soc/add_pcie: Add with_ptm parameter and update CHANGES. --- CHANGES.md | 1 + litex/soc/integration/soc.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 13913636d..dfa194fde 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -51,6 +51,7 @@ - liteeth_gen : Added raw UDP port support. - build/vivado : Added .dcp generation also after synthesis and placement. - gen: : Added initial LiteXContext to easily get build properties (platform, device, toolchain, etc...) + - litepcie/endpoint/tlp : Added optional Configuration/PTM TLP support to Packetizer/Depacketizer. [> Changed ---------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index fc749cb8e..b13066daf 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -2001,6 +2001,7 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre with_dma_monitor = False, with_dma_status = False, with_msi = True, msi_type="msi", msi_width=32, + with_ptm = False, ): # Imports from litepcie.phy.uspciephy import USPCIEPHY @@ -2017,7 +2018,8 @@ def add_pcie(self, name="pcie", phy=None, ndmas=0, max_pending_requests=8, addre endpoint = LitePCIeEndpoint(phy, max_pending_requests = max_pending_requests, endianness = phy.endianness, - address_width = address_width + address_width = address_width, + with_ptm = with_ptm, ) self.add_module(name=f"{name}_endpoint", module=endpoint) From 1a74854e553a96598bb7e9a57db65efbcfac6f17 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sun, 30 Jul 2023 15:37:51 +0200 Subject: [PATCH 133/454] litex_setup: fix software build when liteeth or/and litesata is set (riscv toolchain issue) --- litex_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex_setup.py b/litex_setup.py index 5956d0668..342dda5a1 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -350,7 +350,7 @@ def riscv_gcc_install(): os.system("pacman -S riscv64-linux-gnu-gcc") # Ubuntu. else: - os.system("apt install gcc-riscv64-linux-gnu") + os.system("apt install gcc-riscv64-unknown-elf") # Mac OS. # ------- From bf79c9032a1e5199c660bdef4871ea8afce49623 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 11:27:47 +0200 Subject: [PATCH 134/454] gen/genlib/misc/WaitTimer: Cast t to int and minor cosmetic cleanup. --- litex/gen/genlib/misc.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/litex/gen/genlib/misc.py b/litex/gen/genlib/misc.py index a44ef6d39..b39077860 100644 --- a/litex/gen/genlib/misc.py +++ b/litex/gen/genlib/misc.py @@ -80,12 +80,20 @@ def __init__(self, t): # # # + # Cast t to int. + t = int(t) count = Signal(bits_for(t), reset=t) + self.comb += self.done.eq(count == 0) - self.sync += \ + self.sync += [ If(self.wait, - If(~self.done, count.eq(count - 1)) - ).Else(count.eq(count.reset)) + If(~self.done, + count.eq(count - 1) + ) + ).Else( + count.eq(count.reset) + ) + ] class BitSlip(Module): From e257ff916f34b9041fa0108761a3cd77089dc2ee Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 11:32:48 +0200 Subject: [PATCH 135/454] soc/cores/interconnect: Rely on WaitTimer's new automatic cast to int. --- litex/soc/cores/esc.py | 10 +++++----- litex/soc/cores/hyperbus.py | 2 +- litex/soc/cores/led.py | 12 ++++++------ litex/soc/cores/uart.py | 4 ++-- litex/soc/interconnect/axi/axi_full.py | 4 ++-- litex/soc/interconnect/axi/axi_lite.py | 4 ++-- litex/soc/interconnect/wishbone.py | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/litex/soc/cores/esc.py b/litex/soc/cores/esc.py index 573f47efd..21901aa9f 100644 --- a/litex/soc/cores/esc.py +++ b/litex/soc/cores/esc.py @@ -141,15 +141,15 @@ def __init__(self, pad, sys_clk_freq, protocol="D150"): timings.compute() # Timers. - t0h_timer = WaitTimer(int(timings.t0h*sys_clk_freq)) - t0l_timer = WaitTimer(int(timings.t0l*sys_clk_freq) - 1) # Compensate Xfer FSM latency. + t0h_timer = WaitTimer(timings.t0h*sys_clk_freq) + t0l_timer = WaitTimer(timings.t0l*sys_clk_freq - 1) # Compensate Xfer FSM latency. self.submodules += t0h_timer, t0l_timer - t1h_timer = WaitTimer(int(timings.t1h*sys_clk_freq)) - t1l_timer = WaitTimer(int(timings.t1l*sys_clk_freq) - 1) # Compensate Xfer FSM latency. + t1h_timer = WaitTimer(timings.t1h*sys_clk_freq) + t1l_timer = WaitTimer(timings.t1l*sys_clk_freq - 1) # Compensate Xfer FSM latency. self.submodules += t1h_timer, t1l_timer - tgap_timer = WaitTimer(int(timings.tgap*sys_clk_freq)) + tgap_timer = WaitTimer(timings.tgap*sys_clk_freq) self.submodules += tgap_timer # XFER FSM. diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index cb19385a5..f6c743c4e 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -66,7 +66,7 @@ def __init__(self, pads, latency=6, sys_clk_freq=None): # Burst Timer ------------------------------------------------------------------------------ sys_clk_freq = 10e6 if sys_clk_freq is None else sys_clk_freq - burst_timer = WaitTimer(int(sys_clk_freq*self.tCSM)) + burst_timer = WaitTimer(sys_clk_freq*self.tCSM) self.burst_timer = burst_timer # Clock Generation (sys_clk/4) ------------------------------------------------------------- diff --git a/litex/soc/cores/led.py b/litex/soc/cores/led.py index 94f45385e..7ac782d4c 100644 --- a/litex/soc/cores/led.py +++ b/litex/soc/cores/led.py @@ -32,7 +32,7 @@ def __init__(self, pads, sys_clk_freq, period=1e0, polarity=0): chaser = Signal(self.n) mode = Signal(reset=_CHASER_MODE) - timer = WaitTimer(int(period*sys_clk_freq/(2*self.n))) + timer = WaitTimer(period*sys_clk_freq/(2*self.n)) leds = Signal(self.n) self.submodules += timer self.comb += timer.wait.eq(~timer.done) @@ -165,15 +165,15 @@ def __init__(self, pad, nleds, sys_clk_freq, bus_mastering=False, bus_base=None, self.t1l = t1l = 0.45e-6 # Timers. - trst_timer = WaitTimer(int(trst*sys_clk_freq)) + trst_timer = WaitTimer(trst*sys_clk_freq) self.submodules += trst_timer - t0h_timer = WaitTimer(int(t0h*sys_clk_freq)) - t0l_timer = WaitTimer(int(t0l*sys_clk_freq) - 1) # Compensate Xfer FSM latency. + t0h_timer = WaitTimer(t0h*sys_clk_freq) + t0l_timer = WaitTimer(t0l*sys_clk_freq - 1) # Compensate Xfer FSM latency. self.submodules += t0h_timer, t0l_timer - t1h_timer = WaitTimer(int(t1h*sys_clk_freq)) - t1l_timer = WaitTimer(int(t1l*sys_clk_freq) - 1) # Compensate Xfer FSM latency. + t1h_timer = WaitTimer(t1h*sys_clk_freq) + t1l_timer = WaitTimer(t1l*sys_clk_freq - 1) # Compensate Xfer FSM latency. self.submodules += t1h_timer, t1l_timer # Main FSM. diff --git a/litex/soc/cores/uart.py b/litex/soc/cores/uart.py index 6ca6d4196..723337897 100644 --- a/litex/soc/cores/uart.py +++ b/litex/soc/cores/uart.py @@ -293,7 +293,7 @@ def add_auto_tx_flush(self, sys_clk_freq, timeout=1e-2, interval=2): # Flush TX FIFO when Source.ready is inactive for timeout (with interval cycles between # each ready). - self.timer = timer = WaitTimer(int(timeout*sys_clk_freq)) + self.timer = timer = WaitTimer(timeout*sys_clk_freq) self.comb += timer.wait.eq(~self.source.ready) self.sync += flush_count.eq(flush_count + 1) self.comb += If(timer.done, flush_ep.ready.eq(flush_count == 0)) @@ -330,7 +330,7 @@ def __init__(self, phy=None, clk_freq=None, data_width=32, address_width=32): words_count_done = (words_count == (length - 1)) self.fsm = fsm = ResetInserter()(FSM(reset_state="RECEIVE-CMD")) - self.timer = timer = WaitTimer(int(100e-3*clk_freq)) + self.timer = timer = WaitTimer(100e-3*clk_freq) self.comb += timer.wait.eq(~fsm.ongoing("RECEIVE-CMD")) self.comb += fsm.reset.eq(timer.done) fsm.act("RECEIVE-CMD", diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index e3cdd4af7..bc887ac34 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -371,8 +371,8 @@ def __init__(self, master, cycles): self.comb += self.error.eq(wr_error | rd_error) - wr_timer = WaitTimer(int(cycles)) - rd_timer = WaitTimer(int(cycles)) + wr_timer = WaitTimer(cycles) + rd_timer = WaitTimer(cycles) self.submodules += wr_timer, rd_timer def channel_fsm(timer, wait_cond, error, response): diff --git a/litex/soc/interconnect/axi/axi_lite.py b/litex/soc/interconnect/axi/axi_lite.py index 595eaf50a..26bb1dd46 100644 --- a/litex/soc/interconnect/axi/axi_lite.py +++ b/litex/soc/interconnect/axi/axi_lite.py @@ -525,8 +525,8 @@ def __init__(self, master, cycles): self.comb += self.error.eq(wr_error | rd_error) - wr_timer = WaitTimer(int(cycles)) - rd_timer = WaitTimer(int(cycles)) + wr_timer = WaitTimer(cycles) + rd_timer = WaitTimer(cycles) self.submodules += wr_timer, rd_timer def channel_fsm(timer, wait_cond, error, response): diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index ce8e63314..5d426c997 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -130,7 +130,7 @@ def __init__(self, master, cycles): # # # - timer = WaitTimer(int(cycles)) + timer = WaitTimer(cycles) self.submodules += timer self.comb += [ timer.wait.eq(master.stb & master.cyc & ~master.ack), From cb06949604247a68a93c6cdd1746d5369f7b7400 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 17:59:18 +0200 Subject: [PATCH 136/454] soc/add_etherbone: Expose arp_entries parameter. --- litex/soc/integration/soc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index b13066daf..b46bfb68f 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1709,6 +1709,7 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, mac_address = 0x10e2d5000000, ip_address = "192.168.1.50", + arp_entries = 1, udp_port = 1234, buffer_depth = 16, with_ip_broadcast = True, @@ -1727,6 +1728,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, mac_address = mac_address, ip_address = ip_address, clk_freq = self.clk_freq, + arp_entries = arp_entries, dw = data_width, with_ip_broadcast = with_ip_broadcast, with_sys_datapath = with_sys_datapath, From 87e2456274a1be0b49a3ea19db66ff8703840665 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 18:00:43 +0200 Subject: [PATCH 137/454] CHANGES.md: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index dfa194fde..297133d44 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ - litepcie/US(P) : Fixed root cause of possible MSI deadlock. - soc/add_uart : Fixed stub behavior (sink/source swap). - build/efinix : Fixed AsyncFIFO issues (Minimum of 2 buffer stages). + - software/gcc : Fixed Ubuntu 22.04 GCC compilation issues. [> Added -------- @@ -52,6 +53,7 @@ - build/vivado : Added .dcp generation also after synthesis and placement. - gen: : Added initial LiteXContext to easily get build properties (platform, device, toolchain, etc...) - litepcie/endpoint/tlp : Added optional Configuration/PTM TLP support to Packetizer/Depacketizer. + - liteth/arp : Added proper multi-entries ARP table. [> Changed ---------- From bfd4dcdefca9fe8ca595ab1da2ea103160feb5fb Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 1 Aug 2023 16:52:20 +0200 Subject: [PATCH 138/454] interconnect/ahb: Cleanup and document a bit. --- litex/soc/interconnect/ahb.py | 98 +++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 39 deletions(-) diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index d791d2958..98ae407b4 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -1,67 +1,87 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2021 Ilia Sergachev +# Copyright (c) 2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +"""AHB support for LiteX""" + from enum import IntEnum + from migen import * +from litex.gen import * + +# Helpers ------------------------------------------------------------------------------------------ class TransferType(IntEnum): - IDLE = 0 - BUSY = 1 + """Defines types of AHB transfers.""" + IDLE = 0 + BUSY = 1 NONSEQUENTIAL = 2 - SEQUENTIAL = 3 + SEQUENTIAL = 3 +# AHB Interface ------------------------------------------------------------------------------------ class Interface(Record): - adr_width = 32 - data_width = 32 - + """Sets up the AHB interface signals for master and slave.""" + adr_width = 32 + data_width = 32 master_signals = [ - ('addr', adr_width), - ('burst', 3), - ('mastlock', 1), - ('prot', 4), - ('size', 3), - ('trans', 2), - ('wdata', data_width), - ('write', 1), - ('sel', 1), + ("addr", adr_width), + ("burst", 3), + ("mastlock", 1), + ("prot", 4), + ("size", 3), + ("trans", 2), + ("wdata", data_width), + ("write", 1), + ("sel", 1), ] - slave_signals = [ - ('rdata', data_width), - ('readyout', 1), - ('resp', 1), + ("rdata", data_width), + ("readyout", 1), + ("resp", 1), ] - def __init__(self): Record.__init__(self, set_layout_parameters(self.master_signals + self.slave_signals)) +# AHB to Wishbone --------------------------------------------------------------------------------- + +class AHB2Wishbone(LiteXModule): + """ + This module converts AHB protocol transactions to the Wishbone protocol. -class AHB2Wishbone(Module): + It takes as input an AHB interface and a Wishbone interface and does the conversion. + """ def __init__(self, ahb, wishbone): - wb = wishbone wishbone_adr_shift = log2_int(ahb.data_width // 8) - assert ahb.data_width == wb.data_width - assert ahb.adr_width == wb.adr_width + wishbone_adr_shift + assert ahb.data_width == wishbone.data_width + assert ahb.adr_width == wishbone.adr_width + wishbone_adr_shift - self.comb += [ - ahb.resp.eq(wb.err), - ] + self.comb += ahb.resp.eq(wishbone.err) - self.submodules.fsm = fsm = FSM() + self.fsm = fsm = FSM() fsm.act("IDLE", ahb.readyout.eq(1), - If(ahb.sel & (ahb.size == wishbone_adr_shift) & (ahb.trans == TransferType.NONSEQUENTIAL), - NextValue(wb.adr, ahb.addr[2:]), - NextValue(wb.dat_w, ahb.wdata), - NextValue(wb.we, ahb.write), - NextValue(wb.sel, 2 ** len(wb.sel) - 1), - NextState('ACT'), + If(ahb.sel & + (ahb.size == wishbone_adr_shift) & + (ahb.trans == TransferType.NONSEQUENTIAL), + NextValue(wishbone.adr, ahb.addr[2:]), + NextValue(wishbone.dat_w, ahb.wdata), + NextValue(wishbone.we, ahb.write), + NextValue(wishbone.sel, 2**len(wishbone.sel) - 1), + NextState("ACT"), ) ) fsm.act("ACT", - wb.stb.eq(1), - wb.cyc.eq(1), - If(wb.ack, - If(~wb.we, NextValue(ahb.rdata, wb.dat_r)), - NextState("IDLE") + wishbone.stb.eq(1), + wishbone.cyc.eq(1), + If(wishbone.ack, + If(~wishbone.we, + NextValue(ahb.rdata, wishbone.dat_r) + ), + NextState("IDLE") ) ) From 587981a6b81a0124a5904df86fe29bda46d4d78c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 1 Aug 2023 17:11:13 +0200 Subject: [PATCH 139/454] interconnect/csr_bus: Improve description. --- litex/soc/interconnect/csr_bus.py | 39 ++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/litex/soc/interconnect/csr_bus.py b/litex/soc/interconnect/csr_bus.py index 00a40b7ee..707ae0952 100644 --- a/litex/soc/interconnect/csr_bus.py +++ b/litex/soc/interconnect/csr_bus.py @@ -2,16 +2,34 @@ # This file is part of LiteX. # # Copyright (c) 2015 Sebastien Bourdeauducq -# Copyright (c) 2015-2018 Florent Kermarrec +# Copyright (c) 2015-2023 Florent Kermarrec # Copyright (c) 2016-2019 Tim 'mithro' Ansell # SPDX-License-Identifier: BSD-2-Clause """ -CSR-2 bus -========= +CSR-Bus support for LiteX. -The CSR-2 bus is a low-bandwidth, resource-sensitive bus designed for accessing -the configuration and status registers of cores from software. +The CSR Bus is a lightweight and low-bandwidth bus design for accessing Configuration and Status +Registers (CSRs). + +It takes a minimalist approach, featuring only adr, we, dat_w, and dat_r signals and operate on +sys_clk domain of the SoC, completing writes in a single cycle and reads in two cycles. + + ┌───────────┐ Write in 1 cycle: + │ │ - adr/we/dat_w set by bridge. + │ ├───► adr + │ │ Read in 2 cycles: + Main SoC Bus ◄────► CSR ├───► we - adr set by bridge + │ Bridge │ - dat_r set returned by user logic. + │ ├───► dat_w + │ │ + │ ◄──── dat_r + └───────────┘ + +Think of it as LiteX's version of a local bus usually used in FPGA/SoC design to simplify creation +of registers in SoCs. + +More information available at: https://github.com/enjoy-digital/litex/wiki/CSR-Bus """ from migen import * @@ -33,7 +51,6 @@ ("dat_r", "data_width", DIR_S_TO_M) ] - class Interface(Record): def __init__(self, data_width=8, address_width=14, alignment=32): self.data_width = data_width @@ -41,15 +58,18 @@ def __init__(self, data_width=8, address_width=14, alignment=32): self.alignment = alignment Record.__init__(self, set_layout_parameters(_layout, data_width = data_width, - address_width = address_width)) + address_width = address_width, + )) self.adr.reset_less = True self.dat_w.reset_less = True self.dat_r.reset_less = True @classmethod def like(self, other): - return Interface(len(other.dat_w), - len(other.adr)) + return Interface( + data_width = len(other.dat_w), + address_width = len(other.adr), + ) def write(self, adr, dat): yield self.adr.eq(adr) @@ -204,6 +224,7 @@ def __init__(self, description, address=0, bus=None, paging=0x800, ordering="big # Otherwise, it is a memory object belonging to source.name. # address_map is called exactly once for each object at each call to # scan(), so it can have side effects. + class CSRBankArray(Module): def __init__(self, source, address_map, *ifargs, paging=0x800, ordering="big", **ifkwargs): self.source = source From 036193d046e23e8933735ed1eb0cbf5444994db1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 4 Aug 2023 16:08:00 +0200 Subject: [PATCH 140/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 297133d44..57cc6ec54 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -54,6 +54,7 @@ - gen: : Added initial LiteXContext to easily get build properties (platform, device, toolchain, etc...) - litepcie/endpoint/tlp : Added optional Configuration/PTM TLP support to Packetizer/Depacketizer. - liteth/arp : Added proper multi-entries ARP table. + - liteiclink/serdes : Added tx/rx_clk sharing capabilities on Xilinx transceivers. [> Changed ---------- From 688dae01128e655cd8173e2fb47fffd77abf4c8e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 4 Aug 2023 17:24:51 +0200 Subject: [PATCH 141/454] cores/spi: Add new SPIMMAP core allowing doing SPI accesses directly from MMAP. Implements a new SPIMMAP module, allowing accessing multiple SPI peripherals directly from MMAP. It allows configurable SPI transactions: mode, bit order, and data width. Developed and funded through a collaboration with MoTeC. Example of integration: # SPI MMAP --------------------------------------------------------------------------------- spi_pads = Record([("clk", 1), ("cs_n", 8), ("mosi", 1), ("miso", 1)]) spi_mmap_tx_region = SoCRegion(origin=0x8000_0000, size=4096, cached=False) spi_mmap_rx_region = SoCRegion(origin=0x8000_1000, size=4096, cached=False) self.spi_mmap = SPIMMAP( pads = spi_pads, data_width = 32, sys_clk_freq = sys_clk_freq, tx_origin = spi_mmap_tx_region.origin, rx_origin = spi_mmap_rx_region.origin, tx_fifo_depth = 32, rx_fifo_depth = 32, ) self.bus.add_slave(name="spi_tx", slave = self.spi_mmap.tx_mmap.bus, region = spi_mmap_tx_region, ) self.bus.add_slave(name="spi_rx", slave = self.spi_mmap.rx_mmap.bus, region = spi_mmap_rx_region, ) self.irq.add("spi_mmap", use_loc_if_exists=True) Example of use from CPU C firmware: /* SPI TX Offsets */ #define SPI_TX_CTRL_ENABLE (1 << 0) #define SPI_TX_CTRL_THRESHOLD (1 << 16) #define SPI_TX_STAT_ONGOING (1 << 0) #define SPI_TX_STAT_EMPTY (1 << 1) #define SPI_TX_STAT_FULL (1 << 2) #define SPI_TX_STAT_LEVEL (1 << 16) /* SPI RX Offsets */ #define SPI_RX_CTRL_ENABLE (1 << 0) #define SPI_RX_CTRL_THRESHOLD (1 << 16) #define SPI_RX_STAT_ONGOING (1 << 0) #define SPI_RX_STAT_EMPTY (1 << 1) #define SPI_RX_STAT_FULL (1 << 2) #define SPI_RX_STAT_LEVEL (1 << 16) /* SPI TX/RX Engine */ #define SPI_TX_RX_ENGINE_ENABLE (1 << 0) /* SPI SLOT Offsets */ #define SPI_SLOT_ENABLE (1 << 0) #define SPI_SLOT_MODE (1 << 1) #define SPI_SLOT_LENGTH (1 << 3) #define SPI_SLOT_BITORDER (1 << 5) #define SPI_SLOT_LOOPBACK (1 << 6) #define SPI_SLOT_DIVIDER (1 << 16) /* SPI SLOT Values */ #define SPI_SLOT_MODE_0 0b00 #define SPI_SLOT_MODE_3 0b11 #define SPI_SLOT_LENGTH_32B 0b00 #define SPI_SLOT_LENGTH_16B 0b01 #define SPI_SLOT_LENGTH_8B 0b10 #define SPI_SLOT_BITORDER_MSB_FIRST 0b0 #define SPI_SLOT_BITORDER_LSB_FIRST 0b1 #define SPI_SLOT_EV_TX (1 << 0) #define SPI_SLOT_EV_RX (1 << 1) /* Test SPI with various length (BE) */ void test_spi_length_8_16_32(void) { volatile unsigned char *spi_tx_8 = (unsigned char *)SPI_TX_BASE; volatile unsigned short *spi_tx_16 = (unsigned short *)SPI_TX_BASE; volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned char *spi_rx_8 = (unsigned char *)SPI_RX_BASE; volatile unsigned short *spi_rx_16 = (unsigned short *)SPI_RX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various length (BE): 8, 16 and 32-bit...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control2_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control3_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 8-bit transfers */ spi_tx_8[0] = 0x5a; spi_tx_8[4] = 0x01; spi_tx_8[8] = 0x5a; spi_tx_8[12] = 0x01; /* TX 16-bit transfers */ spi_tx_16[0] = 0x5aa5; spi_tx_16[2] = 0x0102; spi_tx_16[4] = 0x5aa5; spi_tx_16[6] = 0x0102; /* TX 32-bit transfers */ spi_tx_32[0] = 0x5aa55aa5; spi_tx_32[1] = 0x01020304; spi_tx_32[2] = 0x5aa55aa5; spi_tx_32[3] = 0x01020304; /* Small delay */ busy_wait(1); /* Read RX 8-bit transfers */ if (spi_rx_8[ 0] != 0x5a) errors++; if (spi_rx_8[ 4] != 0x01) errors++; if (spi_rx_8[ 8] != 0x5a) errors++; if (spi_rx_8[12] != 0x01) errors++; /* Read RX 16-bit transfers */ if (spi_rx_16[0] != 0x5aa5) errors++; if (spi_rx_16[2] != 0x0102) errors++; if (spi_rx_16[4] != 0x5aa5) errors++; if (spi_rx_16[6] != 0x0102) errors++; /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x5aa55aa5) errors++; if (spi_rx_32[1] != 0x01020304) errors++; if (spi_rx_32[2] != 0x5aa55aa5) errors++; if (spi_rx_32[3] != 0x01020304) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI with various clk divider */ void test_spi_clk_divider(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various clk divider: 4, 8, 16 and 32...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 8 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control2_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 16 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control3_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 32 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x01020304; spi_tx_32[1] = 0x5aa55aa5; spi_tx_32[2] = 0x01020304; spi_tx_32[3] = 0x5aa55aa5; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x01020304) errors++; if (spi_rx_32[1] != 0x5aa55aa5) errors++; if (spi_rx_32[2] != 0x01020304) errors++; if (spi_rx_32[3] != 0x5aa55aa5) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI with various SPI modes */ void test_spi_modes(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various SPI modes: 0 and 3...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_3 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x5aa55aa5; spi_tx_32[1] = 0x5aa55aa5; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x5aa55aa5) errors++; if (spi_rx_32[1] != 0x5aa55aa5) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI with various bitorders */ void test_spi_bitorders(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various bitorders: MSB and LSB first...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_LSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0xff000000; spi_tx_32[1] = 0xff000000; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0xff000000) errors++; if (spi_rx_32[1] != 0xff000000) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI TX/RX levels */ void test_spi_tx_rx_levels(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int i; int errors = 0; int pattern; printf("Test SPI TX/RX levels...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 128 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ pattern = 0x00000001; for (i=0; i<16; i++){ if ((spi_mmap_ctrl_tx_status_read() >> 16) != i) errors++; spi_tx_32[0] = pattern; } /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ for (i=0; i<16; i++){ pattern = spi_rx_32[0]; if ((spi_mmap_ctrl_rx_status_read() >> 16) != (16-1-i)) errors++; } if ((spi_mmap_ctrl_tx_status_read() >> 16) != 0) errors++; if ((spi_mmap_ctrl_rx_status_read() >> 16) != 0) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI TX/RX IRQs */ void test_spi_tx_rx_irqs(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; int data __attribute__((unused)); printf("Test SPI TX/RX IRQs...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 128 * SPI_SLOT_DIVIDER ); /* Enable TX/RX EventManager */ spi_mmap_ev_enable_write(0); spi_mmap_ev_pending_write(spi_mmap_ev_pending_read()); spi_mmap_ev_enable_write(SPI_SLOT_EV_TX | SPI_SLOT_EV_RX); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x00000001; /* Small delay */ busy_wait(1); /* Verify TX/RX events */ if (spi_mmap_ev_pending_read() != (SPI_SLOT_EV_TX | SPI_SLOT_EV_RX)) errors++; /* Read RX 32-bit tranfers */ data = spi_rx_32[0]; /* Clear events */ spi_mmap_ev_pending_write(spi_mmap_ev_pending_read()); /* Verify TX/RX events */ if (spi_mmap_ev_pending_read() != 0) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI Back-to-Back */ void test_spi_back_to_back(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI Back-to-Back...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 8 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x00000001; spi_tx_32[0] = 0x00000002; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x00000001) errors++; if (spi_rx_32[0] != 0x00000002) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } --- CHANGES.md | 1 + litex/soc/cores/spi/spi_mmap.py | 698 ++++++++++++++++++++++++++++++++ 2 files changed, 699 insertions(+) create mode 100644 litex/soc/cores/spi/spi_mmap.py diff --git a/CHANGES.md b/CHANGES.md index 57cc6ec54..412c1eade 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -55,6 +55,7 @@ - litepcie/endpoint/tlp : Added optional Configuration/PTM TLP support to Packetizer/Depacketizer. - liteth/arp : Added proper multi-entries ARP table. - liteiclink/serdes : Added tx/rx_clk sharing capabilities on Xilinx transceivers. + - soc/cores/spi : Added new SPIMMAP core allowing SPI accesses through MMAP. [> Changed ---------- diff --git a/litex/soc/cores/spi/spi_mmap.py b/litex/soc/cores/spi/spi_mmap.py new file mode 100644 index 000000000..77ced6bcd --- /dev/null +++ b/litex/soc/cores/spi/spi_mmap.py @@ -0,0 +1,698 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2022-2023 MoTeC +# Copyright (c) 2022-2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +from litex.gen import * +from litex.gen.genlib.misc import WaitTimer + +from litex.soc.interconnect.csr import * +from litex.soc.interconnect.csr_eventmanager import * +from litex.soc.interconnect import stream +from litex.soc.interconnect import wishbone + +# Constants / Layouts / Helpers -------------------------------------------------------------------- + +_nslots_max = 16 + +# SPI Layout +def spi_layout(data_width=32, be_width=4, cs_width=1): + return [ + ("data", data_width), + ("be", be_width), + ("cs", cs_width) + ] + +# SPI Slot Constants. + +SPI_SLOT_MODE_0 = 0b00 +SPI_SLOT_MODE_3 = 0b11 + +SPI_SLOT_LENGTH_32B = 0b00 +SPI_SLOT_LENGTH_16B = 0b01 +SPI_SLOT_LENGTH_8B = 0b10 + +SPI_SLOT_BITORDER_MSB_FIRST = 0b0 +SPI_SLOT_BITORDER_LSB_FIRST = 0b1 + +# SPI Master --------------------------------------------------------------------------------------- + +class SPIMaster(LiteXModule): + """4-wire SPI Master + + Provides a simple and minimal hardware SPI Master with Mode0 to Mode3 support. + """ + def __init__(self, pads, data_width, sys_clk_freq, clk_settle_time=20e-9): + # Config. + self.loopback = Signal() + self.clk_divider = Signal(16) + self.mode = Signal(2) + + # Interface. + self.start = Signal() + self.length = Signal(8) + self.done = Signal() + self.irq = Signal() + self.mosi = Signal(data_width) + self.miso = Signal(data_width) + self.cs = Signal(len(pads.cs_n)) + + # # # + + # Signals ---------------------------------------------------------------------------------- + # CPHA — SPI Clock Phase Bit + # 1 = Sampling of data at even edges (2,4,6,...,16) of the SCK clock + # 0 = Sampling of data at odd edges (1,3,5,...,15) of the SCK clock + cpha = self.mode[0] + # CPOL — SPI Clock Polarity Bit + # 1 = Active-low. In idle state SCK is high: odd edges are falling + # 0 = Active-high. In idle state SCK is low: odd edges are rising + cpol = self.mode[1] + + clk = Signal() + clk_d = Signal() + clk_enable = Signal() + clk_run = Signal() + clk_count = Signal(16) + clk_odd = Signal() + clk_even = Signal() + + data_count = Signal(8) + + mosi_shift = Signal() + mosi_data = Signal(data_width) + + miso = Signal() + miso_shift = Signal() + miso_data = Signal(data_width) + + # Chip Select generation ------------------------------------------------------------------- + + self.sync += pads.cs_n.eq(~self.cs) + # TODO: need to guarantee cs_n remains asserted for 1/2 SCK after edge 16 + # at the end of a transfer, however next byte for this transfer can start + # in this region + + # Clk Generation --------------------------------------------------------------------------- + + clk_settle = WaitTimer(int(sys_clk_freq*clk_settle_time)) + self.submodules += clk_settle + + clk_fsm = FSM(reset_state="IDLE") + self.submodules += clk_fsm + clk_fsm.act("IDLE", + If(self.start, + NextState("SETTLE") + ) + ) + clk_fsm.act("SETTLE", + clk_settle.wait.eq(1), + If(clk_settle.done, + NextState("RUN") + ) + ) + clk_fsm.act("RUN", + clk_enable.eq(1), + If(self.done, + NextState("IDLE") + ) + ) + self.sync += [ + If(clk_enable, + clk_count.eq(clk_count + 1), + If(clk_count == self.clk_divider[2:], + clk.eq(~clk), + clk_count.eq(0) + ), + If(clk_odd, + clk_run.eq(1)) + ).Else( + clk.eq(0), + clk_count.eq(0), + clk_run.eq(0) + ) + ] + self.comb += pads.clk.eq((clk & ~self.done) ^ cpol) + self.sync += clk_d.eq(clk) + self.comb += [ + If(clk_enable, + clk_odd.eq( clk & ~clk_d), + clk_even.eq(~clk & clk_d), + ) + ] + + # Master FSM ------------------------------------------------------------------------------- + + self.master_fsm = master_fsm = FSM(reset_state="IDLE") + master_fsm.act("IDLE", + self.done.eq(1), + If(self.start, + self.done.eq(0), + NextState("RUN") + ), + NextValue(data_count, 0), + ) + master_fsm.act("RUN", + clk_enable.eq(1), + # regardless of CPHA update data_count on even edge + If(clk_even, + NextValue(data_count, data_count + 1), + If(data_count == (self.length - 1), + self.irq.eq(1), + NextState("IDLE") + ) + ) + ) + + # Master Out Slave In (MOSI) generation ---------------------------------------------------- + # - Shift on clk odd edge (** but not the first one **) for: + # - Mode 1 & 3 (CPHA=1) + # - Shift on clk even edge for: + # - Mode 0 & 2 (CPHA=0) + + self.comb += Case(cpha, { + 0b0 : mosi_shift.eq(clk_even), + 0b1 : mosi_shift.eq(clk_odd & clk_run), + }) + self.sync += [ + If(self.start, + mosi_data.eq(self.mosi) + ).Elif(mosi_shift, + mosi_data.eq(Cat(Signal(), mosi_data)) + ), + ] + self.comb += pads.mosi.eq(mosi_data[-1]) + + # Master In Slave Out (MISO) capture ------------------------------------------------------- + # - Clocked out by slave on odd edge, so captured on even edge for: + # - Mode 1 & 3 (CPHA=1) + # - Clocked out by slave on even edge, so captured on odd edge for: + # - Mode 0 & 2 (CPHA=0) + # NOTE: The data capture should occur on the subsequent clock edge. E.g. for CPHA=1, + # falling clock edge is bit of data clocked out. On the subsequent raising + # edge the MISO data should be captured. + + self.comb += Case(cpha, { + 0b0 : miso_shift.eq(clk_odd), + 0b1 : miso_shift.eq(clk_even), + }) + self.comb += Case(self.loopback, { + 0b0 : miso.eq(pads.miso), + 0b1 : miso.eq(pads.mosi), + }) + self.sync += [ + If(miso_shift, + miso_data.eq(Cat(miso, miso_data)) + ) + ] + self.comb += self.miso.eq(miso_data) + +# SPI FIFO ----------------------------------------------------------------------------------------- + +@ResetInserter() +class SPIFIFO(LiteXModule): + def __init__(self, data_width=32, nslots=1, depth=32): + self.fifo = stream.SyncFIFO(layout=spi_layout( + data_width = data_width, + be_width = data_width//8, + cs_width = nslots + ), depth=depth, buffered=True) + for name in ["level", "sink", "source"]: + setattr(self, name, getattr(self.fifo, name)) + +# SPI Ctrl ----------------------------------------------------------------------------------------- + +class SPICtrl(LiteXModule): + autocsr_exclude = {"ev"} + def __init__(self, nslots=1, + # TX. + default_tx_enable = 0b1, + # RX. + default_rx_enable = 0b1, + # Slots. + default_slot_enable = 0b1, + default_slot_mode = SPI_SLOT_MODE_3, + default_slot_length = SPI_SLOT_LENGTH_32B, + default_slot_bitorder = SPI_SLOT_BITORDER_MSB_FIRST, + default_slot_loopback = 0b1, + default_slot_divider = 2, + ): + self.nslots = nslots + self.slot_controls = [] + self.slot_status = [] + + # Create TX/RX Control/Status registers. + self.tx_control = CSRStorage(fields=[ + CSRField("enable", size=1, offset=0, values=[ + ("``0b0``", "TX Disabled."), + ("``0b1``", "TX Enabled."), + ], reset=default_tx_enable), + CSRField("threshold", size=16, offset=16, description="TX_FIFO IRQ Threshold.", reset=0) + ]) + self.tx_status = CSRStatus(fields=[ + CSRField("ongoing", size=1, offset=0, values=[ + ("``0b0``", "TX Xfer idle."), + ("``0b1``", "TX Xfer ongoing."), + ]), + CSRField("empty", size=1, offset=1, values=[ + ("``0b0``", "TX FIFO Empty."), + ("``0b1``", "TX FIFO Empty."), + ]), + CSRField("full", size=1, offset=2, values=[ + ("``0b0``", "TX FIFO Full."), + ("``0b1``", "TX FIFO Full."), + ]), + CSRField("level", size=16, offset=16, description="TX FIFO Level.") + ]) + self.rx_control = CSRStorage(fields=[ + CSRField("enable", size=1, offset=0, values=[ + ("``0b0``", "RX Disabled."), + ("``0b1``", "RX Enabled."), + ], reset=default_rx_enable), + CSRField("threshold", size=16, offset=16, description="RX_FIFO IRQ Threshold.", reset=0) + ]) + self.rx_status = CSRStatus(fields=[ + CSRField("ongoing", size=1, offset=0, values=[ + ("``0b0``", "RX Xfer idle."), + ("``0b1``", "RX Xfer ongoing."), + ]), + CSRField("empty", size=1, offset=1, values=[ + ("``0b0``", "RX FIFO Empty."), + ("``0b1``", "RX FIFO Empty."), + ]), + CSRField("full", size=1, offset=2, values=[ + ("``0b0``", "RX FIFO Full."), + ("``0b1``", "RX FIFO Full."), + ]), + CSRField("level", size=16, offset=16, description="RX FIFO Level.") + ]) + + # Create IRQ registers. + self.ev = EventManager() + self.ev.tx = EventSourceProcess(edge="rising") + self.ev.rx = EventSourceProcess(edge="rising") + self.ev.finalize() + self.comb += [ + # TX IRQ when FIFO's level <= TX Threshold. + self.ev.tx.trigger.eq(self.tx_status.fields.level <= self.tx_control.fields.threshold), + # RX IRQ when FIFO's level > RX Threshold. + self.ev.rx.trigger.eq(self.rx_status.fields.level > self.rx_control.fields.threshold), + ] + + # Create Slots Control/Status registers. + for slot in range(nslots): + control = CSRStorage(name=f"slot_control{slot}", fields=[ + CSRField("enable", size=1, offset=0, values=[ + ("``0b0``", "Slot Disabled."), + ("``0b1``", "Slot Enabled."), + ], reset=default_slot_enable), + CSRField("mode", size=2, offset=1, values=[ + ("``0b00``", "SPI Mode 0 (CPOL=0, CPHA=0)."), + ("``0b01``", "SPI Mode 1 (CPOL=0, CPHA=1)."), + ("``0b10``", "SPI Mode 2 (CPOL=1, CPHA=0)."), + ("``0b11``", "SPI Mode 3 (CPOL=1, CPHA=1)."), + ], reset=default_slot_mode), + CSRField("length", size=2, offset=3, values=[ + ("``0b00``", "32-bit Max."), + ("``0b01``", "16-bit Max."), + ("``0b10``", " 8-bit Max."), + ("``0b11``", "Reserved."), + ], reset=default_slot_length), + CSRField("bitorder", size=1, offset=5, values=[ + ("``0b0``", "MSB-First."), + ("``0b1``", "LSB-First."), + ], reset=default_slot_bitorder), + CSRField("loopback", size=1, offset=6, values=[ + ("``0b0``", "Loopback Disabled."), + ("``0b1``", "Loopback Enabled."), + ], reset=default_slot_loopback), + CSRField("divider", size=16, offset=16, values=[ + ("``0x0000``", "Reserved."), + ("``0x0001``", "Reserved."), + ("``0x0002``", "SPI-Clk = Sys-Clk/2."), + ("``0x0004``", "SPI-Clk = Sys-Clk/4."), + ("``0xxxxx``", "SPI-Clk = Sys-Clk/xxxxx."), + ], reset=default_slot_divider) + ]) + status = CSRStatus(name=f"slot_status{slot}") # CHECKME: Useful? + setattr(self, f"slot_control{slot}", control) + setattr(self, f"slot_status{slot}", status) + self.slot_controls.append(control) + self.slot_status.append(status) + + def get_ctrl(self, name, slot=None, cs=None): + assert not ((slot is None) and (cs is None)) + if cs is None: + cs = Signal(self.nslots) + self.comb += cs.eq(1< Date: Fri, 4 Aug 2023 17:51:07 +0200 Subject: [PATCH 142/454] test: Add minimal test_spi_mmap with simulation of SPIMaster. --- test/test_spi_mmap.py | 103 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 test/test_spi_mmap.py diff --git a/test/test_spi_mmap.py b/test/test_spi_mmap.py new file mode 100644 index 000000000..8915eef23 --- /dev/null +++ b/test/test_spi_mmap.py @@ -0,0 +1,103 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2022-2023 MoTeC +# Copyright (c) 2022-2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import unittest +import random + +from migen import * + +from litex.gen.sim import * + +from litex.soc.cores.spi.spi_mmap import SPIMaster + +class TestSPIMMAP(unittest.TestCase): + def test_spi_master(self): + pads = Record([("clk", 1), ("cs_n", 4), ("mosi", 1), ("miso", 1)]) + dut = SPIMaster(pads=pads, data_width=32, sys_clk_freq=int(100e6)) + def generator(dut): + data = [ + 0x12345678, + 0xdeadbeef, + ] + #data = [ + # 0x80000001, + # 0x80000001, + #] + + # Config: Mode0, Loopback, Sys-Clk/4 + yield dut.loopback.eq(1) + yield dut.clk_divider.eq(4) + yield dut.mode.eq(0) + yield + yield dut.mosi.eq(data[0]) + yield dut.cs.eq(0b0001) + yield dut.length.eq(32) + yield dut.start.eq(1) + yield + yield dut.start.eq(0) + while (yield dut.done) == 0b0: + yield + yield dut.cs.eq(0b0000) + for i in range(16): + yield + print(f"mosi_data : {(yield dut.miso):08x}") + + # Config: Mode3, Loopback, Sys-Clk/4. + yield dut.loopback.eq(1) + yield dut.clk_divider.eq(4) + yield dut.mode.eq(3) + yield + yield dut.mosi.eq(data[0]) + yield dut.cs.eq(0b0001) + yield dut.length.eq(32) + yield dut.start.eq(1) + yield + yield dut.start.eq(0) + while (yield dut.done) == 0b0: + yield + yield dut.cs.eq(0b0000) + for i in range(16): + yield + print(f"mosi_data : {(yield dut.miso):08x}") + + # Config: Mode0, Loopback, Sys-Clk/8. + yield dut.loopback.eq(1) + yield dut.clk_divider.eq(8) + yield dut.mode.eq(0) + yield + yield dut.mosi.eq(data[1]) + yield dut.cs.eq(0b0001) + yield dut.length.eq(32) + yield dut.start.eq(1) + yield + yield dut.start.eq(0) + while (yield dut.done) == 0b0: + yield + yield dut.cs.eq(0b0000) + for i in range(16): + yield + print(f"mosi_data : {(yield dut.miso):08x}") + + # Config: Mode3, Loopback, Sys-Clk/8. + yield dut.loopback.eq(1) + yield dut.clk_divider.eq(8) + yield dut.mode.eq(3) + yield + yield dut.mosi.eq(data[1]) + yield dut.cs.eq(0b0001) + yield dut.length.eq(32) + yield dut.start.eq(1) + yield + yield dut.start.eq(0) + while (yield dut.done) == 0b0: + yield + yield dut.cs.eq(0b0000) + for i in range(16): + yield + print(f"mosi_data : {(yield dut.miso):08x}") + + run_simulation(dut, generator(dut), vcd_name="sim.vcd") From c1d8db396de9267cfdf1888a301bb8c2d7c3e746 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 11 Aug 2023 14:56:56 +0800 Subject: [PATCH 143/454] build/gowin/common: Fix DDRInput The DDRInput of Gowin seems to be never used and contains a typo that prevents it from being really used. Fix this typo. Signed-off-by: Icenowy Zheng --- litex/build/gowin/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/gowin/common.py b/litex/build/gowin/common.py index 5c58fffa7..395d8c66a 100644 --- a/litex/build/gowin/common.py +++ b/litex/build/gowin/common.py @@ -48,7 +48,7 @@ def __init__(self, i, o1, o2, clk): class GowinDDRInput: @staticmethod def lower(dr): - return GowinInputImpl(dr.i, dr.o1, dr.o2, dr.clk) + return GowinDDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk) # Gowin DDR Output --------------------------------------------------------------------------------- From cd1012470ef10929c633ac42096d274d22f32166 Mon Sep 17 00:00:00 2001 From: Alexey Morozov <31707428+alexey-morozov@users.noreply.github.com> Date: Wed, 16 Aug 2023 09:39:03 +0200 Subject: [PATCH 144/454] To allow offline installation, the "liteiclink" package has to be installed before the "liteeth" package. Otherwise, to satisfy the dependency requirements, the setup will attempt to download the "liteiclink" package from the internet and will consequently fail. --- litex_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex_setup.py b/litex_setup.py index 342dda5a1..2354a6846 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -80,12 +80,12 @@ def __init__(self, url, clone="regular", develop=True, sha1=None, branch="master # LiteX Cores Ecosystem. # ---------------------- + "liteiclink": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "liteeth": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "litedram": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "litepcie": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "litesata": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "litesdcard": GitRepo(url="https://github.com/enjoy-digital/", tag=True), - "liteiclink": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "litescope": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "litejesd204b": GitRepo(url="https://github.com/enjoy-digital/", tag=True), "litespi": GitRepo(url="https://github.com/litex-hub/", tag=True), From 8302cf2e79138b7874f25bcf9dd5d6c17daad24a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 18 Aug 2023 10:01:28 +0200 Subject: [PATCH 145/454] got nax 2 cores to run linux --- litex/soc/cores/cpu/naxriscv/boot-helper.S | 13 +- litex/soc/cores/cpu/naxriscv/core.py | 205 +++++++-------------- litex/soc/cores/cpu/naxriscv/crt0.S | 30 +++ 3 files changed, 109 insertions(+), 139 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/boot-helper.S b/litex/soc/cores/cpu/naxriscv/boot-helper.S index 6dd74aaeb..3a530dd1f 100644 --- a/litex/soc/cores/cpu/naxriscv/boot-helper.S +++ b/litex/soc/cores/cpu/naxriscv/boot-helper.S @@ -1,4 +1,15 @@ .section .text, "ax", @progbits -.global boot_helper +.global boot_helper +.global smp_lottery_target +.global smp_lottery_lock +.global smp_lottery_args + boot_helper: + sw x10, smp_lottery_args , x14 + sw x11, smp_lottery_args+4, x14 + sw x12, smp_lottery_args+8, x14 + sw x13, smp_lottery_target, x14 + fence w, w + li x15, 1 + sw x15, smp_lottery_lock, x14 jr x13 diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 9c4308f9b..ba9b3953a 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -50,6 +50,7 @@ class NaxRiscv(CPU): netlist_name = None scala_paths = [] xlen = 32 + cpu_count = 1 jtag_tap = False jtag_instruction = False @@ -103,6 +104,7 @@ def args_fill(parser): cpu_group.add_argument("--scala-file", action="append", help="Specify the scala files used to configure NaxRiscv.") cpu_group.add_argument("--scala-args", action="append", help="Add arguements for the scala run time. Ex : --scala-args 'rvc=true,mmu=false'") cpu_group.add_argument("--xlen", default=32, help="Specify the RISC-V data width.") + cpu_group.add_argument("--cpu-count", default=1, help="How many NaxRiscv CPU") cpu_group.add_argument("--with-jtag-tap", action="store_true", help="Add a embedded JTAG tap for debugging") cpu_group.add_argument("--with-jtag-instruction", action="store_true", help="Add a JTAG instruction port which implement tunneling for debugging (TAP not included)") cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") @@ -128,6 +130,8 @@ def args_read(args): NaxRiscv.data_width = xlen NaxRiscv.gcc_triple = CPU_GCC_TRIPLE_RISCV64 NaxRiscv.linker_output_format = f"elf{xlen}-littleriscv" + if args.cpu_count: + NaxRiscv.cpu_count = args.cpu_count def __init__(self, platform, variant): @@ -136,10 +140,9 @@ def __init__(self, platform, variant): self.human_name = self.human_name self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = axi.AXILiteInterface(address_width=32, data_width=32) - self.dbus = dbus = axi.AXILiteInterface(address_width=32, data_width=32) + self.pbus = pbus = axi.AXILiteInterface(address_width=32, data_width=32) - self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). + self.periph_buses = [pbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). # # # @@ -151,38 +154,28 @@ def __init__(self, platform, variant): i_reset = ResetSignal("sys") | self.reset, # Interrupt. - i_peripheral_interrupt = self.interrupt, # FIXME: Check what is expected. => interrupt(0) is dummy and should not be used (PLIC stuff), need to reserve interrupt(0) - - # Peripheral Instruction Bus (AXI Lite Slave). - o_peripheral_ibus_arvalid = ibus.ar.valid, - i_peripheral_ibus_arready = ibus.ar.ready, - o_peripheral_ibus_araddr = ibus.ar.addr, - o_peripheral_ibus_arprot = Open(), - i_peripheral_ibus_rvalid = ibus.r.valid, - o_peripheral_ibus_rready = ibus.r.ready, - i_peripheral_ibus_rdata = ibus.r.data, - i_peripheral_ibus_rresp = ibus.r.resp, + #i_peripheral_interrupt = self.interrupt, # FIXME: Check what is expected. => interrupt(0) is dummy and should not be used (PLIC stuff), need to reserve interrupt(0) # Peripheral Memory Bus (AXI Lite Slave). - o_peripheral_dbus_awvalid = dbus.aw.valid, - i_peripheral_dbus_awready = dbus.aw.ready, - o_peripheral_dbus_awaddr = dbus.aw.addr, - o_peripheral_dbus_awprot = Open(), - o_peripheral_dbus_wvalid = dbus.w.valid, - i_peripheral_dbus_wready = dbus.w.ready, - o_peripheral_dbus_wdata = dbus.w.data, - o_peripheral_dbus_wstrb = dbus.w.strb, - i_peripheral_dbus_bvalid = dbus.b.valid, - o_peripheral_dbus_bready = dbus.b.ready, - i_peripheral_dbus_bresp = dbus.b.resp, - o_peripheral_dbus_arvalid = dbus.ar.valid, - i_peripheral_dbus_arready = dbus.ar.ready, - o_peripheral_dbus_araddr = dbus.ar.addr, - o_peripheral_dbus_arprot = Open(), - i_peripheral_dbus_rvalid = dbus.r.valid, - o_peripheral_dbus_rready = dbus.r.ready, - i_peripheral_dbus_rdata = dbus.r.data, - i_peripheral_dbus_rresp = dbus.r.resp, + o_pBus_awvalid = pbus.aw.valid, + i_pBus_awready = pbus.aw.ready, + o_pBus_awaddr = pbus.aw.addr, + o_pBus_awprot = Open(), + o_pBus_wvalid = pbus.w.valid, + i_pBus_wready = pbus.w.ready, + o_pBus_wdata = pbus.w.data, + o_pBus_wstrb = pbus.w.strb, + i_pBus_bvalid = pbus.b.valid, + o_pBus_bready = pbus.b.ready, + i_pBus_bresp = pbus.b.resp, + o_pBus_arvalid = pbus.ar.valid, + i_pBus_arready = pbus.ar.ready, + o_pBus_araddr = pbus.ar.addr, + o_pBus_arprot = Open(), + i_pBus_rvalid = pbus.r.valid, + o_pBus_rready = pbus.r.ready, + i_pBus_rdata = pbus.r.data, + i_pBus_rresp = pbus.r.resp, ) def set_reset_address(self, reset_address): @@ -207,6 +200,7 @@ def generate_netlist_name(reset_address): md5_hash = hashlib.md5() md5_hash.update(str(reset_address).encode('utf-8')) md5_hash.update(str(NaxRiscv.xlen).encode('utf-8')) + md5_hash.update(str(NaxRiscv.cpu_count).encode('utf-8')) md5_hash.update(str(NaxRiscv.jtag_tap).encode('utf-8')) md5_hash.update(str(NaxRiscv.jtag_instruction).encode('utf-8')) md5_hash.update(str(NaxRiscv.memory_regions).encode('utf-8')) @@ -244,15 +238,16 @@ def generate_netlist(reset_address): ndir = os.path.join(vdir, "ext", "NaxRiscv") sdir = os.path.join(vdir, "ext", "SpinalHDL") - if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "57e3bf59" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "8511f126" if NaxRiscv.update_repo=="recommended" else None) + # if NaxRiscv.update_repo != "no": + # NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "57e3bf59" if NaxRiscv.update_repo=="recommended" else None) + # NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "8511f126" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") gen_args.append(f"--netlist-directory={vdir}") gen_args.append(f"--reset-vector={reset_address}") gen_args.append(f"--xlen={NaxRiscv.xlen}") + gen_args.append(f"--cpu-count={NaxRiscv.cpu_count}") for region in NaxRiscv.memory_regions: gen_args.append(f"--memory-region={region[0]},{region[1]},{region[2]},{region[3]}") for args in NaxRiscv.scala_args: @@ -268,7 +263,7 @@ def generate_netlist(reset_address): if(NaxRiscv.with_fpu): gen_args.append(f"--scala-args=rvf=true,rvd=true") - cmd = f"""cd {ndir} && sbt "runMain naxriscv.platform.LitexGen {" ".join(gen_args)}\"""" + cmd = f"""cd {ndir} && sbt "runMain naxriscv.platform.litex.NaxGen {" ".join(gen_args)}\"""" print("NaxRiscv generation command :") print(cmd) subprocess.check_call(cmd, shell=True) @@ -277,6 +272,7 @@ def generate_netlist(reset_address): def add_sources(self, platform): vdir = get_data_mod("cpu", "naxriscv").data_location print(f"NaxRiscv netlist : {self.netlist_name}") + if NaxRiscv.no_netlist_cache or not os.path.exists(os.path.join(vdir, self.netlist_name + ".v")): self.generate_netlist(self.reset_address) @@ -308,31 +304,6 @@ def add_soc_components(self, soc): soc.add_config("CPU_ISA", NaxRiscv.get_arch()) soc.add_config("CPU_MMU", {32 : "sv32", 64 : "sv39"}[NaxRiscv.xlen]) - # Add PLIC Bus (AXILite Slave). - self.plicbus = plicbus = axi.AXILiteInterface(address_width=32, data_width=32) - self.cpu_params.update( - i_peripheral_plic_awvalid = plicbus.aw.valid, - o_peripheral_plic_awready = plicbus.aw.ready, - i_peripheral_plic_awaddr = plicbus.aw.addr, - i_peripheral_plic_awprot = Constant(2), - i_peripheral_plic_wvalid = plicbus.w.valid, - o_peripheral_plic_wready = plicbus.w.ready, - i_peripheral_plic_wdata = plicbus.w.data, - i_peripheral_plic_wstrb = plicbus.w.strb, - o_peripheral_plic_bvalid = plicbus.b.valid, - i_peripheral_plic_bready = plicbus.b.ready, - o_peripheral_plic_bresp = plicbus.b.resp, - i_peripheral_plic_arvalid = plicbus.ar.valid, - o_peripheral_plic_arready = plicbus.ar.ready, - i_peripheral_plic_araddr = plicbus.ar.addr, - i_peripheral_plic_arprot = Constant(2), - o_peripheral_plic_rvalid = plicbus.r.valid, - i_peripheral_plic_rready = plicbus.r.ready, - o_peripheral_plic_rdata = plicbus.r.data, - o_peripheral_plic_rresp = plicbus.r.resp, - ) - soc.bus.add_slave("plic", self.plicbus, region=SoCRegion(origin=soc.mem_map.get("plic"), size=0x40_0000, cached=False)) - if NaxRiscv.jtag_tap: self.jtag_tms = Signal() self.jtag_tck = Signal() @@ -390,30 +361,6 @@ def add_soc_components(self, soc): self.comb += debug_ndmreset_rise.eq(debug_ndmreset & ~debug_ndmreset_last) self.comb += If(debug_ndmreset_rise, soc.crg.rst.eq(1)) - # Add CLINT Bus (AXILite Slave). - self.clintbus = clintbus = axi.AXILiteInterface(address_width=32, data_width=32) - self.cpu_params.update( - i_peripheral_clint_awvalid = clintbus.aw.valid, - o_peripheral_clint_awready = clintbus.aw.ready, - i_peripheral_clint_awaddr = clintbus.aw.addr, - i_peripheral_clint_awprot = Constant(2), - i_peripheral_clint_wvalid = clintbus.w.valid, - o_peripheral_clint_wready = clintbus.w.ready, - i_peripheral_clint_wdata = clintbus.w.data, - i_peripheral_clint_wstrb = clintbus.w.strb, - o_peripheral_clint_bvalid = clintbus.b.valid, - i_peripheral_clint_bready = clintbus.b.ready, - o_peripheral_clint_bresp = clintbus.b.resp, - i_peripheral_clint_arvalid = clintbus.ar.valid, - o_peripheral_clint_arready = clintbus.ar.ready, - i_peripheral_clint_araddr = clintbus.ar.addr, - i_peripheral_clint_arprot = Constant(2), - o_peripheral_clint_rvalid = clintbus.r.valid, - i_peripheral_clint_rready = clintbus.r.ready, - o_peripheral_clint_rdata = clintbus.r.data, - o_peripheral_clint_rresp = clintbus.r.resp, - ) - soc.bus.add_slave("clint", clintbus, region=SoCRegion(origin=soc.mem_map.get("clint"), size=0x1_0000, cached=False)) self.soc_bus = soc.bus # FIXME: Save SoC Bus instance to retrieve the final mem layout on finalization. def add_memory_buses(self, address_width, data_width): @@ -422,63 +369,45 @@ def add_memory_buses(self, address_width, data_width): assert data_width >= nax_data_width # FIXME: Only supporting up-conversion for now. assert data_width <= nax_burst_size*8 # FIXME: AXIUpConverter doing assumptions on minimal burst_size. - ibus = axi.AXIInterface( - data_width = nax_data_width, - address_width = 32, - id_width = 1, - ) - dbus = axi.AXIInterface( + mbus = axi.AXIInterface( data_width = nax_data_width, address_width = 32, - id_width = 4, + id_width = 8, #TODO ) - self.memory_buses.append(ibus) - self.memory_buses.append(dbus) + self.memory_buses.append(mbus) self.cpu_params.update( - # Instruction Memory Bus (Master). - o_ram_ibus_arvalid = ibus.ar.valid, - i_ram_ibus_arready = ibus.ar.ready, - o_ram_ibus_araddr = ibus.ar.addr, - o_ram_ibus_arlen = ibus.ar.len, - o_ram_ibus_arsize = ibus.ar.size, - o_ram_ibus_arburst = ibus.ar.burst, - i_ram_ibus_rvalid = ibus.r.valid, - o_ram_ibus_rready = ibus.r.ready, - i_ram_ibus_rdata = ibus.r.data, - i_ram_ibus_rresp = ibus.r.resp, - i_ram_ibus_rlast = ibus.r.last, - - # Data Memory Bus (Master). - o_ram_dbus_awvalid = dbus.aw.valid, - i_ram_dbus_awready = dbus.aw.ready, - o_ram_dbus_awaddr = dbus.aw.addr, - o_ram_dbus_awid = dbus.aw.id, - o_ram_dbus_awlen = dbus.aw.len, - o_ram_dbus_awsize = dbus.aw.size, - o_ram_dbus_awburst = dbus.aw.burst, - o_ram_dbus_wvalid = dbus.w.valid, - i_ram_dbus_wready = dbus.w.ready, - o_ram_dbus_wdata = dbus.w.data, - o_ram_dbus_wstrb = dbus.w.strb, - o_ram_dbus_wlast = dbus.w.last, - i_ram_dbus_bvalid = dbus.b.valid, - o_ram_dbus_bready = dbus.b.ready, - i_ram_dbus_bid = dbus.b.id, - i_ram_dbus_bresp = dbus.b.resp, - o_ram_dbus_arvalid = dbus.ar.valid, - i_ram_dbus_arready = dbus.ar.ready, - o_ram_dbus_araddr = dbus.ar.addr, - o_ram_dbus_arid = dbus.ar.id, - o_ram_dbus_arlen = dbus.ar.len, - o_ram_dbus_arsize = dbus.ar.size, - o_ram_dbus_arburst = dbus.ar.burst, - i_ram_dbus_rvalid = dbus.r.valid, - o_ram_dbus_rready = dbus.r.ready, - i_ram_dbus_rdata = dbus.r.data, - i_ram_dbus_rid = dbus.r.id, - i_ram_dbus_rresp = dbus.r.resp, - i_ram_dbus_rlast = dbus.r.last, + # Memory Bus (Master). + o_mBus_awvalid = mbus.aw.valid, + i_mBus_awready = mbus.aw.ready, + o_mBus_awaddr = mbus.aw.addr, + o_mBus_awid = mbus.aw.id, + o_mBus_awlen = mbus.aw.len, + o_mBus_awsize = mbus.aw.size, + o_mBus_awburst = mbus.aw.burst, + o_mBus_awallStrb = Open(), + o_mBus_wvalid = mbus.w.valid, + i_mBus_wready = mbus.w.ready, + o_mBus_wdata = mbus.w.data, + o_mBus_wstrb = mbus.w.strb, + o_mBus_wlast = mbus.w.last, + i_mBus_bvalid = mbus.b.valid, + o_mBus_bready = mbus.b.ready, + i_mBus_bid = mbus.b.id, + i_mBus_bresp = mbus.b.resp, + o_mBus_arvalid = mbus.ar.valid, + i_mBus_arready = mbus.ar.ready, + o_mBus_araddr = mbus.ar.addr, + o_mBus_arid = mbus.ar.id, + o_mBus_arlen = mbus.ar.len, + o_mBus_arsize = mbus.ar.size, + o_mBus_arburst = mbus.ar.burst, + i_mBus_rvalid = mbus.r.valid, + o_mBus_rready = mbus.r.ready, + i_mBus_rdata = mbus.r.data, + i_mBus_rid = mbus.r.id, + i_mBus_rresp = mbus.r.resp, + i_mBus_rlast = mbus.r.last, ) def do_finalize(self): diff --git a/litex/soc/cores/cpu/naxriscv/crt0.S b/litex/soc/cores/cpu/naxriscv/crt0.S index 8078020fd..b27df7f47 100644 --- a/litex/soc/cores/cpu/naxriscv/crt0.S +++ b/litex/soc/cores/cpu/naxriscv/crt0.S @@ -2,6 +2,11 @@ .global isr .global _start +.global smp_lottery_target +.global smp_lottery_lock +.global smp_lottery_args +.global smp_slave + #define MSTATUS_FS_INITIAL (1 << 13) #define MSTATUS_FS_CLEAN (2 << 13) #define MSTATUS_FS_DIRTY (3 << 13) @@ -67,6 +72,24 @@ enable_fpu: li x1, MSTATUS_FS_INITIAL csrs mstatus, x1 + sw x0, smp_lottery_lock, a1 +smp_tyranny: + csrr a0, mhartid + beqz a0, data_init + +smp_slave: + lw a0, smp_lottery_lock + beqz a0, smp_slave + fence r, r + + .word(0x100F) //i$ flush + lw x10, smp_lottery_args + lw x11, smp_lottery_args+4 + lw x12, smp_lottery_args+8 + lw x13, smp_lottery_target + jr x13 + + data_init: la a0, _fdata la a1, _edata @@ -96,3 +119,10 @@ bss_done: call main infinit_loop: j infinit_loop + +//Initialized to avoid having them set to zero by BSS clear +.bss + smp_lottery_target: .word 0 + smp_lottery_args: .word 0; .word 0; .word 0 + smp_lottery_lock: .word 0 + From 8f7f97a7137e84acea0c66b82909c47f4df57b0e Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 18 Aug 2023 19:29:41 +0200 Subject: [PATCH 146/454] fix plic/clint regions + dts --- litex/soc/cores/cpu/naxriscv/core.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index ba9b3953a..1b7ef5bc8 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -74,7 +74,7 @@ def get_arch(): # Memory Mapping. @property - def mem_map(self): + def mem_map(self): # TODO return { "rom": 0x0000_0000, "sram": 0x1000_0000, @@ -154,7 +154,7 @@ def __init__(self, platform, variant): i_reset = ResetSignal("sys") | self.reset, # Interrupt. - #i_peripheral_interrupt = self.interrupt, # FIXME: Check what is expected. => interrupt(0) is dummy and should not be used (PLIC stuff), need to reserve interrupt(0) + i_peripheral_externalInterrupts_port = self.interrupt, # Peripheral Memory Bus (AXI Lite Slave). o_pBus_awvalid = pbus.aw.valid, @@ -301,9 +301,13 @@ def add_soc_components(self, soc): soc.bus.add_region("opensbi", SoCRegion(origin=self.mem_map["main_ram"] + 0x00f0_0000, size=0x8_0000, cached=True, linker=True)) # Define ISA. + soc.add_config("CPU_COUNT", NaxRiscv.cpu_count) soc.add_config("CPU_ISA", NaxRiscv.get_arch()) soc.add_config("CPU_MMU", {32 : "sv32", 64 : "sv39"}[NaxRiscv.xlen]) + soc.bus.add_region("plic", SoCRegion(origin=soc.mem_map.get("plic"), size=0x40_0000, cached=False, linker=True)) + soc.bus.add_region("clint", SoCRegion(origin=soc.mem_map.get("clint"), size= 0x1_0000, cached=False, linker=True)) + if NaxRiscv.jtag_tap: self.jtag_tms = Signal() self.jtag_tck = Signal() From 6d8c04b4010a798671b3ff9f2e1374b6ba70d63c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 22 Aug 2023 15:50:08 +0200 Subject: [PATCH 147/454] cpu/naxriscv: Update recommended version. --- litex/soc/cores/cpu/naxriscv/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 9c4308f9b..86d4c833f 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -245,8 +245,8 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "57e3bf59" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "8511f126" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "d7213a3f" if (NaxRiscv.update_repo == "recommended") else None) + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev", "912f4b37" if (NaxRiscv.update_repo == "recommended") else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From 8f54386aab23abd621c2e706a79704ed96954178 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 Aug 2023 09:10:55 +0200 Subject: [PATCH 148/454] gen/fhdl/module: Add some comments. --- litex/gen/fhdl/module.py | 45 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/litex/gen/fhdl/module.py b/litex/gen/fhdl/module.py index fe756318e..8a389cbe8 100644 --- a/litex/gen/fhdl/module.py +++ b/litex/gen/fhdl/module.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# This file is Copyright (c) 2022 Florent Kermarrec +# This file is Copyright (c) 2022-2023 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause from migen import * @@ -14,12 +14,23 @@ # LiteX Module ------------------------------------------------------------------------------------- class LiteXModule(Module, AutoCSR, AutoDoc): + """ + LiteXModule is an enhancement of the Migen Module, offering additional features and simplifications + for users to handle submodules, specials, and clock domains. It is integrated with AutoCSR and + AutoDoc for CSR and documentation automation, respectively. + """ + def __setattr__(m, name, value): - # Migen: + """ + Overrides the default behavior of attribute assignment in Python. This method simplifies the + process of adding submodules, specials, and clock domains in LiteX compared to Migen. + """ + + # Migen behavior: if name in ["comb", "sync", "specials", "submodules", "clock_domains"]: if not isinstance(value, _ModuleProxy): raise AttributeError("Attempted to assign special Module property - use += instead") - # LiteX fix-up: Automatically collect specials/submodules/clock_domains: + # Automatic handling for adding submodules, specials, and clock domains in LiteX. # - m.module_x = .. equivalent of Migen's m.submodules.module_x = .. # Note: Do an exception for CSRs that have a specific collection mechanism. elif (isinstance(value, Module) and ((name, value) not in m._submodules) and (not isinstance(value, _CSRBase))): @@ -34,8 +45,12 @@ def __setattr__(m, name, value): else: object.__setattr__(m, name, value) - # LiteX fix-up: Automatically collect specials/submodules/clock_domains: def __iadd__(m, other): + """ + Overrides the default behavior of "+=" in Python. Simplifies addition of submodules, specials, + and clock domains. + """ + # - m += module_x equivalent of Migen's m.submodules += module_x. if isinstance(other, Module): print(other) @@ -52,11 +67,33 @@ def __iadd__(m, other): return m def add_module(self, name, module): + """ + Add a submodule to the current module. + + Args: + name (str): Name to assign to the submodule. + module (Module): Submodule to be added. + + Raises: + AssertionError: If provided object is not a Module or module name already exists. + """ assert isinstance(module, Module) assert not hasattr(self, name) setattr(self, name, module) def get_module(self, name): + """ + Retrieve a submodule by its name. + + Args: + name (str): Name of the submodule to retrieve. + + Returns: + module (Module or None): Returns the module if found, otherwise None. + + Raises: + AssertionError: If found object is not of type Module. + """ module = getattr(self, name, None) if module is not None: assert isinstance(module, Module) From f7b35f09ae1d2d2c81751f2c57c39d3c8c48e33c Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 28 Aug 2023 14:43:17 +0200 Subject: [PATCH 149/454] build/efinix/efinity: don't hardcode efinity version, read from scripts/sw_version.txt --- litex/build/efinix/efinity.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 0f6919070..8208f1df1 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -217,7 +217,9 @@ def build_project(self): root.attrib["xmlns:efx"] = "http://www.efinixinc.com/enf_proj" root.attrib["name"] = self._build_name root.attrib["location"] = str(pathlib.Path().resolve()) - root.attrib["sw_version"] = "2023.1.150" # TODO: read it from sw_version.txt + # read efinity version in scripts/sw_version.txt + with open(os.path.join(self.efinity_path, "scripts/sw_version.txt"), "r") as fd: + root.attrib["sw_version"]= fd.readline().strip() root.attrib["last_change_date"] = f"Date : {now.strftime('%Y-%m-%d %H:%M')}" # Add Device. From d29d2c09bbbfda4ce0b102c404b093548a143d8e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 28 Aug 2023 16:02:41 +0200 Subject: [PATCH 150/454] interconnect/stream: Minor review/cleanup. --- litex/soc/interconnect/stream.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index a0465a549..31c67a5a6 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -991,21 +991,22 @@ def __init__(self, endpoint_dict, pipe_valid=True, pipe_ready=False): def transform_instance(self, submodule): for name, direction in self.endpoint_dict.items(): endpoint = getattr(submodule, name) - # add buffer on sinks + # Add Buffer on Sinks. if direction == DIR_SINK: buf = Buffer( - endpoint.description, - pipe_valid=pipe_valid, - pipe_ready=pipe_ready + layout = endpoint.description, + pipe_valid = pipe_valid, + pipe_ready = pipe_ready, ) submodule.submodules += buf setattr(submodule, name, buf.sink) submodule.comb += buf.source.connect(endpoint) - # add buffer on sources + # Add Buffer on Sources. elif direction == DIR_SOURCE: - buf = Buffer(endpoint.description, - pipe_valid=pipe_valid, - pipe_ready=pipe_ready + buf = Buffer( + layout = endpoint.description, + pipe_valid = pipe_valid, + pipe_ready = pipe_ready, ) submodule.submodules += buf submodule.comb += endpoint.connect(buf.sink) From 70e52b76fae0dacb6bbff0a1728c8534d96970c8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 28 Aug 2023 16:04:43 +0200 Subject: [PATCH 151/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 412c1eade..1b36baf06 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ - soc/add_uart : Fixed stub behavior (sink/source swap). - build/efinix : Fixed AsyncFIFO issues (Minimum of 2 buffer stages). - software/gcc : Fixed Ubuntu 22.04 GCC compilation issues. + - build/efinix : Fixed hardcoded version. [> Added -------- @@ -56,6 +57,7 @@ - liteth/arp : Added proper multi-entries ARP table. - liteiclink/serdes : Added tx/rx_clk sharing capabilities on Xilinx transceivers. - soc/cores/spi : Added new SPIMMAP core allowing SPI accesses through MMAP. + - soc/interconnect/stream : Added pipe_valid/pipe_ready parameters to BufferizeEndpoints. [> Changed ---------- From 82602f660c95dd9d74d17eb9627c8192db3a1e93 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 28 Aug 2023 16:19:31 +0200 Subject: [PATCH 152/454] interconnect/stream: Fix #1736. --- litex/soc/interconnect/stream.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index 31c67a5a6..14ddda96e 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -987,6 +987,8 @@ def do_finalize(self): class BufferizeEndpoints(ModuleTransformer): def __init__(self, endpoint_dict, pipe_valid=True, pipe_ready=False): self.endpoint_dict = endpoint_dict + self.pipe_valid = pipe_valid + self.pipe_ready = pipe_ready def transform_instance(self, submodule): for name, direction in self.endpoint_dict.items(): @@ -995,8 +997,8 @@ def transform_instance(self, submodule): if direction == DIR_SINK: buf = Buffer( layout = endpoint.description, - pipe_valid = pipe_valid, - pipe_ready = pipe_ready, + pipe_valid = self.pipe_valid, + pipe_ready = self.pipe_ready, ) submodule.submodules += buf setattr(submodule, name, buf.sink) @@ -1005,8 +1007,8 @@ def transform_instance(self, submodule): elif direction == DIR_SOURCE: buf = Buffer( layout = endpoint.description, - pipe_valid = pipe_valid, - pipe_ready = pipe_ready, + pipe_valid = self.pipe_valid, + pipe_ready = self.pipe_ready, ) submodule.submodules += buf submodule.comb += endpoint.connect(buf.sink) From a4498dcd03fc7af403ec5b10ec35e89acb98f99f Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Mon, 28 Aug 2023 18:57:45 +0200 Subject: [PATCH 153/454] nax dma wip, WARNING soc.py --- litex/soc/cores/cpu/naxriscv/core.py | 51 ++++++++++++++++++++++++++++ litex/soc/integration/soc.py | 20 ++++++++--- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 1b7ef5bc8..c1445053e 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -53,6 +53,7 @@ class NaxRiscv(CPU): cpu_count = 1 jtag_tap = False jtag_instruction = False + with_dma = False # ABI. @staticmethod @@ -105,6 +106,7 @@ def args_fill(parser): cpu_group.add_argument("--scala-args", action="append", help="Add arguements for the scala run time. Ex : --scala-args 'rvc=true,mmu=false'") cpu_group.add_argument("--xlen", default=32, help="Specify the RISC-V data width.") cpu_group.add_argument("--cpu-count", default=1, help="How many NaxRiscv CPU") + cpu_group.add_argument("--with-coherent-dma", action="store_true", help="Enable coherent DMA accesses") cpu_group.add_argument("--with-jtag-tap", action="store_true", help="Add a embedded JTAG tap for debugging") cpu_group.add_argument("--with-jtag-instruction", action="store_true", help="Add a JTAG instruction port which implement tunneling for debugging (TAP not included)") cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") @@ -116,6 +118,7 @@ def args_read(args): print(args) NaxRiscv.jtag_tap = args.with_jtag_tap NaxRiscv.jtag_instruction = args.with_jtag_instruction + NaxRiscv.with_dma = args.with_coherent_dma NaxRiscv.update_repo = args.update_repo NaxRiscv.no_netlist_cache = args.no_netlist_cache NaxRiscv.with_fpu = args.with_fpu @@ -145,6 +148,8 @@ def __init__(self, platform, variant): self.periph_buses = [pbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). + self.dma_bus = dma_bus = axi.AXIInterface(data_width=64, address_width=32, id_width=4) + # # # # CPU Instance. @@ -176,6 +181,49 @@ def __init__(self, platform, variant): o_pBus_rready = pbus.r.ready, i_pBus_rdata = pbus.r.data, i_pBus_rresp = pbus.r.resp, + + # DMA + o_dma_bus_awready=dma_bus.aw.ready, + i_dma_bus_awvalid=dma_bus.aw.valid, + i_dma_bus_awid=dma_bus.aw.id, + i_dma_bus_awaddr=dma_bus.aw.addr, + i_dma_bus_awlen=dma_bus.aw.len, + i_dma_bus_awsize=dma_bus.aw.size, + i_dma_bus_awburst=dma_bus.aw.burst, + i_dma_bus_awlock=dma_bus.aw.lock, + i_dma_bus_awcache=dma_bus.aw.cache, + i_dma_bus_awprot=dma_bus.aw.prot, + i_dma_bus_awqos=dma_bus.aw.qos, + + o_dma_bus_wready=dma_bus.w.ready, + i_dma_bus_wvalid=dma_bus.w.valid, + i_dma_bus_wdata=dma_bus.w.data, + i_dma_bus_wstrb=dma_bus.w.strb, + i_dma_bus_wlast=dma_bus.w.last, + + i_dma_bus_bready=dma_bus.b.ready, + o_dma_bus_bvalid=dma_bus.b.valid, + o_dma_bus_bid=dma_bus.b.id, + o_dma_bus_bresp=dma_bus.b.resp, + + o_dma_bus_arready=dma_bus.ar.ready, + i_dma_bus_arvalid=dma_bus.ar.valid, + i_dma_bus_arid=dma_bus.ar.id, + i_dma_bus_araddr=dma_bus.ar.addr, + i_dma_bus_arlen=dma_bus.ar.len, + i_dma_bus_arsize=dma_bus.ar.size, + i_dma_bus_arburst=dma_bus.ar.burst, + i_dma_bus_arlock=dma_bus.ar.lock, + i_dma_bus_arcache=dma_bus.ar.cache, + i_dma_bus_arprot=dma_bus.ar.prot, + i_dma_bus_arqos=dma_bus.ar.qos, + + i_dma_bus_rready=dma_bus.r.ready, + o_dma_bus_rvalid=dma_bus.r.valid, + o_dma_bus_rid=dma_bus.r.id, + o_dma_bus_rdata=dma_bus.r.data, + o_dma_bus_rresp=dma_bus.r.resp, + o_dma_bus_rlast=dma_bus.r.last, ) def set_reset_address(self, reset_address): @@ -203,6 +251,7 @@ def generate_netlist_name(reset_address): md5_hash.update(str(NaxRiscv.cpu_count).encode('utf-8')) md5_hash.update(str(NaxRiscv.jtag_tap).encode('utf-8')) md5_hash.update(str(NaxRiscv.jtag_instruction).encode('utf-8')) + md5_hash.update(str(NaxRiscv.with_dma).encode('utf-8')) md5_hash.update(str(NaxRiscv.memory_regions).encode('utf-8')) for args in NaxRiscv.scala_args: md5_hash.update(args.encode('utf-8')) @@ -258,6 +307,8 @@ def generate_netlist(reset_address): gen_args.append(f"--with-jtag-instruction") if(NaxRiscv.jtag_tap or NaxRiscv.jtag_instruction): gen_args.append(f"--with-debug") + if(NaxRiscv.with_dma) : + gen_args.append(f"--with-dma") for file in NaxRiscv.scala_paths: gen_args.append(f"--scala-file={file}") if(NaxRiscv.with_fpu): diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index b46bfb68f..95f79102d 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1122,16 +1122,28 @@ def add_cpu(self, name="vexriscv", variant="standard", reset_address=None, cfu=N self.logger.info("CPU {} {} DMA Bus.".format( colorer(name, color="underline"), colorer("adding", color="cyan"))) + + # self.dma_bus = SoCBusHandler( + # name = "SoCDMABusHandler", + # standard = "wishbone", + # data_width = self.bus.data_width, + # address_width = self.bus.get_address_width(standard="wishbone"), + # bursting = self.bus.bursting + # ) + # dma_bus = wishbone.Interface(data_width=self.bus.data_width) + # self.dma_bus.add_slave(name="dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only + # self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus) + self.dma_bus = SoCBusHandler( name = "SoCDMABusHandler", - standard = "wishbone", + standard = "axi", data_width = self.bus.data_width, - address_width = self.bus.get_address_width(standard="wishbone"), + address_width = self.bus.get_address_width(standard="axi"), bursting = self.bus.bursting ) - dma_bus = wishbone.Interface(data_width=self.bus.data_width) + dma_bus = axi.AXIInterface(data_width=self.bus.data_width, address_width=32, id_width=4) self.dma_bus.add_slave(name="dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only - self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus) + self.submodules += axi.AXIConverter(dma_bus, self.cpu.dma_bus) # Connect SoCController's reset to CPU reset. if hasattr(self, "ctrl"): From 1636c0ef8d0e85219baa4bba8d610829e205a40a Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 10 Aug 2023 15:32:27 +0800 Subject: [PATCH 154/454] soc/cores/clock: initial GW5A support GW5A has different PLLs than GW1N/GW2A, with multiple individual ODIV's. GW5A-25 has a different PLL with GW5A[S]T-138, with lack of dynamic control. Add basic support for them. Signed-off-by: Icenowy Zheng --- litex/soc/cores/clock/gowin_gw5a.py | 298 ++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 litex/soc/cores/clock/gowin_gw5a.py diff --git a/litex/soc/cores/clock/gowin_gw5a.py b/litex/soc/cores/clock/gowin_gw5a.py new file mode 100644 index 000000000..1976e042a --- /dev/null +++ b/litex/soc/cores/clock/gowin_gw5a.py @@ -0,0 +1,298 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2021-2022 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.gen import * + +from litex.soc.cores.clock.common import * + +# GoWin / GW5APLL ---------------------------------------------------------------------------------- + +class GW5APLL(LiteXModule): + nclkouts_max = 7 + + def __init__(self, devicename, device, vco_margin=0): + self.logger = logging.getLogger("GW5APLL") + self.logger.info("Creating GW5APLL.".format()) + self.device = device + self.devicename = devicename + self.vco_margin = vco_margin + self.reset = Signal() + self.locked = Signal() + self.clkin_freq = None + self.vcxo_freq = None + self.nclkouts = 0 + self.clkouts = {} + self.config = {} + self.params = {} + self.vco_freq_range = self.get_vco_freq_range(device) + self.pfd_freq_range = self.get_pfd_freq_range(device) + + @staticmethod + def get_vco_freq_range(device): + vco_freq_range = None + if device.startswith('GW5A-') or device.startswith('GW5AT-') or device.startswith('GW5AST-'): + vco_freq_range = (800e6, 2000e6) # datasheet values + if vco_freq_range is None: + raise ValueError(f"Unsupported device {device}.") + return vco_freq_range + + @staticmethod + def get_pfd_freq_range(device): + pfd_freq_range = None + if device.startswith('GW5A-') or device.startswith('GW5AT-') or device.startswith('GW5AST-'): + pfd_freq_range = (10e6, 400e6) # datasheet values + if pfd_freq_range is None: + raise ValueError(f"Unsupported device {device}.") + return pfd_freq_range + + def register_clkin(self, clkin, freq): + self.clkin = Signal() + if isinstance(clkin, (Signal, ClockSignal)): + self.comb += self.clkin.eq(clkin) + else: + raise ValueError + self.clkin_freq = freq + register_clkin_log(self.logger, clkin, freq) + + def create_clkout(self, cd, freq, phase=0, margin=1e-2, with_reset=True): + assert self.nclkouts < self.nclkouts_max + clkout = Signal() + self.clkouts[self.nclkouts] = (clkout, freq, phase, margin) + if with_reset: + self.specials += AsyncResetSynchronizer(cd, ~self.locked) + self.comb += cd.clk.eq(clkout) + create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts) + self.nclkouts += 1 + + def compute_config(self): + configs = [] # corresponding VCO/FBDIV/IDIV/ODIV params + diff + + for idiv in range(1, 64): + pfd_freq = self.clkin_freq/idiv + pfd_freq_min, pfd_freq_max = self.pfd_freq_range + if (pfd_freq < pfd_freq_min) or (pfd_freq > pfd_freq_max): + continue + for fdiv in range(1, 64): + for mdiv in range(2,128): + vco_freq = self.clkin_freq/idiv*fdiv*mdiv + (vco_freq_min, vco_freq_max) = self.vco_freq_range + if (vco_freq >= vco_freq_min*(1 + self.vco_margin) and + vco_freq <= vco_freq_max*(1 - self.vco_margin)): + okay = True + config = {} + for n, (clk, f, p, m) in self.clkouts.items(): + odiv = round(vco_freq/f) + out_freq = vco_freq/odiv + diff = abs(out_freq - f) / f + pe = round(p * odiv / 360) + if abs((360.0 * pe / odiv) - p) / 360 > m: + okay = False + if diff > m: + okay = False + else: + config["odiv%d" % n] = odiv + config["diff%d" % n] = diff + config["pe%d" % n] = int(p * odiv / 360) + config["pe%d_fine" % n] = round(p * odiv * 8 / 360) % 8 + if okay: + config["idiv"] = idiv + config["vco"] = vco_freq + config["fdiv"] = fdiv + config["mdiv"] = mdiv + configs += [config] + + if len(configs) == 0: + raise ValueError("No PLL config found") + + best_config = None + best_diff_sum = 0 + for i in range(0,len(configs)): + curr_diff_sum = 0 + for n, clkout in self.clkouts.items(): + curr_diff_sum += configs[i]["diff%d" % n] + + if i == 0 or curr_diff_sum < best_diff_sum: + best_diff_sum = curr_diff_sum + best_config = configs[i] + + return best_config + + def do_finalize(self): + assert hasattr(self, "clkin") + assert len(self.clkouts) > 0 and len(self.clkouts) <= self.nclkouts_max + config = self.compute_config() + # Based on UG306-1.0 Note. + self.params.update( + # Parameters. + p_FCLKIN = str(self.clkin_freq/1e6), # Clk Input frequency (MHz). + p_IDIV_SEL = config["idiv"], # Static IDIV value (1-64). + p_FBDIV_SEL = config["fdiv"], # Static FBDIV value (1-64). + p_ODIV0_SEL = 8, # Static ODIV value (1-128). + p_ODIV0_FRAC_SEL = 0, # Static ODIV0 fractional value (0-7)/8 + p_ODIV1_SEL = 8, # Static ODIV1 value + p_ODIV2_SEL = 8, # Static ODIV2 value + p_ODIV3_SEL = 8, # Static ODIV3 value + p_ODIV4_SEL = 8, # Static ODIV4 value + p_ODIV5_SEL = 8, # Static ODIV5 value + p_ODIV6_SEL = 8, # Static ODIV6 value + p_MDIV_SEL = config["mdiv"], # Static MDIV value (2-128). + p_MDIV_FRAC_SEL = 0, # Static MDIV fractional value (0-7)/8 + p_CLKOUT0_EN = "FALSE", # Disable CLKOUT0. + p_CLKOUT1_EN = "FALSE", # Disable CLKOUT1. + p_CLKOUT2_EN = "FALSE", # Disable CLKOUT2. + p_CLKOUT3_EN = "FALSE", # Disable CLKOUT3. + p_CLKOUT4_EN = "FALSE", # Disable CLKOUT4. + p_CLKOUT5_EN = "FALSE", # Disable CLKOUT5. + p_CLKOUT6_EN = "FALSE", # Disable CLKOUT6. + p_CLKOUT0_DT_DIR = 1, # Static CLKOUT0 duty control direction (0-down, 1-up) + p_CLKOUT1_DT_DIR = 1, # Static CLKOUT1 duty control direction (0-down, 1-up) + p_CLKOUT2_DT_DIR = 1, # Static CLKOUT2 duty control direction (0-down, 1-up) + p_CLKOUT3_DT_DIR = 1, # Static CLKOUT3 duty control direction (0-down, 1-up) + p_CLKOUT0_DT_STEP = 0, # Static CLKOUT0 duty control step (0,1,2,4)*50ps + p_CLKOUT1_DT_STEP = 0, # Static CLKOUT1 duty control step (0,1,2,4)*50ps + p_CLKOUT2_DT_STEP = 0, # Static CLKOUT2 duty control step (0,1,2,4)*50ps + p_CLKOUT3_DT_STEP = 0, # Static CLKOUT3 duty control step (0,1,2,4)*50ps + p_CLK0_IN_SEL = 0, # Select ODIV0 source (0-VCO, 1-CLKIN) + p_CLK0_OUT_SEL = 0, # Select CLKOUT0 source (0-ODIV0, 1-CLKIN) + p_CLK1_IN_SEL = 0, # Select ODIV1 source (0-VCO, 1-CLKIN) + p_CLK1_OUT_SEL = 0, # Select CLKOUT1 source (0-ODIV1, 1-CLKIN) + p_CLK2_IN_SEL = 0, # Select ODIV2 source (0-VCO, 1-CLKIN) + p_CLK2_OUT_SEL = 0, # Select CLKOUT2 source (0-ODIV2, 1-CLKIN) + p_CLK3_IN_SEL = 0, # Select ODIV3 source (0-VCO, 1-CLKIN) + p_CLK3_OUT_SEL = 0, # Select CLKOUT3 source (0-ODIV3, 1-CLKIN) + p_CLK4_IN_SEL = 0, # Select ODIV4 source (0-VCO, 1-CLKIN) + p_CLK4_OUT_SEL = 0, # Select CLKOUT4 source (0-ODIV4, 1-CLKIN) + p_CLK5_IN_SEL = 0, # Select ODIV5 source (0-VCO, 1-CLKIN) + p_CLK5_OUT_SEL = 0, # Select CLKOUT5 source (0-ODIV5, 1-CLKIN) + p_CLKFB_SEL = "INTERNAL", # Clk Feedback type (INTERNAL, EXTERNAL). + p_DYN_DPA_EN = "FALSE", # Disable dynamic phase shift. + p_CLKOUT0_PE_COARSE= 0, # Static CLKOUT0 phase shift coarse config + p_CLKOUT0_PE_FINE = 0, # Static CLKOUT0 phase shift fine config + p_CLKOUT1_PE_COARSE= 0, # Static CLKOUT1 phase shift coarse config + p_CLKOUT1_PE_FINE = 0, # Static CLKOUT1 phase shift fine config + p_CLKOUT2_PE_COARSE= 0, # Static CLKOUT2 phase shift coarse config + p_CLKOUT2_PE_FINE = 0, # Static CLKOUT2 phase shift fine config + p_CLKOUT3_PE_COARSE= 0, # Static CLKOUT3 phase shift coarse config + p_CLKOUT3_PE_FINE = 0, # Static CLKOUT3 phase shift fine config + p_CLKOUT4_PE_COARSE= 0, # Static CLKOUT4 phase shift coarse config + p_CLKOUT4_PE_FINE = 0, # Static CLKOUT4 phase shift fine config + p_CLKOUT5_PE_COARSE= 0, # Static CLKOUT5 phase shift coarse config + p_CLKOUT5_PE_FINE = 0, # Static CLKOUT5 phase shift fine config + p_CLKOUT6_PE_COARSE= 0, # Static CLKOUT6 phase shift coarse config + p_CLKOUT6_PE_FINE = 0, # Static CLKOUT6 phase shift fine config + p_DYN_PE0_SEL = "FALSE", # Static CLKOUT0 phase shift. + p_DYN_PE1_SEL = "FALSE", # Static CLKOUT1 phase shift. + p_DYN_PE2_SEL = "FALSE", # Static CLKOUT2 phase shift. + p_DYN_PE3_SEL = "FALSE", # Static CLKOUT3 phase shift. + p_DYN_PE4_SEL = "FALSE", # Static CLKOUT4 phase shift. + p_DYN_PE5_SEL = "FALSE", # Static CLKOUT5 phase shift. + p_DYN_PE6_SEL = "FALSE", # Static CLKOUT6 phase shift. + p_DE0_EN = "FALSE", # Disable CLKOUT0 duty cycle adjust + p_DE1_EN = "FALSE", # Disable CLKOUT0 duty cycle adjust + p_DE2_EN = "FALSE", # Disable CLKOUT0 duty cycle adjust + p_DE3_EN = "FALSE", # Disable CLKOUT0 duty cycle adjust + p_DE4_EN = "FALSE", # Disable CLKOUT0 duty cycle adjust + p_DE5_EN = "FALSE", # Disable CLKOUT0 duty cycle adjust + p_DE6_EN = "FALSE", # Disable CLKOUT0 duty cycle adjust + p_RESET_I_EN = "FALSE", # - + p_RESET_O_EN = "FALSE", # - + p_SSC_EN = "FALSE", # Disable spread spectrun control. + + # Inputs. + i_CLKIN = self.clkin, # Clk Input. + i_CLKFB = 0, # Clk Feedback. + i_RESET = self.reset, # PLL Reset. + i_PLLPWD = 0, # PLL Power Down. + i_RESET_I = 0, # PLL Partial Reset (for testing) + i_RESET_O = 0, # PLL Partial Reset (for testing) + i_PSDIR = 0, # Dynamic Phase Select direction. + i_PSSEL = Constant(0, 3), # Dynamic Phase Select channel control. + i_PSPULSE = 0, # Dynamic Phase Select pulse. + i_SSCPOL = 0, # Spread Spectrum polarity. + i_SSCON = 0, # Spread Spectrum enable. + i_SSCMDSEL = Constant(0, 7), # Dynamic SSC MDIV integer control. + i_SSCMDSEL_FRAC = Constant(0, 3), # Dynamic SSC MDIV fractional control. + + o_LOCK = self.locked, + o_CLKOUT0 = Open(), + o_CLKOUT1 = Open(), + o_CLKOUT2 = Open(), + o_CLKOUT3 = Open(), + o_CLKOUT4 = Open(), + o_CLKOUT5 = Open(), + o_CLKOUT6 = Open(), + o_CLKFBOUT = Open() + ) + + if self.device.startswith('GW5A-'): # GW5A-25, uses PLLA + instance_name = 'PLLA' + self.params.update( + i_MDCLK = 0, + i_MDOPC = Constant(0, 2), + i_MDAINC = 0, + i_MDWDI = Constant(0, 8), + ) + else: # GW5A{,S}T, uses PLL + instance_name = 'PLL' + self.params.update( + p_DYN_IDIV_SEL = "FALSE", # Disable dynamic IDIV. + p_DYN_FBDIV_SEL = "FALSE", # Disable dynamic FBDIV. + p_DYN_ODIV0_SEL = "FALSE", # Disable dynamic ODIV0. + p_DYN_ODIV1_SEL = "FALSE", # Disable dynamic ODIV1. + p_DYN_ODIV2_SEL = "FALSE", # Disable dynamic ODIV2. + p_DYN_ODIV3_SEL = "FALSE", # Disable dynamic ODIV3. + p_DYN_ODIV4_SEL = "FALSE", # Disable dynamic ODIV4. + p_DYN_ODIV5_SEL = "FALSE", # Disable dynamic ODIV5. + p_DYN_ODIV6_SEL = "FALSE", # Disable dynamic ODIV6. + p_DYN_DT0_SEL = "FALSE", # Static CLKOUT0 duty control. + p_DYN_DT1_SEL = "FALSE", # Static CLKOUT1 duty control. + p_DYN_DT2_SEL = "FALSE", # Static CLKOUT2 duty control. + p_DYN_DT3_SEL = "FALSE", # Static CLKOUT3 duty control. + p_DYN_ICP_SEL = "FALSE", # Static ICP_SEL. + # ICP_SEL determined by the toolchain + p_DYN_LPF_SEL = "FALSE", # Static LPF_RES/LPF_CAP; + # LPF_RES/LPF_CAP determined by the toolchain + + i_FBDSEL = Constant(0, 6), # Dynamic FBDIV control. + i_IDSEL = Constant(0, 6), # Dynamic IDIV control. + i_MDSEL = Constant(0, 7), # Dynamic MDIV integer control. + i_MDSEL_FRAC = Constant(0, 3), # Dynamic MDIV fractional control. + i_ODSEL0 = Constant(0, 7), # Dynamic ODIV0 integer control. + i_ODSEL0_FRAC = Constant(0, 3), # Dynamic ODIV0 fractional control. + i_ODSEL1 = Constant(0, 7), # Dynamic ODIV1 control. + i_ODSEL2 = Constant(0, 7), # Dynamic ODIV2 control. + i_ODSEL3 = Constant(0, 7), # Dynamic ODIV3 control. + i_ODSEL4 = Constant(0, 7), # Dynamic ODIV4 control. + i_ODSEL5 = Constant(0, 7), # Dynamic ODIV5 control. + i_ODSEL6 = Constant(0, 7), # Dynamic ODIV6 control. + i_DT0 = Constant(0, 4), # Dynamic duty cycle control for CLKOUT0. + i_DT1 = Constant(0, 4), # Dynamic duty cycle control for CLKOUT1. + i_DT2 = Constant(0, 4), # Dynamic duty cycle control for CLKOUT2. + i_DT3 = Constant(0, 4), # Dynamic duty cycle control for CLKOUT3. + i_ENCLK0 = 1, # Dynamic CLKOUT0 enable. + i_ENCLK1 = 1, # Dynamic CLKOUT1 enable. + i_ENCLK2 = 1, # Dynamic CLKOUT2 enable. + i_ENCLK3 = 1, # Dynamic CLKOUT3 enable. + i_ENCLK4 = 1, # Dynamic CLKOUT4 enable. + i_ENCLK5 = 1, # Dynamic CLKOUT5 enable. + i_ENCLK6 = 1, # Dynamic CLKOUT6 enable. + i_ICPSEL = Constant(0, 6), # Dynamic ICP current control. + i_LPFRES = Constant(0, 3), # Dynamic LPFRES control. + i_LPFCAP = Constant(0, 2), # Dynamic LPFCAP control. + ) + + for i in range(0, len(self.clkouts)): + clk, f, p, m = self.clkouts[i] + self.params["o_CLKOUT%d" % i] = clk + self.params["p_CLKOUT%d_EN" % i] = "TRUE" + self.params["p_ODIV%d_SEL" % i] = config["odiv%d" % i] + self.params["p_CLKOUT%d_PE_COARSE" % i] = config["pe%d" % i] + self.params["p_CLKOUT%d_PE_FINE" % i] = config["pe%d_fine" % i] + + self.specials += Instance(instance_name, **self.params) From 85dadb827a374ff3e762cca5660da7c9e4b672af Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 29 Aug 2023 14:25:04 +0200 Subject: [PATCH 155/454] clock/gowin_gw5a: Fix copyright. --- litex/soc/cores/clock/gowin_gw5a.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/clock/gowin_gw5a.py b/litex/soc/cores/clock/gowin_gw5a.py index 1976e042a..79de44f96 100644 --- a/litex/soc/cores/clock/gowin_gw5a.py +++ b/litex/soc/cores/clock/gowin_gw5a.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2021-2022 Florent Kermarrec +# Copyright (c) 2023 Icenowy Zheng # SPDX-License-Identifier: BSD-2-Clause from migen import * From 9528f89d45e8812ced5f6b16d3d6da31cae10d6d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 29 Aug 2023 17:15:45 +0200 Subject: [PATCH 156/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 1b36baf06..9dcedf125 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ - build/efinix : Fixed AsyncFIFO issues (Minimum of 2 buffer stages). - software/gcc : Fixed Ubuntu 22.04 GCC compilation issues. - build/efinix : Fixed hardcoded version. + - litedram/gw2ddrphy : Fixed latencies and tested on Tang Primer 20K. [> Added -------- @@ -58,6 +59,7 @@ - liteiclink/serdes : Added tx/rx_clk sharing capabilities on Xilinx transceivers. - soc/cores/spi : Added new SPIMMAP core allowing SPI accesses through MMAP. - soc/interconnect/stream : Added pipe_valid/pipe_ready parameters to BufferizeEndpoints. + - soc/cores/clock : Added initial GW5A support. [> Changed ---------- From 6dff371835a8f3fd87e4c30a2111541a8f72bfc6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2023 09:16:46 +0200 Subject: [PATCH 157/454] build/efinix/common: Simplify IO exclusion in EfinixTristateImpl and fix corner cases (ex eth_mdio that was not automatically excluded). --- litex/build/efinix/common.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 6bfe530ff..1c307c8a5 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -89,16 +89,12 @@ def __init__(self, platform, io, o, oe, i=None): platform.toolchain.ifacewriter.blocks.append(block) - # Remove the group from the io list - exclude = platform.get_pin_name(io[0], without_index=True) - - # In case of a single signal, there is still a '0' index - # to be remove at the end - if (nbits == 1) and (exclude[:-1] == '0'): - exclude = exclude[:-1] - - platform.toolchain.excluded_ios.append(exclude) - + # Exclude IO. + if isinstance(io, Signal): + exclude_io = io + else: + exclude_io = platform.get_pin_name(io[0], without_index=True) + platform.toolchain.excluded_ios.append(exclude_io) class EfinixTristate(Module): @staticmethod From c0ab4ed1c167dbd7ea1c2a20f13a053e46eeac8f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2023 10:52:13 +0200 Subject: [PATCH 158/454] build/io: Allow passing clk as str on DDRInput/Output, wrap DDROutput IOs and minor ident fixes. --- litex/build/io.py | 64 +++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/litex/build/io.py b/litex/build/io.py index 73ba48015..28a965415 100644 --- a/litex/build/io.py +++ b/litex/build/io.py @@ -20,7 +20,7 @@ def __init__(self, i_p, i_n, o): def iter_expressions(self): yield self, "i_p", SPECIAL_INPUT yield self, "i_n", SPECIAL_INPUT - yield self, "o", SPECIAL_OUTPUT + yield self, "o" , SPECIAL_OUTPUT @staticmethod def lower(dr): @@ -35,7 +35,7 @@ def __init__(self, i, o_p, o_n): self.o_n = wrap(o_n) def iter_expressions(self): - yield self, "i", SPECIAL_INPUT + yield self, "i" , SPECIAL_INPUT yield self, "o_p", SPECIAL_OUTPUT yield self, "o_n", SPECIAL_OUTPUT @@ -61,8 +61,8 @@ def __init__(self, i, o, clk=ClockSignal()): self.clk_domain = None if not hasattr(clk, "cd") else clk.cd def iter_expressions(self): - yield self, "i", SPECIAL_INPUT - yield self, "o", SPECIAL_OUTPUT + yield self, "i" , SPECIAL_INPUT + yield self, "o" , SPECIAL_OUTPUT yield self, "clk", SPECIAL_INPUT @staticmethod @@ -80,26 +80,26 @@ def __init__(self, io, o, oe, i, clk): _o = Signal() _oe = Signal() _i = Signal() - self.specials += SDROutput(o, _o, clk) - self.specials += SDRInput(_i, i, clk) + self.specials += SDROutput(o, _o, clk) + self.specials += SDRInput(_i, i, clk) self.submodules += InferedSDRIO(oe, _oe, clk) - self.specials += Tristate(io, _o, _oe, _i) + self.specials += Tristate(io, _o, _oe, _i) class SDRTristate(Special): def __init__(self, io, o, oe, i, clk=ClockSignal()): assert len(i) == len(o) == len(oe) Special.__init__(self) - self.io = wrap(io) - self.o = wrap(o) - self.oe = wrap(oe) - self.i = wrap(i) - self.clk = wrap(clk) + self.io = wrap(io) + self.o = wrap(o) + self.oe = wrap(oe) + self.i = wrap(i) + self.clk = wrap(clk) def iter_expressions(self): - yield self, "io", SPECIAL_INOUT - yield self, "o", SPECIAL_INPUT - yield self, "oe", SPECIAL_INPUT - yield self, "i", SPECIAL_OUTPUT + yield self, "io" , SPECIAL_INOUT + yield self, "o" , SPECIAL_INPUT + yield self, "oe" , SPECIAL_INPUT + yield self, "i" , SPECIAL_OUTPUT yield self, "clk", SPECIAL_INPUT @staticmethod @@ -114,12 +114,12 @@ def __init__(self, i, o1, o2, clk=ClockSignal()): self.i = wrap(i) self.o1 = wrap(o1) self.o2 = wrap(o2) - self.clk = wrap(clk) + self.clk = clk if isinstance(clk, str) else wrap(clk) def iter_expressions(self): - yield self, "i", SPECIAL_INPUT - yield self, "o1", SPECIAL_OUTPUT - yield self, "o2", SPECIAL_OUTPUT + yield self, "i" , SPECIAL_INPUT + yield self, "o1" , SPECIAL_OUTPUT + yield self, "o2" , SPECIAL_OUTPUT yield self, "clk", SPECIAL_INPUT @staticmethod @@ -130,15 +130,15 @@ def lower(dr): class DDROutput(Special): def __init__(self, i1, i2, o, clk=ClockSignal()): Special.__init__(self) - self.i1 = i1 - self.i2 = i2 - self.o = o - self.clk = clk + self.i1 = wrap(i1) + self.i2 = wrap(i2) + self.o = wrap(o) + self.clk = clk if isinstance(clk, str) else wrap(clk) def iter_expressions(self): - yield self, "i1", SPECIAL_INPUT - yield self, "i2", SPECIAL_INPUT - yield self, "o", SPECIAL_OUTPUT + yield self, "i1" , SPECIAL_INPUT + yield self, "i2" , SPECIAL_INPUT + yield self, "o" , SPECIAL_OUTPUT yield self, "clk", SPECIAL_INPUT @staticmethod @@ -170,13 +170,13 @@ def __init__(self, io, o1, o2, oe1, oe2, i1, i2, clk=ClockSignal()): self.clk = clk def iter_expressions(self): - yield self, "io", SPECIAL_INOUT - yield self, "o1", SPECIAL_INPUT - yield self, "o2", SPECIAL_INPUT + yield self, "io" , SPECIAL_INOUT + yield self, "o1" , SPECIAL_INPUT + yield self, "o2" , SPECIAL_INPUT yield self, "oe1", SPECIAL_INPUT yield self, "oe2", SPECIAL_INPUT - yield self, "i1", SPECIAL_OUTPUT - yield self, "i2", SPECIAL_OUTPUT + yield self, "i1" , SPECIAL_OUTPUT + yield self, "i2" , SPECIAL_OUTPUT yield self, "clk", SPECIAL_INPUT @staticmethod From c2714df198719ad77dbcfe00fd2bb6a9ae16c773 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2023 11:25:27 +0200 Subject: [PATCH 159/454] build/efinix/common: Add initial EfinixDDROutput/EfinixDDRInput implementation. Still need to figure out a few things: - Clk is passed as a string for now. - IOs exclusion still handled externally. --- litex/build/efinix/common.py | 63 ++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 1c307c8a5..5434db4ce 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -120,10 +120,73 @@ class EfinixSDRTristate(Module): def lower(dr): return EfinixSDRTristateImpl(dr.platform, dr.io, dr.o, dr.oe, dr.i, dr.clk) +# Efinix DDROutput --------------------------------------------------------------------------------- + +class EfinixDDROutputImpl(Module): + def __init__(self, platform, i1, i2, o, clk): + io_name = platform.get_pin_name(o) + io_pad = platform.get_pin_location(o) + io_prop = platform.get_pin_properties(o) + io_data_h = platform.add_iface_io(io_name + "_HI") + io_data_l = platform.add_iface_io(io_name + "_LO") + self.comb += io_data_h.eq(i1) + self.comb += io_data_l.eq(i2) + block = { + "type" : "GPIO", + "mode" : "OUTPUT", + "name" : io_name, + "location" : io_pad, + "properties" : io_prop, + "size" : 1, + "out_reg" : "DDIO_RESYNC", + "out_clk_pin" : clk, # FIXME. + "is_inclk_inverted" : False, + "drive_strength" : 4 # FIXME: Get it from constraints. + } + platform.toolchain.ifacewriter.blocks.append(block) + # FIXME: Integrate IO exclusion. + +class EfinixDDROutput: + @staticmethod + def lower(dr): + return EfinixDDROutputImpl(dr.platform, dr.i1, dr.i2, dr.o, dr.clk) + +# Efinix DDRInput ---------------------------------------------------------------------------------- + +class EfinixDDRInputImpl(Module): + def __init__(self, platform, i, o1, o2, clk): + io_name = platform.get_pin_name(i) + io_pad = platform.get_pin_location(i) + io_prop = platform.get_pin_properties(i) + io_data_h = platform.add_iface_io(io_name + "_HI") + io_data_l = platform.add_iface_io(io_name + "_LO") + self.comb += o1.eq(io_data_h) + self.comb += o2.eq(io_data_l) + block = { + "type" : "GPIO", + "mode" : "INPUT", + "name" : io_name, + "location" : io_pad, + "properties" : io_prop, + "size" : 1, + "in_reg" : "DDIO_RESYNC", + "in_clk_pin" : clk, # FIXME. + "is_inclk_inverted" : False + } + platform.toolchain.ifacewriter.blocks.append(block) + # FIXME: Integrate IO exclusion. + +class EfinixDDRInput: + @staticmethod + def lower(dr): + return EfinixDDRInputImpl(dr.platform, dr.i, dr.o1, dr.o2, dr.clk) + # Efinix Special Overrides ------------------------------------------------------------------------- efinix_special_overrides = { AsyncResetSynchronizer : EfinixAsyncResetSynchronizer, Tristate : EfinixTristate, SDRTristate : EfinixSDRTristate, + DDROutput : EfinixDDROutput, + DDRInput : EfinixDDRInput, } From 434e2225eafa6e1f883b0566c9b4755af441ee71 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2023 17:22:57 +0200 Subject: [PATCH 160/454] software/liblitedram: Fix swap_bit warning. --- litex/soc/software/liblitedram/sdram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index 3d69d16cf..a58981978 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -238,7 +238,7 @@ void sdram_software_control_off(void) { /* Mode Register */ /*-----------------------------------------------------------------------*/ -int swap_bit(int num, int a, int b) { +__attribute__((unused)) static int swap_bit(int num, int a, int b) { if (((num >> a) & 1) != ((num >> b) & 1)) { num ^= (1 << a); num ^= (1 << b); From 72590dfde3d798e6f9f710a6973a046a459b94bf Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2023 17:44:00 +0200 Subject: [PATCH 161/454] software/libliteeth: Fix udp_set_callback warning. --- litex/soc/software/libliteeth/tftp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/software/libliteeth/tftp.c b/litex/soc/software/libliteeth/tftp.c index 8c8167a19..f3b53fd75 100644 --- a/litex/soc/software/libliteeth/tftp.c +++ b/litex/soc/software/libliteeth/tftp.c @@ -145,7 +145,7 @@ int tftp_get(uint32_t ip, uint16_t server_port, const char *filename, if(!udp_arp_resolve(ip)) return -1; - udp_set_callback(rx_callback); + udp_set_callback((udp_callback) rx_callback); dst_buffer = buffer; @@ -201,7 +201,7 @@ int tftp_put(uint32_t ip, uint16_t server_port, const char *filename, if(!udp_arp_resolve(ip)) return -1; - udp_set_callback(rx_callback); + udp_set_callback((udp_callback) rx_callback); packet_data = udp_get_tx_buffer(); From ff0df100e93742e7af21251e8a52fba16078a60d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2023 18:08:36 +0200 Subject: [PATCH 162/454] build/efinix: Add get_pin (from sig) to EfinixPlatform and use it to simplify/fix IOs exclusion. --- litex/build/efinix/common.py | 12 +++--------- litex/build/efinix/platform.py | 5 +++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 5434db4ce..1b662515d 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -88,13 +88,7 @@ def __init__(self, platform, io, o, oe, i=None): } platform.toolchain.ifacewriter.blocks.append(block) - - # Exclude IO. - if isinstance(io, Signal): - exclude_io = io - else: - exclude_io = platform.get_pin_name(io[0], without_index=True) - platform.toolchain.excluded_ios.append(exclude_io) + platform.toolchain.excluded_ios.append(platform.get_pin(io)) class EfinixTristate(Module): @staticmethod @@ -144,7 +138,7 @@ def __init__(self, platform, i1, i2, o, clk): "drive_strength" : 4 # FIXME: Get it from constraints. } platform.toolchain.ifacewriter.blocks.append(block) - # FIXME: Integrate IO exclusion. + platform.toolchain.excluded_ios.append(platform.get_pin(o)) class EfinixDDROutput: @staticmethod @@ -174,7 +168,7 @@ def __init__(self, platform, i, o1, o2, clk): "is_inclk_inverted" : False } platform.toolchain.ifacewriter.blocks.append(block) - # FIXME: Integrate IO exclusion. + platform.toolchain.excluded_ios.append(platform.get_pin(i)) class EfinixDDRInput: @staticmethod diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index 2ca80593a..a38095da9 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -119,6 +119,11 @@ def get_pin_properties(self, sig): return ret return None + def get_pin(self, sig): + while isinstance(sig, _Slice) and hasattr(sig, "value"): + sig = sig.value + return sig + def get_pin_name(self, sig, without_index=False): if sig is None: return None From 9854c9f3228b8c3ff0dd8a66c1afc1f3f3c536a2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 30 Aug 2023 18:11:11 +0200 Subject: [PATCH 163/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 9dcedf125..6ce9e8dda 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -60,6 +60,7 @@ - soc/cores/spi : Added new SPIMMAP core allowing SPI accesses through MMAP. - soc/interconnect/stream : Added pipe_valid/pipe_ready parameters to BufferizeEndpoints. - soc/cores/clock : Added initial GW5A support. + - build/efinix : Added initial EfinixDDROutput/Input and simplified IOs exclusion. [> Changed ---------- From a071cc343db0686799faf8df0e281c3d67d052dd Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 31 Aug 2023 11:36:24 +0200 Subject: [PATCH 164/454] litex/soc/integration/soc: add_etherxx: when eth_rx_clk is eth_tx_clk only apply constraints on eth_rx_clk --- litex/soc/integration/soc.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index b46bfb68f..558a674eb 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1702,8 +1702,11 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, eth_tx_clk = getattr(phy, "crg", phy).cd_eth_tx.clk if not isinstance(phy, LiteEthPHYModel) and not getattr(phy, "model", False): self.platform.add_period_constraint(eth_rx_clk, 1e9/phy.rx_clk_freq) - self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq) - self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk, eth_tx_clk) + if not eth_rx_clk is eth_tx_clk: + self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq) + self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk, eth_tx_clk) + else: + self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk) # Add Etherbone -------------------------------------------------------------------------------- def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, @@ -1761,8 +1764,11 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, eth_tx_clk = getattr(phy, "crg", phy).cd_eth_tx.clk if not isinstance(phy, LiteEthPHYModel) and not getattr(phy, "model", False): self.platform.add_period_constraint(eth_rx_clk, 1e9/phy.rx_clk_freq) - self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq) - self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk, eth_tx_clk) + if not eth_rx_clk is eth_tx_clk: + self.platform.add_period_constraint(eth_tx_clk, 1e9/phy.tx_clk_freq) + self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk, eth_tx_clk) + else: + self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk) # Add SPI Flash -------------------------------------------------------------------------------- def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, phy=None, rate="1:1", software_debug=False, **kwargs): From 3f43481eb9874abe8121114f1596620b72c3ec2f Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 31 Aug 2023 11:42:07 +0200 Subject: [PATCH 165/454] build/efinix/efinity: build_timing_constraints: set_false_path is unidirectional -> add another one to -> from_ --- litex/build/efinix/efinity.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 8208f1df1..1508d6b3e 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -79,6 +79,8 @@ def build_timing_constraints(self, vns): for from_, to in sorted(self.false_paths, key=lambda x: (x[0].duid, x[1].duid)): tpl = "set_false_path -from [get_clocks {{{from_}}}] -to [get_clocks {{{to}}}]" sdc.append(tpl.format(from_=self._vns.get_name(from_), to=self._vns.get_name(to))) + tpl = "set_false_path -from [get_clocks {{{to}}}] -to [get_clocks {{{from_}}}]" + sdc.append(tpl.format(to=self._vns.get_name(to), from_=self._vns.get_name(from_))) # Add additional commands sdc += self.additional_sdc_commands From 2a7caa26960f66248627b9589137b10034972e08 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 31 Aug 2023 12:29:09 +0200 Subject: [PATCH 166/454] build: all platforms: override add_period_constraint only when required --- litex/build/altera/platform.py | 2 +- litex/build/anlogic/platform.py | 3 --- litex/build/efinix/platform.py | 3 --- litex/build/generic_platform.py | 4 ++-- litex/build/gowin/platform.py | 3 --- litex/build/lattice/platform.py | 3 --- litex/build/microsemi/platform.py | 3 --- litex/build/osfpga/platform.py | 3 --- litex/build/xilinx/platform.py | 3 --- 9 files changed, 3 insertions(+), 24 deletions(-) diff --git a/litex/build/altera/platform.py b/litex/build/altera/platform.py index 59f1078ff..3bef3011f 100644 --- a/litex/build/altera/platform.py +++ b/litex/build/altera/platform.py @@ -44,7 +44,7 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period): + def add_period_constraint(self, clk, period, keep=False): self.toolchain.add_period_constraint(self, clk, period, keep=False) def add_false_path_constraint(self, from_, to): diff --git a/litex/build/anlogic/platform.py b/litex/build/anlogic/platform.py index 9979223df..334c75297 100644 --- a/litex/build/anlogic/platform.py +++ b/litex/build/anlogic/platform.py @@ -34,6 +34,3 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - - def add_period_constraint(self, clk, period): - self.toolchain.add_period_constraint(self, clk, period) diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index a38095da9..007031094 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -62,9 +62,6 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period): - self.toolchain.add_period_constraint(self, clk, period) - def add_false_path_constraint(self, from_, to): if hasattr(from_, "p"): from_ = from_.p diff --git a/litex/build/generic_platform.py b/litex/build/generic_platform.py index 6e3734f5c..14dd17c5e 100644 --- a/litex/build/generic_platform.py +++ b/litex/build/generic_platform.py @@ -366,8 +366,8 @@ def request_remaining(self, *args, **kwargs): def lookup_request(self, *args, **kwargs): return self.constraint_manager.lookup_request(*args, **kwargs) - def add_period_constraint(self, clk, period): - raise NotImplementedError + def add_period_constraint(self, clk, period, keep=True): + self.toolchain.add_period_constraint(self, clk, period, keep=keep) def add_false_path_constraint(self, from_, to): raise NotImplementedError diff --git a/litex/build/gowin/platform.py b/litex/build/gowin/platform.py index 30c86bd6e..1e7fb419c 100644 --- a/litex/build/gowin/platform.py +++ b/litex/build/gowin/platform.py @@ -41,6 +41,3 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - - def add_period_constraint(self, clk, period): - self.toolchain.add_period_constraint(self, clk, period) diff --git a/litex/build/lattice/platform.py b/litex/build/lattice/platform.py index 2aaa4e77b..323b2e511 100644 --- a/litex/build/lattice/platform.py +++ b/litex/build/lattice/platform.py @@ -47,9 +47,6 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period): - self.toolchain.add_period_constraint(self, clk, period) - def add_false_path_constraint(self, from_, to): if hasattr(from_, "p"): from_ = from_.p diff --git a/litex/build/microsemi/platform.py b/litex/build/microsemi/platform.py index a324a776b..9be106e04 100644 --- a/litex/build/microsemi/platform.py +++ b/litex/build/microsemi/platform.py @@ -33,9 +33,6 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period): - self.toolchain.add_period_constraint(self, clk, period) - def add_false_path_constraint(self, from_, to): if hasattr(from_, "p"): from_ = from_.p diff --git a/litex/build/osfpga/platform.py b/litex/build/osfpga/platform.py index d3e822908..d3665ae15 100644 --- a/litex/build/osfpga/platform.py +++ b/litex/build/osfpga/platform.py @@ -35,8 +35,5 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period): - self.toolchain.add_period_constraint(self, clk, period) - def add_false_path_constraint(self, from_, to): pass # FIXME: Implement. diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index 806516038..cfe1b2f94 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -84,9 +84,6 @@ def get_edif(self, fragment, **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period, keep=True): - self.toolchain.add_period_constraint(self, clk, period, keep=keep) - def add_false_path_constraint(self, from_, to): if hasattr(from_, "p"): from_ = from_.p From 46800176aec7edf8a38f88076d4460840d98ef48 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 31 Aug 2023 14:39:34 +0200 Subject: [PATCH 167/454] build/xx/toolchains: allows override clock naming --- litex/build/altera/platform.py | 4 ++-- litex/build/altera/quartus.py | 13 ++++++++----- litex/build/anlogic/anlogic.py | 7 +++++-- litex/build/efinix/efinity.py | 15 ++++++++++----- litex/build/generic_platform.py | 4 ++-- litex/build/generic_toolchain.py | 6 +++--- litex/build/gowin/gowin.py | 7 +++++-- litex/build/lattice/diamond.py | 2 +- litex/build/lattice/icestorm.py | 2 +- litex/build/lattice/radiant.py | 10 ++++++---- litex/build/lattice/trellis.py | 2 +- litex/build/microsemi/libero_soc.py | 9 ++++++--- litex/build/osfpga/osfpga.py | 7 +++++-- litex/build/xilinx/f4pga.py | 2 +- litex/build/xilinx/ise.py | 2 +- litex/build/xilinx/vivado.py | 9 ++++++--- 16 files changed, 63 insertions(+), 38 deletions(-) diff --git a/litex/build/altera/platform.py b/litex/build/altera/platform.py index 3bef3011f..a389a24f8 100644 --- a/litex/build/altera/platform.py +++ b/litex/build/altera/platform.py @@ -44,8 +44,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) - def add_period_constraint(self, clk, period, keep=False): - self.toolchain.add_period_constraint(self, clk, period, keep=False) + def add_period_constraint(self, clk, period, keep=False, name=None): + self.toolchain.add_period_constraint(self, clk, period, keep=keep, name=name) def add_false_path_constraint(self, from_, to): if hasattr(from_, "p"): diff --git a/litex/build/altera/quartus.py b/litex/build/altera/quartus.py index 61877283e..f85f3a4c0 100644 --- a/litex/build/altera/quartus.py +++ b/litex/build/altera/quartus.py @@ -89,17 +89,20 @@ def build_timing_constraints(self, vns): sdc = [] # Clock constraints - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): is_port = False for sig, pins, others, resname in self.named_sc: if sig == vns.get_name(clk): is_port = True + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig if is_port: - tpl = "create_clock -name {clk} -period {period} [get_ports {{{clk}}}]" - sdc.append(tpl.format(clk=vns.get_name(clk), period=str(period))) + tpl = "create_clock -name {name} -period {period} [get_ports {{{clk}}}]" + sdc.append(tpl.format(name=name, clk=clk_sig, period=str(period))) else: - tpl = "create_clock -name {clk} -period {period} [get_nets {{{clk}}}]" - sdc.append(tpl.format(clk=vns.get_name(clk), period=str(period))) + tpl = "create_clock -name {name} -period {period} [get_nets {{{clk}}}]" + sdc.append(tpl.format(name=name, clk=clk_sig, period=str(period))) # Enable automatical constraint generation for PLLs sdc.append("derive_pll_clocks -use_net_name") diff --git a/litex/build/anlogic/anlogic.py b/litex/build/anlogic/anlogic.py index 838f0bf9c..11a3bf223 100644 --- a/litex/build/anlogic/anlogic.py +++ b/litex/build/anlogic/anlogic.py @@ -62,8 +62,11 @@ def build_io_constraints(self): def build_timing_constraints(self, vns): sdc = [] - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): - sdc.append(f"create_clock -name {vns.get_name(clk)} -period {str(period)} [get_ports {{{vns.get_name(clk)}}}]") + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig + sdc.append(f"create_clock -name {name} -period {str(period)} [get_ports {{{clk_sig}}}]") tools.write_to_file("top.sdc", "\n".join(sdc)) return ("top.sdc", "SDC") diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 1508d6b3e..9e2592e01 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -63,17 +63,22 @@ def build_timing_constraints(self, vns): sdc = [] # Clock constraints - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): is_port = False for sig, pins, others, resname in self.named_sc: if sig == self._vns.get_name(clk): is_port = True + + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig + if is_port: - tpl = "create_clock -name {clk} -period {period} [get_ports {{{clk}}}]" - sdc.append(tpl.format(clk=self._vns.get_name(clk), period=str(period))) + tpl = "create_clock -name {name} -period {period} [get_ports {{{clk}}}]" + sdc.append(tpl.format(name=name, clk=clk_sig, period=str(period))) else: - tpl = "create_clock -name {clk} -period {period} [get_nets {{{clk}}}]" - sdc.append(tpl.format(clk=self._vns.get_name(clk), period=str(period))) + tpl = "create_clock -name {name} -period {period} [get_nets {{{clk}}}]" + sdc.append(tpl.format(name=name, clk=clk_sig, period=str(period))) # False path constraints for from_, to in sorted(self.false_paths, key=lambda x: (x[0].duid, x[1].duid)): diff --git a/litex/build/generic_platform.py b/litex/build/generic_platform.py index 14dd17c5e..a9a24eeaa 100644 --- a/litex/build/generic_platform.py +++ b/litex/build/generic_platform.py @@ -366,8 +366,8 @@ def request_remaining(self, *args, **kwargs): def lookup_request(self, *args, **kwargs): return self.constraint_manager.lookup_request(*args, **kwargs) - def add_period_constraint(self, clk, period, keep=True): - self.toolchain.add_period_constraint(self, clk, period, keep=keep) + def add_period_constraint(self, clk, period, keep=True, name=None): + self.toolchain.add_period_constraint(self, clk, period, keep=keep, name=name) def add_false_path_constraint(self, from_, to): raise NotImplementedError diff --git a/litex/build/generic_toolchain.py b/litex/build/generic_toolchain.py index 46a01e459..488b92178 100644 --- a/litex/build/generic_toolchain.py +++ b/litex/build/generic_toolchain.py @@ -162,7 +162,7 @@ def build(self, platform, fragment, return v_output.ns - def add_period_constraint(self, platform, clk, period, keep=True): + def add_period_constraint(self, platform, clk, period, keep=True, name=None): if clk is None: return if hasattr(clk, "p"): @@ -171,10 +171,10 @@ def add_period_constraint(self, platform, clk, period, keep=True): clk.attr.add("keep") period = math.floor(period*1e3)/1e3 # Round to lowest picosecond. if clk in self.clocks: - if period != self.clocks[clk]: + if period != self.clocks[clk][0]: raise ValueError("Clock already constrained to {:.2f}ns, new constraint to {:.2f}ns" .format(self.clocks[clk], period)) - self.clocks[clk] = period + self.clocks[clk] = [period, name] def add_false_path_constraint(self, platform, from_, to, keep=True): if keep: diff --git a/litex/build/gowin/gowin.py b/litex/build/gowin/gowin.py index dac35c25a..a0e693e14 100644 --- a/litex/build/gowin/gowin.py +++ b/litex/build/gowin/gowin.py @@ -89,8 +89,11 @@ def build_io_constraints(self): def build_timing_constraints(self, vns): sdc = [] - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): - sdc.append(f"create_clock -name {vns.get_name(clk)} -period {str(period)} [get_ports {{{vns.get_name(clk)}}}]") + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig + sdc.append(f"create_clock -name {name} -period {str(period)} [get_ports {{{clk_sig}}}]") tools.write_to_file(f"{self._build_name}.sdc", "\n".join(sdc)) return (f"{self._build_name}.sdc", "SDC") diff --git a/litex/build/lattice/diamond.py b/litex/build/lattice/diamond.py index 494b01644..6ab994ebc 100644 --- a/litex/build/lattice/diamond.py +++ b/litex/build/lattice/diamond.py @@ -84,7 +84,7 @@ def build_io_constraints(self): lpf.append("\n".join(self.named_pc)) # Note: .lpf is only used post-synthesis, Synplify constraints clocks by default to 200MHz. - for clk, period in self.clocks.items(): + for clk, [period, _] in self.clocks.items(): clk_name = self._vns.get_name(clk) lpf.append("FREQUENCY {} \"{}\" {} MHz;".format( "PORT" if clk_name in [name for name, _, _, _ in self.named_sc] else "NET", diff --git a/litex/build/lattice/icestorm.py b/litex/build/lattice/icestorm.py index 24f164c64..0664a063a 100644 --- a/litex/build/lattice/icestorm.py +++ b/litex/build/lattice/icestorm.py @@ -67,7 +67,7 @@ def build_io_constraints(self): def build_timing_constraints(self, vns): r = "" - for clk, period in self.clocks.items(): + for clk, [period, _] in self.clocks.items(): r += """ctx.addClock("{}", {})\n""".format(vns.get_name(clk), 1e3/period) tools.write_to_file(self._build_name + "_pre_pack.py", r) return (self._build_name + "_pre_pack.py", "PY") diff --git a/litex/build/lattice/radiant.py b/litex/build/lattice/radiant.py index a0ab290a7..433c2758f 100644 --- a/litex/build/lattice/radiant.py +++ b/litex/build/lattice/radiant.py @@ -56,13 +56,15 @@ def _build_pdc(named_sc, named_pc, clocks, vns, build_name): pdc.append("\n".join(named_pc)) # Note: .pdc is only used post-synthesis, Synplify constraints clocks by default to 200MHz. - for clk, period in clocks.items(): - clk_name = vns.get_name(clk) + for clk, [period, clk_name] in clocks.items(): + clk_sig = vns.get_name(clk) + if clk_name is None: + clk_name = clk_sig pdc.append("create_clock -period {} -name {} [{} {}];".format( str(period), clk_name, - "get_ports" if clk_name in [name for name, _, _, _ in named_sc] else "get_nets", - clk_name + "get_ports" if clk_sig in [name for name, _, _, _ in named_sc] else "get_nets", + clk_sig )) tools.write_to_file(build_name + ".pdc", "\n".join(pdc)) diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index 367864237..2651f62af 100644 --- a/litex/build/lattice/trellis.py +++ b/litex/build/lattice/trellis.py @@ -145,7 +145,7 @@ def nextpnr_ecp5_parse_device(self, device): "lfe5um5g-85f": "um5g-85k", } - def add_period_constraint(self, platform, clk, period): + def add_period_constraint(self, platform, clk, period, name=None): if clk is None: return if hasattr(clk, "p"): diff --git a/litex/build/microsemi/libero_soc.py b/litex/build/microsemi/libero_soc.py index b4ca3cde7..87c7949d2 100644 --- a/litex/build/microsemi/libero_soc.py +++ b/litex/build/microsemi/libero_soc.py @@ -187,10 +187,13 @@ def build_project(self): def build_timing_constraints(self, vns): sdc = [] - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig sdc.append( - "create_clock -name {clk} -period " + str(period) + - " [get_nets {clk}]".format(clk=vns.get_name(clk))) + "create_clock -name {name} -period " + str(period) + + " [get_nets {clk}]".format(name=name, clk=clk_sig)) for from_, to in sorted(self.false_paths, key=lambda x: (x[0].duid, x[1].duid)): sdc.append( diff --git a/litex/build/osfpga/osfpga.py b/litex/build/osfpga/osfpga.py index c7652e535..382e864fc 100644 --- a/litex/build/osfpga/osfpga.py +++ b/litex/build/osfpga/osfpga.py @@ -35,8 +35,11 @@ def build_io_constraints(self): def build_timing_constraints(self, vns): sdc = [] - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): - sdc.append(f"create_clock -name {vns.get_name(clk)} -period {str(period)} [get_ports {{{vns.get_name(clk)}}}]") + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig + sdc.append(f"create_clock -name {name} -period {str(period)} [get_ports {{{clk_sig}}}]") with open(f"{self._build_name}.sdc", "w") as f: f.write("\n".join(sdc)) return (self._build_name + ".sdc", "SDC") diff --git a/litex/build/xilinx/f4pga.py b/litex/build/xilinx/f4pga.py index 1ce6f9b4c..1d78235c3 100644 --- a/litex/build/xilinx/f4pga.py +++ b/litex/build/xilinx/f4pga.py @@ -69,7 +69,7 @@ def build_io_constraints(self): def build_timing_constraints(self, vns): self.platform.add_platform_command(_xdc_separator("Clock constraints")) - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): self.platform.add_platform_command( "create_clock -period " + str(period) + " {clk}", clk=clk) diff --git a/litex/build/xilinx/ise.py b/litex/build/xilinx/ise.py index d62c9ca85..a2fbda9a4 100755 --- a/litex/build/xilinx/ise.py +++ b/litex/build/xilinx/ise.py @@ -205,7 +205,7 @@ def run_script(self, script): # constraints and other constraints otherwise it will be unable to trace # them through clock objects like DCM and PLL objects. - def add_period_constraint(self, platform, clk, period, keep=True): + def add_period_constraint(self, platform, clk, period, keep=True, name=None): if clk is None: return if hasattr(clk, "p"): diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 9b51b65ad..ef3bcf318 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -169,10 +169,13 @@ def get_clk_type(clk): False : "nets", True : "ports", }[hasattr(clk, "port")] - for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig self.platform.add_platform_command( - "create_clock -name {clk} -period " + str(period) + - " [get_" + get_clk_type(clk) + " {clk}]", clk=clk) + "create_clock -name {name} -period " + str(period) + + " [get_" + get_clk_type(clk) + " {clk}]", name=name, clk=clk) for _from, _to in sorted(self.false_paths, key=lambda x: (x[0].duid, x[1].duid)): self.platform.add_platform_command( "set_clock_groups " From ad924a522ad445c68771e51f9671d529701324ff Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 31 Aug 2023 16:03:52 +0200 Subject: [PATCH 168/454] interconnect/stream/AsyncFIFO: Remove Efinix workaround since seems to be solved with Efinity 2023.x. --- litex/soc/interconnect/stream.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index 14ddda96e..18eca1533 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -236,19 +236,11 @@ class AsyncFIFO(_FIFOWrapper): def __init__(self, layout, depth=None, buffered=False): depth = 4 if depth is None else depth assert depth >= 4 - nbuffers = 0 - if buffered: - nbuffers = 1 - from litex.build.efinix import EfinixPlatform - if isinstance(LiteXContext.platform, EfinixPlatform): - nbuffers = 2 # Minimum of 2 buffers required on Efinix FPGAs. _FIFOWrapper.__init__(self, - fifo_class = fifo.AsyncFIFOBuffered if nbuffers > 0 else fifo.AsyncFIFO, + fifo_class = fifo.AsyncFIFOBuffered if buffered else fifo.AsyncFIFO, layout = layout, depth = depth ) - if nbuffers > 1: - ClockDomainsRenamer("read")(BufferizeEndpoints({"source": DIR_SOURCE})(self)) # ClockDomainCrossing ------------------------------------------------------------------------------ From 41357aba7d6a657163f8be6248f512b5881a5323 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 31 Aug 2023 16:38:50 +0200 Subject: [PATCH 169/454] xilinx/vivado: Fix issue with #1755. --- litex/build/xilinx/vivado.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index ef3bcf318..65f37938a 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -170,9 +170,8 @@ def get_clk_type(clk): True : "ports", }[hasattr(clk, "port")] for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): - clk_sig = self._vns.get_name(clk) if name is None: - name = clk_sig + name = clk self.platform.add_platform_command( "create_clock -name {name} -period " + str(period) + " [get_" + get_clk_type(clk) + " {clk}]", name=name, clk=clk) From fadf47d353abb56c072e6a6822f4c93db3ab8c52 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 31 Aug 2023 16:52:48 +0200 Subject: [PATCH 170/454] build/lattice/trellis: fix add_period_constraint signature (missing keep arg) --- litex/build/lattice/trellis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/lattice/trellis.py b/litex/build/lattice/trellis.py index 2651f62af..80c5a0fcc 100644 --- a/litex/build/lattice/trellis.py +++ b/litex/build/lattice/trellis.py @@ -145,7 +145,7 @@ def nextpnr_ecp5_parse_device(self, device): "lfe5um5g-85f": "um5g-85k", } - def add_period_constraint(self, platform, clk, period, name=None): + def add_period_constraint(self, platform, clk, period, keep=True, name=None): if clk is None: return if hasattr(clk, "p"): From 516038ce76d9da6718bef849c15f81a8a93e0f91 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 31 Aug 2023 16:07:12 +0200 Subject: [PATCH 171/454] soc/cores/clock/efinix: don't hardcore create_clock (fix warning because clock is created after set_false_path), explicit clock name (fix warning when signal is absorbed) --- litex/soc/cores/clock/efinix.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index 9b07aa4ba..14794294b 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -96,11 +96,13 @@ def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True): assert self.nclkouts < self.nclkouts_max clk_out_name = f"{self.name}_clkout{self.nclkouts}" if name == "" else name - self.platform.toolchain.additional_sdc_commands.append(f"create_clock -period {1e9/freq} {clk_out_name}") if cd is not None: self.platform.add_extension([(clk_out_name, 0, Pins(1))]) - self.comb += cd.clk.eq(self.platform.request(clk_out_name)) + clk_name = f"{cd.name}_clk" + clk_out = self.platform.request(clk_out_name) + self.comb += cd.clk.eq(clk_out) + self.platform.add_period_constraint(clk=clk_out, period=1e9/freq, name=clk_name) if with_reset: self.specials += AsyncResetSynchronizer(cd, ~self.locked) self.platform.toolchain.excluded_ios.append(clk_out_name) From 405296b7fd99764af21fffd94afa5075c22affa8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 31 Aug 2023 19:34:55 +0200 Subject: [PATCH 172/454] interconnect/axi/axi_full: Fix missing switch to LiteXModule. --- litex/soc/interconnect/axi/axi_full.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index bc887ac34..e073ef356 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -602,12 +602,12 @@ def get_check_parameters(ports): return data_width -class AXIInterconnectPointToPoint(Module): +class AXIInterconnectPointToPoint(LiteXModule): """AXI point to point interconnect""" def __init__(self, master, slave): self.comb += master.connect(slave) -class AXIInterconnectShared(Module): +class AXIInterconnectShared(LiteXModule): """AXI shared interconnect""" def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) From d494e3016621927eca7ffeccf119ca7c994d4f1d Mon Sep 17 00:00:00 2001 From: Radek Pesina Date: Fri, 11 Aug 2023 16:52:25 +1000 Subject: [PATCH 173/454] soc/cores/spi_mmap: Fix clock divider --- litex/soc/cores/spi/spi_mmap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/spi/spi_mmap.py b/litex/soc/cores/spi/spi_mmap.py index 77ced6bcd..7ef213137 100644 --- a/litex/soc/cores/spi/spi_mmap.py +++ b/litex/soc/cores/spi/spi_mmap.py @@ -124,7 +124,7 @@ def __init__(self, pads, data_width, sys_clk_freq, clk_settle_time=20e-9): self.sync += [ If(clk_enable, clk_count.eq(clk_count + 1), - If(clk_count == self.clk_divider[2:], + If(clk_count == self.clk_divider[1:], clk.eq(~clk), clk_count.eq(0) ), From 058cdd646bb0733fa0ea58c1920efc95f37c33f6 Mon Sep 17 00:00:00 2001 From: Richard Tucker Date: Thu, 10 Aug 2023 14:19:29 +1000 Subject: [PATCH 174/454] tools/litex_json2dts_linux: fix missed sdcard_ references --- litex/tools/litex_json2dts_linux.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/tools/litex_json2dts_linux.py b/litex/tools/litex_json2dts_linux.py index bef068663..8e059c14c 100755 --- a/litex/tools/litex_json2dts_linux.py +++ b/litex/tools/litex_json2dts_linux.py @@ -247,7 +247,7 @@ def generate_dts(d, initrd_start=None, initrd_size=None, initrd=None, root_devic """ # Voltage Regulator for LiteSDCard (if applicable) -------------------------------------------- - if "sdcore" in d["csr_bases"]: + if "sdcard_core" in d["csr_bases"]: dts += """ vreg_mmc: vreg_mmc {{ compatible = "regulator-fixed"; @@ -419,7 +419,7 @@ def generate_dts(d, initrd_start=None, initrd_size=None, initrd=None, root_devic # SDCard --------------------------------------------------------------------------------------- - if "sdcore" in d["csr_bases"]: + if "sdcard_core" in d["csr_bases"]: dts += """ mmc0: mmc@{mmc_csr_base:x} {{ compatible = "litex,mmc"; From db2ad78860f749ef54842c54b3fa82efb1eb6d76 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 1 Sep 2023 12:16:15 +0200 Subject: [PATCH 175/454] interconnect/wishbone: Add address_width property to make sure all interfaces (Wishbone/AXI-Lite/AXI) have it. --- litex/soc/interconnect/wishbone.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 5d426c997..05dab1b33 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -50,8 +50,9 @@ def __init__(self, data_width=32, adr_width=30, bursting=False, **kwargs): if kwargs.get("address_width", False): # FIXME: Improve or switch Wishbone to byte addressing instead of word addressing. adr_width = kwargs["address_width"] - int(log2(data_width//8)) - self.adr_width = adr_width - self.bursting = bursting + self.adr_width = adr_width + self.address_width = adr_width + int(log2(data_width//8)) + self.bursting = bursting Record.__init__(self, set_layout_parameters(_layout, adr_width = adr_width, data_width = data_width, From f473261bc6bb188a1b2739960ba619f6da95ad7f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 1 Sep 2023 12:19:11 +0200 Subject: [PATCH 176/454] soc/dma_bus: Make SoCDMABusHandler use the Bus Standard of the DMA Bus defined in the CPU. Also simplify code by using automatic Bus conversion of SoCBusHandler. --- litex/soc/integration/soc.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 558a674eb..72ae9acb4 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1119,19 +1119,26 @@ def add_cpu(self, name="vexriscv", variant="standard", reset_address=None, cfu=N # Create optional DMA Bus (for Cache Coherence). if hasattr(self.cpu, "dma_bus"): + if isinstance(self.cpu.dma_bus, wishbone.Interface): + dma_bus_standard = "wishbone" + elif isinstance(self.cpu.dma_bus, axi.AXILiteInterface): + dma_bus_standard = "axi_lite" + elif isinstance(self.cpu.dma_bus, axi.AXIInterface): + dma_bus_standard = "axi" + else: + raise NotImplementedError self.logger.info("CPU {} {} DMA Bus.".format( colorer(name, color="underline"), - colorer("adding", color="cyan"))) + colorer("adding", color="cyan")) + ) self.dma_bus = SoCBusHandler( name = "SoCDMABusHandler", - standard = "wishbone", - data_width = self.bus.data_width, - address_width = self.bus.get_address_width(standard="wishbone"), - bursting = self.bus.bursting + standard = dma_bus_standard, + data_width = self.cpu.dma_bus.data_width, + address_width = self.cpu.dma_bus.address_width, + bursting = self.cpu.dma_bus.bursting ) - dma_bus = wishbone.Interface(data_width=self.bus.data_width) - self.dma_bus.add_slave(name="dma", slave=dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only - self.submodules += wishbone.Converter(dma_bus, self.cpu.dma_bus) + self.dma_bus.add_slave(name="dma", slave=self.cpu.dma_bus, region=SoCRegion(origin=0x00000000, size=0x100000000)) # FIXME: covers lower 4GB only # Connect SoCController's reset to CPU reset. if hasattr(self, "ctrl"): From 57faa9102f3de89c0be83e37e070cd8de364e861 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 1 Sep 2023 12:40:03 +0200 Subject: [PATCH 177/454] CHANGES: Update. --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 6ce9e8dda..0072e94d1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -61,6 +61,9 @@ - soc/interconnect/stream : Added pipe_valid/pipe_ready parameters to BufferizeEndpoints. - soc/cores/clock : Added initial GW5A support. - build/efinix : Added initial EfinixDDROutput/Input and simplified IOs exclusion. + - soc/interconnect : Improved DMA Bus to use the same Bus Standard than the CPU DMA Bus. + - liteeth/phy : Added Artix7 2500BASE-X PHY. + - liteeth/phy : Added Gowin Arora V RGMII PHY (GW5RGMII). [> Changed ---------- From 48ab96fd43dba9cdc850b66378f99deed8a24fee Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Sat, 2 Sep 2023 11:40:58 +1000 Subject: [PATCH 178/454] soc/intregation: fix cpu name in logging Fixed CPU name being reported as irq name in logging. ``` INFO:SoC:CPU vexriscv_smp adding Interrupt(s). INFO:SoCIRQHandler:noirq IRQ added at Location 0. INFO:SoC:CPU noirq adding DMA Bus. INFO:SoCDMABusHandler:Creating Bus Handler... ``` --- litex/soc/integration/soc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 72ae9acb4..2ed96f46b 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1113,8 +1113,8 @@ def add_cpu(self, name="vexriscv", variant="standard", reset_address=None, cfu=N self.irq.enable() if hasattr(self.cpu, "reserved_interrupts"): self.cpu.interrupts.update(self.cpu.reserved_interrupts) - for name, loc in self.cpu.interrupts.items(): - self.irq.add(name, loc) + for irq_name, loc in self.cpu.interrupts.items(): + self.irq.add(irq_name, loc) self.add_config("CPU_HAS_INTERRUPT") # Create optional DMA Bus (for Cache Coherence). From 1bb4d299a6227372b3afe53b3c92c3b18de9b569 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Sat, 2 Sep 2023 11:44:09 +1000 Subject: [PATCH 179/454] vexrisc_smp: fix DMA bus address_width calculation --- litex/soc/cores/cpu/vexriscv_smp/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index 18780e187..47f0f5aee 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -337,7 +337,7 @@ def __init__(self, platform, variant): # DMA. if VexRiscvSMP.coherent_dma: - self.dma_bus = dma_bus = wishbone.Interface(data_width=VexRiscvSMP.dcache_width) + self.dma_bus = dma_bus = wishbone.Interface(data_width=VexRiscvSMP.dcache_width, address_width=32) dma_bus_stall = Signal() dma_bus_inhibit = Signal() self.cpu_params.update( From 2e6ddd9dd95665829a17922fa4cdcf2b3d12d5ca Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Tue, 8 Aug 2023 20:39:46 +0200 Subject: [PATCH 180/454] build/lattice/radiant: allow use of Windows-side (.exe) radiant toolchain under WSL2 --- litex/build/lattice/radiant.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/litex/build/lattice/radiant.py b/litex/build/lattice/radiant.py index 433c2758f..b211e88f4 100644 --- a/litex/build/lattice/radiant.py +++ b/litex/build/lattice/radiant.py @@ -209,6 +209,10 @@ def build_script(self): if self._synth_mode == "yosys": script_contents += self._yosys.get_yosys_call(target="script") + "\n" + # Radiant installed on Windows, executed from WSL2 + if "microsoft-standard" in uname().release and which("pnmainc.exe") is not None: + tool = "pnmainc.exe" + script_contents += "{tool} {tcl_script}{fail_stmt}\n".format( tool = tool, tcl_script = self._build_name + ".tcl", @@ -232,6 +236,10 @@ def run_script(self, script): shell = ["bash"] tool = "radiantc" + # Radiant installed on Windows, executed from WSL2 + if "microsoft-standard" in uname().release and which("pnmainc.exe") is not None: + tool = "pnmainc.exe" + if which(tool) is None: msg = "Unable to find Radiant toolchain, please:\n" msg += "- Add Radiant toolchain to your $PATH." From 5e4628f1fe7506d2d18b05a87dbb1bf5e5daf8be Mon Sep 17 00:00:00 2001 From: Josuah Demangeon Date: Mon, 4 Sep 2023 19:30:29 +0200 Subject: [PATCH 181/454] build/lattice/radiant: fix uname() not prefixed by 'os.' --- litex/build/lattice/radiant.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/build/lattice/radiant.py b/litex/build/lattice/radiant.py index b211e88f4..53b595d95 100644 --- a/litex/build/lattice/radiant.py +++ b/litex/build/lattice/radiant.py @@ -210,7 +210,7 @@ def build_script(self): script_contents += self._yosys.get_yosys_call(target="script") + "\n" # Radiant installed on Windows, executed from WSL2 - if "microsoft-standard" in uname().release and which("pnmainc.exe") is not None: + if "microsoft-standard" in os.uname().release and which("pnmainc.exe") is not None: tool = "pnmainc.exe" script_contents += "{tool} {tcl_script}{fail_stmt}\n".format( @@ -237,7 +237,7 @@ def run_script(self, script): tool = "radiantc" # Radiant installed on Windows, executed from WSL2 - if "microsoft-standard" in uname().release and which("pnmainc.exe") is not None: + if "microsoft-standard" in os.uname().release and which("pnmainc.exe") is not None: tool = "pnmainc.exe" if which(tool) is None: From 7afe06a60c46bb91d499c635f0a8d4f3827de0ae Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Tue, 5 Sep 2023 16:50:49 +0800 Subject: [PATCH 182/454] clock/gowin_gw5a: change allowed frequency range for GW5A- prefix When targeting GW5A-25 ES, the Gowin IDE has a more strict frequency range. Change the range when GW5A- is matched to this. Signed-off-by: Icenowy Zheng --- litex/soc/cores/clock/gowin_gw5a.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/clock/gowin_gw5a.py b/litex/soc/cores/clock/gowin_gw5a.py index 79de44f96..c5d00f217 100644 --- a/litex/soc/cores/clock/gowin_gw5a.py +++ b/litex/soc/cores/clock/gowin_gw5a.py @@ -36,7 +36,9 @@ def __init__(self, devicename, device, vco_margin=0): @staticmethod def get_vco_freq_range(device): vco_freq_range = None - if device.startswith('GW5A-') or device.startswith('GW5AT-') or device.startswith('GW5AST-'): + if device.startswith('GW5A-'): + vco_freq_range = (800e6, 1600e6) # As restricted by Gowin toolchain 1.9.9b3 + elif device.startswith('GW5A-') or device.startswith('GW5AT-') or device.startswith('GW5AST-'): vco_freq_range = (800e6, 2000e6) # datasheet values if vco_freq_range is None: raise ValueError(f"Unsupported device {device}.") @@ -45,7 +47,9 @@ def get_vco_freq_range(device): @staticmethod def get_pfd_freq_range(device): pfd_freq_range = None - if device.startswith('GW5A-') or device.startswith('GW5AT-') or device.startswith('GW5AST-'): + if device.startswith('GW5A-'): + pfd_freq_range = (19e6, 400e6) # As restricted by Gowin toolchain 1.9.9b3 + elif device.startswith('GW5AT-') or device.startswith('GW5AST-'): pfd_freq_range = (10e6, 400e6) # datasheet values if pfd_freq_range is None: raise ValueError(f"Unsupported device {device}.") From 99cb46fd3e9c8bde010f07bbe1b517ec938b75f9 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 5 Sep 2023 16:44:47 +0200 Subject: [PATCH 183/454] build/efinix/ifacewriter: fix CLKOUTx_PHASE configuration for recent efinity, keep backward compatibility --- litex/build/efinix/ifacewriter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index d01215b3d..a38f112d9 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -311,6 +311,7 @@ def generate_pll(self, block, partnumber, verbose=True): cmd += "target_freq = {\n" for i, clock in enumerate(block["clk_out"]): cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6) + cmd += ' "CLKOUT{}_PHASE": "{}",\n'.format(i, clock[2]) cmd += "}\n" cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n'.format(name) From 943d65236264c6a71b8ea8d4c2d0ee42d2f1f5a8 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 5 Sep 2023 18:13:27 +0200 Subject: [PATCH 184/454] cores/naxriscv match axi width --- litex/soc/cores/cpu/naxriscv/core.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index c1445053e..67fe62866 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -53,7 +53,8 @@ class NaxRiscv(CPU): cpu_count = 1 jtag_tap = False jtag_instruction = False - with_dma = False + with_dma = False + litedram_width = 32 # ABI. @staticmethod @@ -247,6 +248,7 @@ def find_scala_files(): def generate_netlist_name(reset_address): md5_hash = hashlib.md5() md5_hash.update(str(reset_address).encode('utf-8')) + md5_hash.update(str(NaxRiscv.litedram_width).encode('utf-8')) md5_hash.update(str(NaxRiscv.xlen).encode('utf-8')) md5_hash.update(str(NaxRiscv.cpu_count).encode('utf-8')) md5_hash.update(str(NaxRiscv.jtag_tap).encode('utf-8')) @@ -297,6 +299,7 @@ def generate_netlist(reset_address): gen_args.append(f"--reset-vector={reset_address}") gen_args.append(f"--xlen={NaxRiscv.xlen}") gen_args.append(f"--cpu-count={NaxRiscv.cpu_count}") + gen_args.append(f"--litedram-width={NaxRiscv.litedram_width}") for region in NaxRiscv.memory_regions: gen_args.append(f"--memory-region={region[0]},{region[1]},{region[2]},{region[3]}") for args in NaxRiscv.scala_args: @@ -419,13 +422,14 @@ def add_soc_components(self, soc): self.soc_bus = soc.bus # FIXME: Save SoC Bus instance to retrieve the final mem layout on finalization. def add_memory_buses(self, address_width, data_width): + NaxRiscv.litedram_width = data_width nax_data_width = 64 nax_burst_size = 64 assert data_width >= nax_data_width # FIXME: Only supporting up-conversion for now. assert data_width <= nax_burst_size*8 # FIXME: AXIUpConverter doing assumptions on minimal burst_size. mbus = axi.AXIInterface( - data_width = nax_data_width, + data_width = NaxRiscv.litedram_width, address_width = 32, id_width = 8, #TODO ) From fbae6e8e37d8a6edaf45ef5ef865b5110a2cf36f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 7 Sep 2023 14:27:12 +0200 Subject: [PATCH 185/454] CHANGES.md: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 0072e94d1..7696d32b6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -64,6 +64,7 @@ - soc/interconnect : Improved DMA Bus to use the same Bus Standard than the CPU DMA Bus. - liteeth/phy : Added Artix7 2500BASE-X PHY. - liteeth/phy : Added Gowin Arora V RGMII PHY (GW5RGMII). + - liteeth/phy : Added Titanium RGMII PHY (Tested with Ti60 F225 + RGMII adapter board). [> Changed ---------- From 6c30cb8695aa3f0760c627993031a1f4fa772416 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 8 Sep 2023 10:41:30 +0200 Subject: [PATCH 186/454] litex_setup.py: Use fixed sha1 version of Migen. Migen switched from setup.py to pyproject.toml, we'll need to handle this. --- litex_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex_setup.py b/litex_setup.py index 2354a6846..577675dfd 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -70,7 +70,7 @@ def __init__(self, url, clone="regular", develop=True, sha1=None, branch="master git_repos = { # HDL. # ---- - "migen": GitRepo(url="https://github.com/m-labs/", clone="recursive"), + "migen": GitRepo(url="https://github.com/m-labs/", clone="recursive", sha1=0xccaee68e14d3636e1d8fb2e0864dd89b1b1f7384), # LiteX SoC builder. # ------------------ From 022bdf3cdc0c251434981517ec80f7127b89cf83 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 8 Sep 2023 16:12:04 +0200 Subject: [PATCH 187/454] tools/litex_client: Add binary mode to read_memory and fix hex/binary prefix in dump_registers. --- litex/tools/litex_client.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/litex/tools/litex_client.py b/litex/tools/litex_client.py index ff6ac180f..07b741973 100644 --- a/litex/tools/litex_client.py +++ b/litex/tools/litex_client.py @@ -129,19 +129,23 @@ def dump_registers(host, csr_csv, port, filter=None, binary=False): for name, register in bus.regs.__dict__.items(): if (filter is None) or filter in name: register_value = { - True : f"{register.read():032b}", - False : f"{register.read():08x}", + True : f"0b{register.read():032b}", + False : f"0x{register.read():08x}", }[binary] - print("0x{:08x} : 0x{} {}".format(register.addr, register_value, name)) + print("0x{:08x} : {} {}".format(register.addr, register_value, name)) bus.close() -def read_memory(host, csr_csv, port, addr, length): +def read_memory(host, csr_csv, port, addr, length, binary=False): bus = RemoteClient(host=host, csr_csv=csr_csv, port=port) bus.open() for offset in range(length//4): - print(f"0x{addr + 4*offset:08x} : 0x{bus.read(addr + 4*offset):08x}") + register_value = { + True : f"0b{bus.read(addr + 4*offset):032b}", + False : f"0x{bus.read(addr + 4*offset):08x}", + }[binary] + print(f"0x{addr + 4*offset:08x} : {register_value}") bus.close() @@ -406,6 +410,7 @@ def main(): port = port, addr = addr, length = int(args.length, 0), + binary = args.binary, ) if args.write: From 112f78bde37c454209a25de7465e96d76cf87552 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 8 Sep 2023 16:42:09 +0200 Subject: [PATCH 188/454] cores/vexriscv_smp add risc-v official debug support via --with-privileged-debug Using https://github.com/SpinalHDL/NaxRiscv/blob/main/src/main/tcl/openocd/naxriscv_jtag_tunneled.tcl --- litex/soc/cores/cpu/vexriscv_smp/core.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index 47f0f5aee..3edc54540 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -47,6 +47,7 @@ class VexRiscvSMP(CPU): icache_width = 32 aes_instruction = False out_of_order_decoder = True + privileged_debug = False wishbone_memory = False wishbone_force_32b = False with_fpu = False @@ -71,6 +72,7 @@ def args_fill(parser): cpu_group.add_argument("--aes-instruction", default=None, help="Enable AES instruction acceleration.") cpu_group.add_argument("--without-out-of-order-decoder", action="store_true", help="Reduce area at cost of peripheral access speed") cpu_group.add_argument("--with-wishbone-memory", action="store_true", help="Disable native LiteDRAM interface") + cpu_group.add_argument("--with-privileged-debug", action="store_true", help="Enable official RISC-V debug spec") cpu_group.add_argument("--wishbone-force-32b", action="store_true", help="Force the wishbone bus to be 32 bits") cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU") cpu_group.add_argument("--cpu-per-fpu", default="4", help="Maximal ratio between CPU count and FPU count. Will instanciate as many FPU as necessary.") @@ -99,6 +101,7 @@ def args_read(args): if(args.icache_ways): VexRiscvSMP.icache_ways = int(args.icache_ways) if(args.aes_instruction): VexRiscvSMP.aes_instruction = bool(args.aes_instruction) if(args.without_out_of_order_decoder): VexRiscvSMP.out_of_order_decoder = False + if(args.with_privileged_debug): VexRiscvSMP.privileged_debug = True if(args.with_wishbone_memory): VexRiscvSMP.wishbone_memory = True if(args.wishbone_force_32b): VexRiscvSMP.wishbone_force_32b = True if(args.with_fpu): @@ -179,6 +182,7 @@ def generate_cluster_name(): f"{'_Wm' if VexRiscvSMP.wishbone_memory else ''}" \ f"{'_Wf32' if VexRiscvSMP.wishbone_force_32b else ''}" \ f"{'_Fpu' + str(VexRiscvSMP.cpu_per_fpu) if VexRiscvSMP.with_fpu else ''}" \ + f"{'_Pd' if VexRiscvSMP.privileged_debug else ''}" \ f"{'_Rvc' if VexRiscvSMP.with_rvc else ''}" # Default Configs Generation. @@ -264,6 +268,7 @@ def generate_netlist(): gen_args.append(f"--litedram-width={VexRiscvSMP.litedram_width}") gen_args.append(f"--aes-instruction={VexRiscvSMP.aes_instruction}") gen_args.append(f"--out-of-order-decoder={VexRiscvSMP.out_of_order_decoder}") + gen_args.append(f"--privileged-debug={VexRiscvSMP.privileged_debug}") gen_args.append(f"--wishbone-memory={VexRiscvSMP.wishbone_memory}") if(VexRiscvSMP.wishbone_force_32b): gen_args.append(f"--wishbone-force-32b={VexRiscvSMP.wishbone_force_32b}") gen_args.append(f"--fpu={VexRiscvSMP.with_fpu}") From 36ce71d59b002d6e0bb99a39e52e248853926b3e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 11 Sep 2023 10:11:58 +0200 Subject: [PATCH 189/454] clock/efinix: Avoid manual n parameter and handle it internally. --- litex/soc/cores/clock/efinix.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index 14794294b..28e64a244 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -16,8 +16,9 @@ # Efinix / TRIONPLL ---------------------------------------------------------------------------------- class EFINIXPLL(LiteXModule): + n = 0 nclkouts_max = 3 - def __init__(self, platform, n=0, version="V1_V2"): + def __init__(self, platform,version="V1_V2"): self.logger = logging.getLogger("EFINIXPLL") if version == "V1_V2": @@ -33,7 +34,8 @@ def __init__(self, platform, n=0, version="V1_V2"): self.nclkouts = 0 self.reset = Signal() self.locked = Signal() - self.name = f"pll{n}" + self.name = f"pll{self.n}" + EFINIXPLL.n += 1 # FIXME: Improve. # Create PLL block. block = {} @@ -131,12 +133,12 @@ def do_finalize(self): class TITANIUMPLL(EFINIXPLL): nclkouts_max = 5 - def __init__(self, platform, n=0): - EFINIXPLL.__init__(self, platform, n, version="V3") + def __init__(self, platform): + EFINIXPLL.__init__(self, platform, version="V3") # Efinix / TRION ---------------------------------------------------------------------------------- class TRIONPLL(EFINIXPLL): nclkouts_max = 3 - def __init__(self, platform, n=0): - EFINIXPLL.__init__(self, platform, n, version="V1_V2") + def __init__(self, platform): + EFINIXPLL.__init__(self, platform, version="V1_V2") From 412f0f59b943c6bca7ce2c65adde3eff868556db Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 12 Sep 2023 09:29:45 +0200 Subject: [PATCH 190/454] build/io: Add ClkInput/Ouptut to be able to abstract Clk Input/Output primitives. --- litex/build/io.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/litex/build/io.py b/litex/build/io.py index 28a965415..8a5445450 100644 --- a/litex/build/io.py +++ b/litex/build/io.py @@ -43,6 +43,37 @@ def iter_expressions(self): def lower(dr): raise NotImplementedError("Attempted to use a Differential Output, but platform does not support them") +# Clk Input/Output --------------------------------------------------------------------------------- + +class ClkInput(Special): + def __init__(self, i, o): + Special.__init__(self) + self.i = wrap(i) + self.o = o if isinstance(o, str) else wrap(o) + + def iter_expressions(self): + yield self, "i", SPECIAL_INPUT + yield self, "o", SPECIAL_OUTPUT + + @staticmethod + def lower(dr): + raise NotImplementedError("Attempted to use a Clk Input, but platform does not support them") + + +class ClkOutput(Special): + def __init__(self, i, o): + Special.__init__(self) + self.i = i if isinstance(i, str) else wrap(i) + self.o = wrap(o) + + def iter_expressions(self): + yield self, "i", SPECIAL_INPUT + yield self, "o", SPECIAL_OUTPUT + + @staticmethod + def lower(dr): + raise NotImplementedError("Attempted to use a Clk Output, but platform does not support them") + # SDR Input/Output --------------------------------------------------------------------------------- class InferedSDRIO(Module): From bcc7e56dc678fac65472b5f760fa0f6f0ecaa15b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 12 Sep 2023 09:30:45 +0200 Subject: [PATCH 191/454] build/efinix/common: Add EfinixClkInput/Ouptut to use then in RGMII PHYs and avoid duplicating block code. --- litex/build/efinix/common.py | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 1b662515d..2a8a0bd79 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -62,6 +62,49 @@ class EfinixAsyncResetSynchronizer: def lower(dr): return EfinixAsyncResetSynchronizerImpl(dr.cd, dr.async_reset) +# Efinix Clk Input --------------------------------------------------------------------------------- + +class EfinixClkInputImpl(Module): + def __init__(self, platform, i, o): + o_clk = platform.add_iface_io(o) # FIXME. + block = { + "type" : "GPIO", + "size" : 1, + "location" : platform.get_pin_location(i)[0], + "properties" : platform.get_pin_properties(i), + "name" : platform.get_pin_name(o_clk), + "mode" : "INPUT_CLK", + } + platform.toolchain.ifacewriter.blocks.append(block) + platform.toolchain.excluded_ios.append(i) + + +class EfinixClkInput(Module): + @staticmethod + def lower(dr): + return EfinixClkInputImpl(dr.platform, dr.i, dr.o) + +# Efinix Clk Output --------------------------------------------------------------------------------- + +class EfinixClkOutputImpl(Module): + def __init__(self, platform, i, o): + block = { + "type" : "GPIO", + "size" : 1, + "location" : platform.get_pin_location(o)[0], + "properties" : platform.get_pin_properties(o), + "name" : i, # FIXME. + "mode" : "OUTPUT_CLK", + } + platform.toolchain.ifacewriter.blocks.append(block) + platform.toolchain.excluded_ios.append(o) + + +class EfinixClkOutput(Module): + @staticmethod + def lower(dr): + return EfinixClkOutputImpl(dr.platform, dr.i, dr.o) + # Efinix Tristate ---------------------------------------------------------------------------------- class EfinixTristateImpl(Module): @@ -179,6 +222,8 @@ def lower(dr): efinix_special_overrides = { AsyncResetSynchronizer : EfinixAsyncResetSynchronizer, + ClkInput : EfinixClkInput, + ClkOutput : EfinixClkOutput, Tristate : EfinixTristate, SDRTristate : EfinixSDRTristate, DDROutput : EfinixDDROutput, From d165418719aa4848bb098dd5540ad5233716e89b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 12 Sep 2023 09:35:53 +0200 Subject: [PATCH 192/454] CHANGES.md: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 7696d32b6..a3b7ae1b5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -65,6 +65,7 @@ - liteeth/phy : Added Artix7 2500BASE-X PHY. - liteeth/phy : Added Gowin Arora V RGMII PHY (GW5RGMII). - liteeth/phy : Added Titanium RGMII PHY (Tested with Ti60 F225 + RGMII adapter board). + - build/io : Added ClkInput/Ouput IO abstraction to simplify some Efinix designs. [> Changed ---------- From 5d9dd1059d31379d315704bc7b2e3dbdb482983a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 12 Sep 2023 10:41:47 +0200 Subject: [PATCH 193/454] core/usb_ohci fix generation --- litex/soc/cores/usb_ohci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/usb_ohci.py b/litex/soc/cores/usb_ohci.py index 894217323..2ca50daac 100644 --- a/litex/soc/cores/usb_ohci.py +++ b/litex/soc/cores/usb_ohci.py @@ -131,7 +131,7 @@ def generate_netlist(self): gen_args.append(f"--netlist-name={self.get_netlist_name()}") gen_args.append(f"--netlist-directory={vdir}") - cmd = 'cd {path} && sbt "runMain spinal.lib.com.usb.ohci.UsbOhciWishbone {args}"'.format( + cmd = 'cd {path} && sbt "lib/runMain spinal.lib.com.usb.ohci.UsbOhciWishbone {args}"'.format( path=os.path.join(vdir, "ext", "SpinalHDL"), args=" ".join(gen_args)) print("!!! " + cmd) if os.system(cmd) != 0: From c16add73b41738e8e14569cab919d4fe9bd31886 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 12 Sep 2023 10:42:44 +0200 Subject: [PATCH 194/454] core/vexriscv_smp add --expose-time, which add "clint_time" as output of the cpu. --- litex/soc/cores/cpu/vexriscv_smp/core.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index 3edc54540..dc8d85167 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -46,6 +46,7 @@ class VexRiscvSMP(CPU): dcache_width = 32 icache_width = 32 aes_instruction = False + expose_time = False out_of_order_decoder = True privileged_debug = False wishbone_memory = False @@ -79,6 +80,7 @@ def args_fill(parser): cpu_group.add_argument("--with-rvc", action="store_true", help="Enable RISC-V compressed instruction support") cpu_group.add_argument("--dtlb-size", default=4, help="Data TLB size.") cpu_group.add_argument("--itlb-size", default=4, help="Instruction TLB size.") + cpu_group.add_argument("--expose-time", action="store_true", help="Add CLINT time output.") @staticmethod def args_read(args): @@ -100,6 +102,7 @@ def args_read(args): if(args.dcache_ways): VexRiscvSMP.dcache_ways = int(args.dcache_ways) if(args.icache_ways): VexRiscvSMP.icache_ways = int(args.icache_ways) if(args.aes_instruction): VexRiscvSMP.aes_instruction = bool(args.aes_instruction) + if(args.expose_time): VexRiscvSMP.expose_time = bool(args.expose_time) if(args.without_out_of_order_decoder): VexRiscvSMP.out_of_order_decoder = False if(args.with_privileged_debug): VexRiscvSMP.privileged_debug = True if(args.with_wishbone_memory): VexRiscvSMP.wishbone_memory = True @@ -178,6 +181,7 @@ def generate_cluster_name(): f"{'_'+ldw if not VexRiscvSMP.wishbone_memory else ''}" \ f"{'_Cdma' if VexRiscvSMP.coherent_dma else ''}" \ f"{'_Aes' if VexRiscvSMP.aes_instruction else ''}" \ + f"{'_Time' if VexRiscvSMP.expose_time else ''}" \ f"{'_Ood' if VexRiscvSMP.out_of_order_decoder else ''}" \ f"{'_Wm' if VexRiscvSMP.wishbone_memory else ''}" \ f"{'_Wf32' if VexRiscvSMP.wishbone_force_32b else ''}" \ @@ -267,6 +271,7 @@ def generate_netlist(): gen_args.append(f"--icache-ways={VexRiscvSMP.icache_ways}") gen_args.append(f"--litedram-width={VexRiscvSMP.litedram_width}") gen_args.append(f"--aes-instruction={VexRiscvSMP.aes_instruction}") + gen_args.append(f"--expose-time={VexRiscvSMP.expose_time}") gen_args.append(f"--out-of-order-decoder={VexRiscvSMP.out_of_order_decoder}") gen_args.append(f"--privileged-debug={VexRiscvSMP.privileged_debug}") gen_args.append(f"--wishbone-memory={VexRiscvSMP.wishbone_memory}") @@ -366,6 +371,13 @@ def __init__(self, platform, variant): ) ] + # expose CLINT time + if VexRiscvSMP.expose_time: + self.clint_time = Signal(64) + self.cpu_params.update( + o_clint_time = self.clint_time + ) + def set_reset_address(self, reset_address): self.reset_address = reset_address assert reset_address == 0x0000_0000 From 5e0b8969eecb2f667735c526954b11b79507bcb4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 16:16:27 +0200 Subject: [PATCH 195/454] Provide a deployable naxriscv SMP --- litex/soc/cores/cpu/naxriscv/core.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 67fe62866..e71b565a8 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -153,12 +153,18 @@ def __init__(self, platform, variant): # # # + self.tracer_valid = Signal() + self.tracer_payload = Signal(8) + # CPU Instance. self.cpu_params = dict( # Clk/Rst. i_clk = ClockSignal("sys"), i_reset = ResetSignal("sys") | self.reset, + o_patcher_tracer_valid=self.tracer_valid, + o_patcher_tracer_payload=self.tracer_payload, + # Interrupt. i_peripheral_externalInterrupts_port = self.interrupt, @@ -289,9 +295,9 @@ def generate_netlist(reset_address): ndir = os.path.join(vdir, "ext", "NaxRiscv") sdir = os.path.join(vdir, "ext", "SpinalHDL") - # if NaxRiscv.update_repo != "no": - # NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "57e3bf59" if NaxRiscv.update_repo=="recommended" else None) - # NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev" , "8511f126" if NaxRiscv.update_repo=="recommended" else None) + if NaxRiscv.update_repo != "no": + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "coherency", "abe0c3bc" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From d40d76fe4e835daa971244f55b85781b82ff7756 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 16:18:44 +0200 Subject: [PATCH 196/454] fix indent --- litex/soc/cores/cpu/naxriscv/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index e71b565a8..bcd5afc87 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -295,9 +295,9 @@ def generate_netlist(reset_address): ndir = os.path.join(vdir, "ext", "NaxRiscv") sdir = os.path.join(vdir, "ext", "SpinalHDL") - if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "coherency", "abe0c3bc" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) + if NaxRiscv.update_repo != "no": + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "abe0c3bc" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From 50b9f44d26f0049b0a12d27deafdf6bc504bad3a Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 16:23:39 +0200 Subject: [PATCH 197/454] make naxriscv dma optional again --- litex/soc/cores/cpu/naxriscv/core.py | 94 ++++++++++++++-------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index bcd5afc87..a974e30f2 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -149,8 +149,6 @@ def __init__(self, platform, variant): self.periph_buses = [pbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). - self.dma_bus = dma_bus = axi.AXIInterface(data_width=64, address_width=32, id_width=4) - # # # self.tracer_valid = Signal() @@ -187,52 +185,56 @@ def __init__(self, platform, variant): i_pBus_rvalid = pbus.r.valid, o_pBus_rready = pbus.r.ready, i_pBus_rdata = pbus.r.data, - i_pBus_rresp = pbus.r.resp, - - # DMA - o_dma_bus_awready=dma_bus.aw.ready, - i_dma_bus_awvalid=dma_bus.aw.valid, - i_dma_bus_awid=dma_bus.aw.id, - i_dma_bus_awaddr=dma_bus.aw.addr, - i_dma_bus_awlen=dma_bus.aw.len, - i_dma_bus_awsize=dma_bus.aw.size, - i_dma_bus_awburst=dma_bus.aw.burst, - i_dma_bus_awlock=dma_bus.aw.lock, - i_dma_bus_awcache=dma_bus.aw.cache, - i_dma_bus_awprot=dma_bus.aw.prot, - i_dma_bus_awqos=dma_bus.aw.qos, - - o_dma_bus_wready=dma_bus.w.ready, - i_dma_bus_wvalid=dma_bus.w.valid, - i_dma_bus_wdata=dma_bus.w.data, - i_dma_bus_wstrb=dma_bus.w.strb, - i_dma_bus_wlast=dma_bus.w.last, - - i_dma_bus_bready=dma_bus.b.ready, - o_dma_bus_bvalid=dma_bus.b.valid, - o_dma_bus_bid=dma_bus.b.id, - o_dma_bus_bresp=dma_bus.b.resp, - - o_dma_bus_arready=dma_bus.ar.ready, - i_dma_bus_arvalid=dma_bus.ar.valid, - i_dma_bus_arid=dma_bus.ar.id, - i_dma_bus_araddr=dma_bus.ar.addr, - i_dma_bus_arlen=dma_bus.ar.len, - i_dma_bus_arsize=dma_bus.ar.size, - i_dma_bus_arburst=dma_bus.ar.burst, - i_dma_bus_arlock=dma_bus.ar.lock, - i_dma_bus_arcache=dma_bus.ar.cache, - i_dma_bus_arprot=dma_bus.ar.prot, - i_dma_bus_arqos=dma_bus.ar.qos, - - i_dma_bus_rready=dma_bus.r.ready, - o_dma_bus_rvalid=dma_bus.r.valid, - o_dma_bus_rid=dma_bus.r.id, - o_dma_bus_rdata=dma_bus.r.data, - o_dma_bus_rresp=dma_bus.r.resp, - o_dma_bus_rlast=dma_bus.r.last, + i_pBus_rresp = pbus.r.resp ) + if NaxRiscv.with_dma: + self.dma_bus = dma_bus = axi.AXIInterface(data_width=64, address_width=32, id_width=4) + + self.cpu_params.update( + o_dma_bus_awready=dma_bus.aw.ready, + i_dma_bus_awvalid=dma_bus.aw.valid, + i_dma_bus_awid=dma_bus.aw.id, + i_dma_bus_awaddr=dma_bus.aw.addr, + i_dma_bus_awlen=dma_bus.aw.len, + i_dma_bus_awsize=dma_bus.aw.size, + i_dma_bus_awburst=dma_bus.aw.burst, + i_dma_bus_awlock=dma_bus.aw.lock, + i_dma_bus_awcache=dma_bus.aw.cache, + i_dma_bus_awprot=dma_bus.aw.prot, + i_dma_bus_awqos=dma_bus.aw.qos, + + o_dma_bus_wready=dma_bus.w.ready, + i_dma_bus_wvalid=dma_bus.w.valid, + i_dma_bus_wdata=dma_bus.w.data, + i_dma_bus_wstrb=dma_bus.w.strb, + i_dma_bus_wlast=dma_bus.w.last, + + i_dma_bus_bready=dma_bus.b.ready, + o_dma_bus_bvalid=dma_bus.b.valid, + o_dma_bus_bid=dma_bus.b.id, + o_dma_bus_bresp=dma_bus.b.resp, + + o_dma_bus_arready=dma_bus.ar.ready, + i_dma_bus_arvalid=dma_bus.ar.valid, + i_dma_bus_arid=dma_bus.ar.id, + i_dma_bus_araddr=dma_bus.ar.addr, + i_dma_bus_arlen=dma_bus.ar.len, + i_dma_bus_arsize=dma_bus.ar.size, + i_dma_bus_arburst=dma_bus.ar.burst, + i_dma_bus_arlock=dma_bus.ar.lock, + i_dma_bus_arcache=dma_bus.ar.cache, + i_dma_bus_arprot=dma_bus.ar.prot, + i_dma_bus_arqos=dma_bus.ar.qos, + + i_dma_bus_rready=dma_bus.r.ready, + o_dma_bus_rvalid=dma_bus.r.valid, + o_dma_bus_rid=dma_bus.r.id, + o_dma_bus_rdata=dma_bus.r.data, + o_dma_bus_rresp=dma_bus.r.resp, + o_dma_bus_rlast=dma_bus.r.last + ) + def set_reset_address(self, reset_address): self.reset_address = reset_address From b1605070422f0f06a3ae48c558bd3db645754744 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 18:52:40 +0200 Subject: [PATCH 198/454] core/naxriscv add rvls git --- litex/soc/cores/cpu/naxriscv/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index a974e30f2..b53024415 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -296,10 +296,12 @@ def generate_netlist(reset_address): vdir = get_data_mod("cpu", "naxriscv").data_location ndir = os.path.join(vdir, "ext", "NaxRiscv") sdir = os.path.join(vdir, "ext", "SpinalHDL") + rdir = os.path.join(vdir, "ext", "NaxRiscv/ext/rvls") if NaxRiscv.update_repo != "no": NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "abe0c3bc" if NaxRiscv.update_repo=="recommended" else None) NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("Rvls", rdir, "https://github.com/SpinalHDL/rvls.git", "main", "d7e8d845" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From 2e4ebc8ec322305e660d02097e3697627294def4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 19:42:16 +0200 Subject: [PATCH 199/454] core/naxriscv git fix attempt --- litex/soc/cores/cpu/naxriscv/core.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index b53024415..7bc304092 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -288,7 +288,7 @@ def git_setup(name, dir, repo, branch, hash): os.chdir(os.path.join(dir)) wipe_cmd = "&& git clean --force -d -x && git reset --hard" if "wipe" in NaxRiscv.update_repo else "" checkout_cmd = f"&& git checkout {hash}" if hash is not None else "" - subprocess.check_call(f"cd {dir} {wipe_cmd} && git checkout {branch} && git pull {checkout_cmd}", shell=True) + subprocess.check_call(f"cd {dir} {wipe_cmd} && git checkout {branch} && git submodule init && git pull --recurse-submodules {checkout_cmd}", shell=True) # Netlist Generation. @staticmethod @@ -296,12 +296,10 @@ def generate_netlist(reset_address): vdir = get_data_mod("cpu", "naxriscv").data_location ndir = os.path.join(vdir, "ext", "NaxRiscv") sdir = os.path.join(vdir, "ext", "SpinalHDL") - rdir = os.path.join(vdir, "ext", "NaxRiscv/ext/rvls") if NaxRiscv.update_repo != "no": NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "abe0c3bc" if NaxRiscv.update_repo=="recommended" else None) NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("Rvls", rdir, "https://github.com/SpinalHDL/rvls.git", "main", "d7e8d845" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From e8ed93c57139319ba8cc5b25025aef11da3e9fa5 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 20:41:27 +0200 Subject: [PATCH 200/454] core/naxriscv git fix attempt --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 7bc304092..2752fb4d7 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -298,7 +298,7 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "abe0c3bc" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "01bc27a2" if NaxRiscv.update_repo=="recommended" else None) NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] From e2c3a50e99fbca066442edf095439018a62a75d4 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 13 Sep 2023 23:10:10 +0200 Subject: [PATCH 201/454] core/naxriscv allow memory less gen --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 2752fb4d7..8746d88ea 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -298,7 +298,7 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "01bc27a2" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "ee4c6fb7" if NaxRiscv.update_repo=="recommended" else None) NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] From 51592df2608b5fabeb0d85d81f52b473ee1a9599 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 14 Sep 2023 07:19:05 +0200 Subject: [PATCH 202/454] debug --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 8746d88ea..3dd5aa03a 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -299,7 +299,7 @@ def generate_netlist(reset_address): if NaxRiscv.update_repo != "no": NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "ee4c6fb7" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "d1f0b637" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "ee95492a" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From a2c2c211c56c5d7a6a57e5248e3216c37446bdd3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 14 Sep 2023 10:47:37 +0200 Subject: [PATCH 203/454] Changes.md: Release 2023.08. --- CHANGES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a3b7ae1b5..46070c433 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,5 @@ -[> Changes since 2023.04 ------------------------- +[> 2023.08, released on September 14th 2023 +------------------------------------------- [> Fixed -------- From ff3318b20d590d7e04778f9fb527f1e0eb121203 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 14 Sep 2023 11:25:02 +0200 Subject: [PATCH 204/454] Update litex_setup.py with naxriscv smp --- litex_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex_setup.py b/litex_setup.py index 2354a6846..01f1cfbb4 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -122,7 +122,7 @@ def __init__(self, url, clone="regular", develop=True, sha1=None, branch="master "pythondata-cpu-cva6": GitRepo(url="https://github.com/litex-hub/", clone="recursive"), "pythondata-cpu-ibex": GitRepo(url="https://github.com/litex-hub/", clone="recursive", sha1=0xd3d53df), "pythondata-cpu-minerva": GitRepo(url="https://github.com/litex-hub/"), - "pythondata-cpu-naxriscv": GitRepo(url="https://github.com/litex-hub/"), + "pythondata-cpu-naxriscv": GitRepo(url="https://github.com/litex-hub/", branch="smp"), "pythondata-cpu-picorv32": GitRepo(url="https://github.com/litex-hub/"), "pythondata-cpu-rocket": GitRepo(url="https://github.com/litex-hub/"), "pythondata-cpu-serv": GitRepo(url="https://github.com/litex-hub/"), From 6da148233696a4168cb8f120dc5d950a85d09129 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Thu, 14 Sep 2023 17:49:44 +0200 Subject: [PATCH 205/454] gen/fhdl/verilog: Fix #1777. --- litex/gen/fhdl/verilog.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index 244d72bd2..bc03183ed 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -377,11 +377,15 @@ def _print_attribute(attr, attr_translate): # MODULE # # ------------------------------------------------------------------------------------------------ # +def _use_wire(stmts): + return (len(stmts) == 1 and isinstance(stmts[0], _Assign) and + not isinstance(stmts[0].l, _Slice)) + def _list_comb_wires(f): r = set() groups = group_by_targets(f.comb) for g in groups: - if len(g[1]) == 1 and isinstance(g[1][0], _Assign): + if _use_wire(g[1]): r |= g[0] return r @@ -460,7 +464,7 @@ def _print_combinatorial_logic_sim(f, ns): for n, (t, stmts) in enumerate(target_stmt_map.items()): assert isinstance(t, Signal) - if len(stmts) == 1 and isinstance(stmts[0], _Assign): + if _use_wire(stmts): r += "assign " + _print_node(ns, _AT_BLOCKING, 0, stmts[0]) else: r += "always @(*) begin\n" @@ -476,7 +480,7 @@ def _print_combinatorial_logic_synth(f, ns): groups = group_by_targets(f.comb) for n, g in enumerate(groups): - if len(g[1]) == 1 and isinstance(g[1][0], _Assign): + if _use_wire(g[1]): r += "assign " + _print_node(ns, _AT_BLOCKING, 0, g[1][0]) else: r += "always @(*) begin\n" From eb54ec74028f5364ce1893144017634b776b1cfb Mon Sep 17 00:00:00 2001 From: Giulio Girardi Date: Sat, 16 Sep 2023 10:41:18 +0000 Subject: [PATCH 206/454] Add Debug support for NEORV32 --- litex/soc/cores/cpu/neorv32/core.py | 63 +++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/litex/soc/cores/cpu/neorv32/core.py b/litex/soc/cores/cpu/neorv32/core.py index 14ab85694..9cc16e158 100644 --- a/litex/soc/cores/cpu/neorv32/core.py +++ b/litex/soc/cores/cpu/neorv32/core.py @@ -17,7 +17,16 @@ # Variants ----------------------------------------------------------------------------------------- -CPU_VARIANTS = ["minimal", "lite", "standard", "full"] +CPU_VARIANTS = [ + "minimal", + "minimal+debug", + "lite", + "lite+debug", + "standard", + "standard+debug", + "full", + "full+debug", +] # GCC Flags ---------------------------------------------------------------------------------------- @@ -30,9 +39,13 @@ # | ||||/-- Double-Precision Floating-Point # i macfd "minimal": "-march=rv32i2p0 -mabi=ilp32", + "minimal+debug": "-march=rv32i2p0 -mabi=ilp32", "lite": "-march=rv32i2p0_mc -mabi=ilp32", + "lite+debug": "-march=rv32i2p0_mc -mabi=ilp32", "standard": "-march=rv32i2p0_mc -mabi=ilp32", + "standard+debug": "-march=rv32i2p0_mc -mabi=ilp32", "full": "-march=rv32i2p0_mc -mabi=ilp32", + "full+debug": "-march=rv32i2p0_mc -mabi=ilp32", } # NEORV32 ------------------------------------------------------------------------------------------ @@ -67,8 +80,8 @@ def __init__(self, platform, variant="standard"): # # # - # CPU LiteX Core Complex Wrapper - self.specials += Instance("neorv32_litex_core_complex", + # CPU Instance. + self.cpu_params = dict( # Clk/Rst. i_clk_i = ClockSignal("sys"), i_rstn_i = ~(ResetSignal() | self.reset), @@ -95,30 +108,51 @@ def __init__(self, platform, variant="standard"): i_wb_err_i = idbus.err, ) - self.vhd2v_converter = VHD2VConverter(platform, + if "debug" in variant: + self.add_debug() + + self.vhd2v_converter = VHD2VConverter(self.platform, top_entity = "neorv32_litex_core_complex", build_dir = os.path.abspath(os.path.dirname(__file__)), work_package = "neorv32", force_convert = True, params = dict( p_CONFIG = { - "minimal" : 0, - "lite" : 1, - "standard" : 2, - "full" : 3 - }[variant], - p_DEBUG = False, + "minimal" : 0, + "minimal+debug" : 0, + "lite" : 1, + "lite+debug" : 1, + "standard" : 2, + "standard+debug" : 2, + "full" : 3, + "full+debug" : 3 + }[self.variant], + p_DEBUG = "debug" in self.variant, ) ) - # Add Verilog sources - self.add_sources(variant) + self.add_sources() def set_reset_address(self, reset_address): self.reset_address = reset_address assert reset_address == 0x0000_0000 - def add_sources(self, variant): + def add_debug(self): + self.i_jtag_trst = Signal() + self.i_jtag_tck = Signal() + self.i_jtag_tdi = Signal() + self.o_jtag_tdo = Signal() + self.i_jtag_tms = Signal() + + self.cpu_params.update( + i_jtag_trst_i = self.i_jtag_trst, + i_jtag_tck_i = self.i_jtag_tck, + i_jtag_tdi_i = self.i_jtag_tdi, + o_jtag_tdo_o = self.o_jtag_tdo, + i_jtag_tms_i = self.i_jtag_tms, + ) + + def add_sources(self): cdir = os.path.abspath(os.path.dirname(__file__)) # List VHDL sources. sources = { @@ -172,3 +206,6 @@ def add_sources(self, variant): def do_finalize(self): assert hasattr(self, "reset_address") + + # CPU LiteX Core Complex Wrapper + self.specials += Instance("neorv32_litex_core_complex", **self.cpu_params) From de608ee1141ae93640880ea2d2ea122329cce9f8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 17 Sep 2023 21:59:55 +0200 Subject: [PATCH 207/454] ci: Switch install to --dev. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cbfa106f6..e27b6a23d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: # Install (n)Migen / LiteX / Cores - name: Install LiteX run: | - python3 litex_setup.py --config=full --init --install --user + python3 litex_setup.py --config=full --init --install --user --dev # Install GCC Toolchains - name: Install GCC Toolchains From 6162a6dc9081889c4467690846649c38c19be8ec Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Sun, 17 Sep 2023 17:42:53 -0400 Subject: [PATCH 208/454] update version number to 2023.08 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a4b0df2a0..08af7085f 100755 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name="litex", - version="2023.04", + version="2023.08", description="Python SoC/Core builder for building FPGA based systems.", long_description=long_description, long_description_content_type="text/markdown", From b931499c122f69044b0794e3c14f4d363748ba48 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 18 Sep 2023 08:46:48 +0200 Subject: [PATCH 209/454] build: Remove osfpga skeleton (would need feedbacks & updates). --- litex/build/osfpga/__init__.py | 1 - litex/build/osfpga/common.py | 27 --------- litex/build/osfpga/osfpga.py | 99 ------------------------------- litex/build/osfpga/platform.py | 39 ------------ litex/build/osfpga/test_blinky.py | 41 ------------- litex/build/osfpga/test_soc.py | 65 -------------------- 6 files changed, 272 deletions(-) delete mode 100644 litex/build/osfpga/__init__.py delete mode 100644 litex/build/osfpga/common.py delete mode 100644 litex/build/osfpga/osfpga.py delete mode 100644 litex/build/osfpga/platform.py delete mode 100755 litex/build/osfpga/test_blinky.py delete mode 100755 litex/build/osfpga/test_soc.py diff --git a/litex/build/osfpga/__init__.py b/litex/build/osfpga/__init__.py deleted file mode 100644 index 9b874d960..000000000 --- a/litex/build/osfpga/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from litex.build.osfpga.platform import OSFPGAPlatform diff --git a/litex/build/osfpga/common.py b/litex/build/osfpga/common.py deleted file mode 100644 index f5aa89254..000000000 --- a/litex/build/osfpga/common.py +++ /dev/null @@ -1,27 +0,0 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2022 Florent Kermarrec -# SPDX-License-Identifier: BSD-2-Clause - -from migen.fhdl.module import Module -from migen.genlib.resetsync import AsyncResetSynchronizer - -from litex.build.io import * - -# OS-FPGA AsyncResetSynchronizer ------------------------------------------------------------------- - -class OSFPGAAsyncResetSynchronizerImpl(Module): - def __init__(self, cd, async_reset): - self.comb += cd.rst.eq(async_reset) # FIXME: Implement. - -class OSFPGAAsyncResetSynchronizer: - @staticmethod - def lower(dr): - return OSFPGAAsyncResetSynchronizerImpl(dr.cd, dr.async_reset) - -# OS-FPGA Special Overrides ------------------------------------------------------------------------- - -osfpga_special_overrides = { - AsyncResetSynchronizer: OSFPGAAsyncResetSynchronizer, -} diff --git a/litex/build/osfpga/osfpga.py b/litex/build/osfpga/osfpga.py deleted file mode 100644 index 382e864fc..000000000 --- a/litex/build/osfpga/osfpga.py +++ /dev/null @@ -1,99 +0,0 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2022 Florent Kermarrec -# SPDX-License-Identifier: BSD-2-Clause - -import os -import sys -import math -import subprocess -from shutil import which, copyfile - -from migen.fhdl.structure import _Fragment - -from litex.build.generic_toolchain import GenericToolchain -from litex.build.generic_platform import * -from litex.build import tools - -# OSFPGAToolchain ---------------------------------------------------------------------------------- - -class OSFPGAToolchain(GenericToolchain): - attr_translate = {} - - def __init__(self, toolchain): - super().__init__() - self.toolchain = toolchain - self.clocks = dict() - - # Constraints ---------------------------------------------------------------------------------- - - def build_io_constraints(self): - return ("", "") # TODO - - # Timing Constraints (.sdc) -------------------------------------------------------------------- - - def build_timing_constraints(self, vns): - sdc = [] - for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): - clk_sig = self._vns.get_name(clk) - if name is None: - name = clk_sig - sdc.append(f"create_clock -name {name} -period {str(period)} [get_ports {{{clk_sig}}}]") - with open(f"{self._build_name}.sdc", "w") as f: - f.write("\n".join(sdc)) - return (self._build_name + ".sdc", "SDC") - - # Project -------------------------------------------------------------------------------------- - - def build_project(self): - tcl = [] - - # Create Design. - tcl.append(f"create_design {self._build_name}") - - # Set Device. - tcl.append(f"target_device {self.platform.device.upper()}") - - # Add Include Path. - tcl.append("add_include_path ./") - for include_path in self.platform.verilog_include_paths: - tcl.append(f"add_include_path {include_path}") - - # Add Sources. - for f, typ, lib in self.platform.sources: - tcl.append(f"add_design_file {f}") - - # Set Top Module. - tcl.append(f"set_top_module {self._build_name}") - - # Add Timings Constraints. - tcl.append(f"add_constraint_file {self._build_name}.sdc") - - # Run. - tcl.append("synth") - tcl.append("packing") - tcl.append("place") - tcl.append("route") - tcl.append("sta") - tcl.append("power") - tcl.append("bitstream") - - # Generate .tcl. - with open("build.tcl", "w") as f: - f.write("\n".join(tcl)) - - # Script --------------------------------------------------------------------------------------- - - def build_script(self): - return "" # unused - - def run_script(self, script): - toolchain_sh = self.toolchain - if which(toolchain_sh) is None: - msg = f"Unable to find {toolchain_sh.upper()} toolchain, please:\n" - msg += f"- Add {toolchain_sh.upper()} toolchain to your $PATH." - raise OSError(msg) - - if subprocess.call([toolchain_sh, "--batch", "--script", "build.tcl"]) != 0: - raise OSError(f"Error occured during {toolchain_sh.upper()}'s script execution.") diff --git a/litex/build/osfpga/platform.py b/litex/build/osfpga/platform.py deleted file mode 100644 index d3665ae15..000000000 --- a/litex/build/osfpga/platform.py +++ /dev/null @@ -1,39 +0,0 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2022 Florent Kermarrec -# SPDX-License-Identifier: BSD-2-Clause - -import os - -from litex.build.generic_platform import GenericPlatform -from litex.build.osfpga import common, osfpga - -# OSFPGAPlatform ----------------------------------------------------------------------------------- - -class OSFPGAPlatform(GenericPlatform): - _bitstream_ext = ".bin" - - _supported_toolchains = ["osfpga"] - - def __init__(self, device, *args, toolchain="foedag", devicename=None, **kwargs): - GenericPlatform.__init__(self, device, *args, **kwargs) - self.devicename = devicename - if toolchain in ["foedag", "raptor"]: - self.toolchain = osfpga.OSFPGAToolchain(toolchain=toolchain) - else: - raise ValueError(f"Unknown toolchain {toolchain}") - - def get_verilog(self, *args, special_overrides=dict(), **kwargs): - so = dict(common.osfpga_special_overrides) - so.update(special_overrides) - return GenericPlatform.get_verilog(self, *args, - special_overrides = so, - attr_translate = self.toolchain.attr_translate, - **kwargs) - - def build(self, *args, **kwargs): - return self.toolchain.build(self, *args, **kwargs) - - def add_false_path_constraint(self, from_, to): - pass # FIXME: Implement. diff --git a/litex/build/osfpga/test_blinky.py b/litex/build/osfpga/test_blinky.py deleted file mode 100755 index 7dd79f3ba..000000000 --- a/litex/build/osfpga/test_blinky.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 - -# -# This file is part of LiteX. -# -# Copyright (c) 2022 Florent Kermarrec -# SPDX-License-Identifier: BSD-2-Clause - -import os - -from migen import * - -from litex.build.generic_platform import Pins -from litex.build.osfpga import OSFPGAPlatform - -# Minimal Platform --------------------------------------------------------------------------------- - -_io = [ - ("clk", 0, Pins(1)), - ("led", 0, Pins(1)) -] - -class Platform(OSFPGAPlatform): - def __init__(self): - OSFPGAPlatform.__init__(self, device="gemini", toolchain="raptor", io=_io) - -# Minimal Design ----------------------------------------------------------------------------------- - -platform = Platform() -clk = platform.request("clk") -led = platform.request("led") -module = Module() -module.clock_domains.cd_sys = ClockDomain("sys") -module.comb += module.cd_sys.clk.eq(clk) -counter = Signal(26) -module.comb += led.eq(counter[25]) -module.sync += counter.eq(counter + 1) - -# Build -------------------------------------------------------------------------------------------- - -platform.build(module, build_name="blinky", run=True) diff --git a/litex/build/osfpga/test_soc.py b/litex/build/osfpga/test_soc.py deleted file mode 100755 index 54b0ca8e3..000000000 --- a/litex/build/osfpga/test_soc.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 - -# -# This file is part of LiteX. -# -# Copyright (c) 2022 Florent Kermarrec -# SPDX-License-Identifier: BSD-2-Clause - -from migen import * - -from litex.build.io import CRG -from litex.build.generic_platform import Pins, Subsignal -from litex.build.osfpga import OSFPGAPlatform - -from litex.soc.integration.soc_core import * -from litex.soc.integration.builder import * - -# Platform --------------------------------------------------------------------------------- - -_io = [ - # Clk. - ("clk", 0, Pins(1)), - - # Serial. - ("serial", 0, - Subsignal("tx", Pins(1)), - Subsignal("rx", Pins(1)), - ), -] - -class Platform(OSFPGAPlatform): - def __init__(self, toolchain="raptor", device="gemini"): - OSFPGAPlatform.__init__(self, device=device, toolchain=toolchain, io=_io) - -# BaseSoC ------------------------------------------------------------------------------------------ - -class BaseSoC(SoCCore): - def __init__(self, platform, sys_clk_freq=int(10e6), **kwargs): - # CRG -------------------------------------------------------------------------------------- - self.submodules.crg = CRG(platform.request("clk")) - - # SoCCore ---------------------------------------------------------------------------------- - SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX Test SoC on OS-FPGA", **kwargs) - -# Build -------------------------------------------------------------------------------------------- - -def main(): - from litex.soc.integration.soc import LiteXSoCArgumentParser - parser = LiteXSoCArgumentParser(description="LiteX Test SoC on OS-FPGA") - target_group = parser.add_argument_group(title="Target options") - target_group.add_argument("--build", action="store_true", help="Build design.") - target_group.add_argument("--toolchain", default="raptor", help="FPGA toolchain.") - target_group.add_argument("--device", default="gemini", help="FPGA device.") - builder_args(parser) - soc_core_args(parser) - args = parser.parse_args() - - platform = Platform(toolchain=args.toolchain, device=args.device) - soc = BaseSoC(platform,**soc_core_argdict(args)) - builder = Builder(soc, **builder_argdict(args)) - if args.build: - builder.build() - -if __name__ == "__main__": - main() From 46d9d8c780d18a4d6c76c35eca4c6e1a6c73920e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 18 Sep 2023 08:55:24 +0200 Subject: [PATCH 210/454] README: Update sponsors. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a12bd41c..721021380 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ To discover more products/projects built with LiteX, visit the [projects page](h A huge shoutout to our awesome industrial clients who have given us the green light to incorporate some of the developments we initially created for them directly into LiteX! These innovative developments often provide the building blocks for the features that the wider community can then use and improve upon. Your support has been instrumental for the project, and we are incredibly grateful for your partnership. Thanks! -![](https://user-images.githubusercontent.com/1450143/221536924-5b6511f9-084a-4c94-9bb3-4653094d2723.png) +![](https://github.com/enjoy-digital/litex/assets/1450143/444d8fc2-3092-487c-b52f-bdd776b790a4.png) # Papers, Presentations, Tutorials, Links **FPGA lessons/tutorials:** From 8bd548d453e36ec4ce213bc4754a6e5c87dce5b5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 18 Sep 2023 08:56:36 +0200 Subject: [PATCH 211/454] CHANGES.md: Start listing changes since 2023.08. --- CHANGES.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 46070c433..dca666323 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,16 @@ +[> Changes since 2023.08 +------------------------ + [> Fixed + -------- + + [> Added + -------- + + [> Changed + ---------- + build/osfpga: Removed initial support (would need feedbacks/updates). + + [> 2023.08, released on September 14th 2023 ------------------------------------------- From 04a33c5ddb7878627ff592683be53a087aa872bc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 18 Sep 2023 09:09:45 +0200 Subject: [PATCH 212/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index dca666323..a96db8e02 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ [> Added -------- + cpu/naxriscv: Added SMP support. [> Changed ---------- From e0be02875375cdd3db347bdce0c56ef2241e917e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 18 Sep 2023 09:20:48 +0200 Subject: [PATCH 213/454] litex_setup: Don't do repo init in dev_mode (SSH clone) if running on CI. --- litex_setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex_setup.py b/litex_setup.py index 577675dfd..5ec3caa41 100755 --- a/litex_setup.py +++ b/litex_setup.py @@ -449,7 +449,9 @@ def main(): # Init. if args.init: - litex_setup_init_repos(config=args.config, tag=args.tag, dev_mode=args.dev) + ci_run = (os.environ.get("GITHUB_ACTIONS") == "true") + dev_mode = args.dev and (not ci_run) + litex_setup_init_repos(config=args.config, tag=args.tag, dev_mode=dev_mode) # Update. if args.update: From 3d956af81dab9fcdf4fc18dae8ecc71a994a69ab Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 20 Sep 2023 09:10:20 +0200 Subject: [PATCH 214/454] core/vexriscv_smp add --hardware-breakpoints INT to allow hardware breakpoint on PC --- litex/soc/cores/cpu/vexriscv_smp/core.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index dc8d85167..10133d1c5 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -49,6 +49,7 @@ class VexRiscvSMP(CPU): expose_time = False out_of_order_decoder = True privileged_debug = False + hardware_breakpoints = 0 wishbone_memory = False wishbone_force_32b = False with_fpu = False @@ -74,6 +75,7 @@ def args_fill(parser): cpu_group.add_argument("--without-out-of-order-decoder", action="store_true", help="Reduce area at cost of peripheral access speed") cpu_group.add_argument("--with-wishbone-memory", action="store_true", help="Disable native LiteDRAM interface") cpu_group.add_argument("--with-privileged-debug", action="store_true", help="Enable official RISC-V debug spec") + cpu_group.add_argument("--hardware-breakpoints", default=1, help="Number of hardware breapoints", type=int) cpu_group.add_argument("--wishbone-force-32b", action="store_true", help="Force the wishbone bus to be 32 bits") cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU") cpu_group.add_argument("--cpu-per-fpu", default="4", help="Maximal ratio between CPU count and FPU count. Will instanciate as many FPU as necessary.") @@ -102,9 +104,10 @@ def args_read(args): if(args.dcache_ways): VexRiscvSMP.dcache_ways = int(args.dcache_ways) if(args.icache_ways): VexRiscvSMP.icache_ways = int(args.icache_ways) if(args.aes_instruction): VexRiscvSMP.aes_instruction = bool(args.aes_instruction) - if(args.expose_time): VexRiscvSMP.expose_time = bool(args.expose_time) + if(args.expose_time): VexRiscvSMP.expose_time = bool(args.expose_time) if(args.without_out_of_order_decoder): VexRiscvSMP.out_of_order_decoder = False if(args.with_privileged_debug): VexRiscvSMP.privileged_debug = True + if(args.hardware_breakpoints): VexRiscvSMP.hardware_breakpoints = args.hardware_breakpoints if(args.with_wishbone_memory): VexRiscvSMP.wishbone_memory = True if(args.wishbone_force_32b): VexRiscvSMP.wishbone_force_32b = True if(args.with_fpu): @@ -187,6 +190,7 @@ def generate_cluster_name(): f"{'_Wf32' if VexRiscvSMP.wishbone_force_32b else ''}" \ f"{'_Fpu' + str(VexRiscvSMP.cpu_per_fpu) if VexRiscvSMP.with_fpu else ''}" \ f"{'_Pd' if VexRiscvSMP.privileged_debug else ''}" \ + f"{'_Hb' + str(VexRiscvSMP.hardware_breakpoints) if VexRiscvSMP.hardware_breakpoints > 0 else ''}" \ f"{'_Rvc' if VexRiscvSMP.with_rvc else ''}" # Default Configs Generation. @@ -274,6 +278,7 @@ def generate_netlist(): gen_args.append(f"--expose-time={VexRiscvSMP.expose_time}") gen_args.append(f"--out-of-order-decoder={VexRiscvSMP.out_of_order_decoder}") gen_args.append(f"--privileged-debug={VexRiscvSMP.privileged_debug}") + gen_args.append(f"--hardware-breakpoints={VexRiscvSMP.hardware_breakpoints}") gen_args.append(f"--wishbone-memory={VexRiscvSMP.wishbone_memory}") if(VexRiscvSMP.wishbone_force_32b): gen_args.append(f"--wishbone-force-32b={VexRiscvSMP.wishbone_force_32b}") gen_args.append(f"--fpu={VexRiscvSMP.with_fpu}") From 564f96c6c7c0570eb2a7bf96990a33baaf0b6e53 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 25 Sep 2023 19:34:09 +1000 Subject: [PATCH 215/454] litex_json2renode: fix --bios-binary and add --opensbi-binary --bios-binary is reverted to loading the bios into _rom_ as per the documentation and litex defaults --opensbi-binary is added to load the openSBI binary into the opensbi memory region The examples documented in the wiki now work again --- litex/tools/litex_json2renode.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 21f2e2582..0f83b5e76 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -883,16 +883,23 @@ def generate_resc(csr, number_of_cores, args, flash_binaries={}, tftp_binaries={ """.format(cpu_type, args.repl) opensbi_base = csr['memories']['opensbi']['base'] if 'opensbi' in csr['memories'] else None - if opensbi_base is not None and args.bios_binary: - # load LiteX BIOS to ROM + if opensbi_base is not None and args.opensbi_binary: + # load OpenSBI to opensbi base result += """ sysbus LoadBinary @{} {} -""".format(args.bios_binary, hex(opensbi_base)) - - if opensbi_base: +""".format(args.opensbi_binary, hex(opensbi_base)) for cpu_id in range(0, number_of_cores): result += f"cpu{cpu_id} PC {hex(opensbi_base)}\n" + rom_base = csr['memories']['rom']['base'] if 'rom' in csr['memories'] else None + if rom_base is not None and args.bios_binary: + # load LiteX BIOS to ROM base + result += """ +sysbus LoadBinary @{} {} +""".format(args.bios_binary, hex(rom_base)) + for cpu_id in range(0, number_of_cores): + result += f"cpu{cpu_id} PC {hex(rom_base)}\n" + if args.tftp_ip: result += """ @@ -1047,8 +1054,12 @@ def parse_args(): help='Output platform definition file') parser.add_argument('--configure-network', action='store', help='Generate virtual network and connect it to host') - parser.add_argument('--bios-binary', action='store', + bios_group = parser.add_mutually_exclusive_group() + bios_group.add_argument('--bios-binary', action='store', help='Path to the BIOS binary') + bios_group.add_argument('--opensbi-binary', action='store', + help='Path to the OpenSBI binary') + parser.add_argument('--firmware-binary', action='store', help='Path to the binary to load into boot flash') parser.add_argument('--flash-binary', action='append', dest='flash_binaries_args', From a0f4c3715da252bfbb177d33845864e0354719b5 Mon Sep 17 00:00:00 2001 From: Matteo Marzaro Date: Mon, 25 Sep 2023 12:07:15 +0200 Subject: [PATCH 216/454] Update NEORV32 to verion 1.8.9 --- litex/soc/cores/cpu/neorv32/core.py | 84 +++++++++++++++++++---------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/litex/soc/cores/cpu/neorv32/core.py b/litex/soc/cores/cpu/neorv32/core.py index 9cc16e158..3f9dc61ef 100644 --- a/litex/soc/cores/cpu/neorv32/core.py +++ b/litex/soc/cores/cpu/neorv32/core.py @@ -2,6 +2,7 @@ # This file is part of LiteX. # # Copyright (c) 2022 Florent Kermarrec +# 2023 Protech Engineering # SPDX-License-Identifier: BSD-2-Clause import os @@ -60,7 +61,7 @@ class NEORV32(CPU): gcc_triple = CPU_GCC_TRIPLE_RISCV32 linker_output_format = "elf32-littleriscv" nop = "nop" - io_regions = {0x8000_0000: 0x8000_0000} # Origin, Length. + io_regions = {0xF000_0000: 0x0FFF_BFFF} # Origin, Length. # GCC Flags. @property @@ -133,6 +134,16 @@ def __init__(self, platform, variant="standard"): self.add_sources() + # Memory Mapping. + @property + def mem_map(self): + return { + "rom" : 0x0000_0000, + "sram" : 0x0100_0000, + "main_ram" : 0x4000_0000, + "csr" : 0xF000_0000, + } + def set_reset_address(self, reset_address): self.reset_address = reset_address assert reset_address == 0x0000_0000 @@ -157,33 +168,51 @@ def add_sources(self): # List VHDL sources. sources = { "core" : [ - # CPU & Processors Packages/Cores. - "neorv32_package.vhd", - "neorv32_fifo.vhd", - - # CPU components. + "neorv32_application_image.vhd", + "neorv32_bootloader_image.vhd", + "neorv32_boot_rom.vhd", + "neorv32_cfs.vhd", + "neorv32_cpu_alu.vhd", + "neorv32_cpu_control.vhd", + "neorv32_cpu_cp_bitmanip.vhd", + "neorv32_cpu_cp_cfu.vhd", + "neorv32_cpu_cp_fpu.vhd", + "neorv32_cpu_cp_muldiv.vhd", + "neorv32_cpu_cp_shifter.vhd", + "neorv32_cpu_decompressor.vhd", + "neorv32_cpu_lsu.vhd", + "neorv32_cpu_pmp.vhd", + "neorv32_cpu_regfile.vhd", "neorv32_cpu.vhd", - "neorv32_cpu_alu.vhd", - "neorv32_cpu_cp_bitmanip.vhd", - "neorv32_cpu_cp_cfu.vhd", - "neorv32_cpu_cp_fpu.vhd", - "neorv32_cpu_cp_muldiv.vhd", - "neorv32_cpu_cp_shifter.vhd", - "neorv32_cpu_bus.vhd", - "neorv32_cpu_control.vhd", - "neorv32_cpu_decompressor.vhd", - "neorv32_cpu_regfile.vhd", - - # Processor components. + "neorv32_crc.vhd", + "neorv32_dcache.vhd", + "neorv32_debug_dm.vhd", + "neorv32_debug_dtm.vhd", + "neorv32_dma.vhd", + "neorv32_dmem.entity.vhd", + "neorv32_fifo.vhd", + "neorv32_gpio.vhd", + "neorv32_gptmr.vhd", + "neorv32_icache.vhd", + "neorv32_imem.entity.vhd", + "neorv32_intercon.vhd", + "neorv32_mtime.vhd", + "neorv32_neoled.vhd", + "neorv32_onewire.vhd", + "neorv32_package.vhd", + "neorv32_pwm.vhd", + "neorv32_sdi.vhd", + "neorv32_slink.vhd", + "neorv32_spi.vhd", + "neorv32_sysinfo.vhd", "neorv32_top.vhd", - "neorv32_icache.vhd", - "neorv32_busswitch.vhd", - "neorv32_bus_keeper.vhd", - "neorv32_wishbone.vhd", - "neorv32_mtime.vhd", - "neorv32_sysinfo.vhd", - "neorv32_debug_dm.vhd", - "neorv32_debug_dtm.vhd", + "neorv32_trng.vhd", + "neorv32_twi.vhd", + "neorv32_uart.vhd", + "neorv32_wdt.vhd", + "neorv32_wishbone.vhd", + "neorv32_xip.vhd", + "neorv32_xirq.vhd", ], "core/mem": [ @@ -197,7 +226,8 @@ def add_sources(self): } # Download VHDL sources (if not already present). - sha1 = "d610a0bd777f55d17dd59f174566aa88e911a1ec" + # Version 1.8.9 + sha1 = "fdb00a5d24e256ac9a9cb29410f2653c95068c91" for directory, vhds in sources.items(): for vhd in vhds: self.vhd2v_converter.add_source(os.path.join(cdir, vhd)) From f5b7c0d88e278d6605325ddd7c06b867323d4826 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 26 Sep 2023 13:49:19 +0200 Subject: [PATCH 217/454] CHANGES: Update. --- CHANGES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index a96db8e02..fbc6602f4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,7 +5,9 @@ [> Added -------- - cpu/naxriscv: Added SMP support. + cpu/naxriscv : Added SMP support. + cpu/neorv32 : Added Debug support and update core complex. + cpu/vexriscv_smp : Added hardware breakpoints support. [> Changed ---------- From 9842c95ef5b8081537b64c83eee7c2dba5ce80ba Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 2 Oct 2023 14:45:10 +0200 Subject: [PATCH 218/454] build/efinix/platform: adding method to get resource name based on signal --- litex/build/efinix/platform.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index 007031094..2f877ac0e 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -143,6 +143,19 @@ def get_pin_name(self, sig, without_index=False): return resource[0] + (f"{idx}" if slc else "") return None + def get_pad_name(self, sig): + """ Return pin name (GPIOX_Y_ZZZ). + + Parameters + ========== + sig: Signal + Signal for which pad name is searched. + """ + if sig is None: + return None + pin = self.get_pin_location(sig)[0] + return self.parser.get_pad_name_from_pin(pin) + def get_sig_constraint(self, sig): sc = self.constraint_manager.get_sig_constraints() for s, pins, others, resource in sc: From cd1bd73a87fb92d58250318523f2fc5c8b063bd1 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 2 Oct 2023 14:53:27 +0200 Subject: [PATCH 219/454] build/efinix/ifacewriter: adding method to generate lvds python code --- litex/build/efinix/ifacewriter.py | 103 ++++++++++++++++++------------ 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index a38f112d9..a50672a21 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -72,8 +72,6 @@ def generate_xml_blocks(self): if isinstance(block, InterfaceWriterXMLBlock): block.generate(root, namespaces) else: - if block["type"] == "LVDS": - self.add_lvds_xml(root, block) if block["type"] == "DRAM": self.add_dram_xml(root, block) @@ -367,6 +365,66 @@ def get_pin_name(pin): cmds.append(f"# ---------- END JTAG {id} ---------\n") return "\n".join(cmds) + def generate_lvds(self, block, verbose=True): + name = block["name"] + mode = block["mode"] + location = block["location"] + size = block["size"] + sig = block["sig"] + cmd = [] + + if mode == "INPUT": + block_type = "LVDS_TX" + tx_mode = block["tx_mode"] + cmd.append('design.create_block("{}", block_type="{}", tx_mode="{}")'.format(name, block_type, tx_mode)) + cmd.append('design.set_property("{}", "TX_DELAY", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_DIFF_TYPE", "LVDS", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_EN_SER", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_FASTCLK_PIN", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_HALF_RATE", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_MODE", "{}", "{}")'.format(name, tx_mode, block_type)) + cmd.append('design.set_property("{}", "TX_OE_PIN", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_OUT_PIN", "{}", "{}")'.format(name, sig.name, block_type)) + cmd.append('design.set_property("{}", "TX_PRE_EMP", "MEDIUM_LOW", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_RST_PIN", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) + cmd.append('design.set_property("{}", "TX_SLOWCLK_PIN", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_VOD", "TYPICAL", "{}")'.format(name, block_type)) + else: + # FIXME: untested + block_type = "LVDS_RX" + rx_mode = block["rx_mode"] + cmd.append('design.create_block("{}", block_type="{}", rx_conn_type="{}")'.format(name, block_type, rx_mode)) + cmd.append('design.set_property("{}","GBUF","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_CONN_TYPE","{}","{}")'.format(name, block_type, rx_mode)) + cmd.append('design.set_property("{}","RX_DBG_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DELAY","16","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DELAY_MODE","STATIC","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DESER","1","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","lvds_rx_inst1_RX_DLY_ENA","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DLY_INC_PIN","lvds_rx_inst1_RX_DLY_INC","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DLY_RST_PIN","lvds_rx_inst1_RX_DLY_RST","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_ENA_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_EN_DESER","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_FASTCLK_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_FIFO","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_FIFOCLK_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_FIFO_EMPTY_PIN","lvds_rx_inst1_RX_FIFO_EMPTY","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_HALF_RATE","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_IN_PIN","lvds_rx_inst1_RX_DATA","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_RST_PIN","lvds_rx_inst1_RX_RST","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_SLOWCLK_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_SLVS","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_TERM","ON","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_TERM_PIN","lvds_rx_inst1_RX_TERM","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_VOC_DRIVER","0","{}")'.format(name, block_type)) + + cmd.append('design.assign_resource("{}", "{}", "{}")\n'.format(name, location, block_type)) + + return '\n'.join(cmd) + def generate(self, partnumber): output = "" for block in self.blocks: @@ -381,6 +439,8 @@ def generate(self, partnumber): output += self.generate_mipi_tx(block) if block["type"] == "MIPI_RX_LANE": output += self.generate_mipi_rx(block) + if block["type"] == "LVDS": + output += self.generate_lvds(block) if block["type"] == "JTAG": output += self.generate_jtag(block) return output @@ -393,45 +453,6 @@ def footer(self): design.save()""" - def add_lvds_xml(self, root, params): - lvds_info = root.find("efxpt:lvds_info", namespaces) - if params["mode"] == "OUTPUT": - dir = "tx" - mode = "out" - else: - dir = "rx" - mode = "in" - - pad = self.platform.parser.get_pad_name_from_pin(params["location"][0]) - pad = pad.replace("TXP", "TX") - pad = pad.replace("TXN", "TX") - pad = pad.replace("RXP", "RX") - pad = pad.replace("RXN", "RX") - # Sometimes there is an extra identifier at the end - # TODO: do a better parser - if pad.count("_") == 2: - pad = pad.rsplit("_", 1)[0] - - lvds = et.SubElement(lvds_info, "efxpt:lvds", - name = params["name"], - lvds_def = pad, - ops_type = dir - ) - - et.SubElement(lvds, "efxpt:ltx_info", - pll_instance = "", - fast_clock_name = "{}".format(params["fast_clk"]), - slow_clock_name = "{}".format(params["slow_clk"]), - reset_name = "", - out_bname = "{}".format(params["name"]), - oe_name = "", - clock_div = "1", - mode = "{}".format(mode), - serialization = "{}".format(params["serialisation"]), - reduced_swing = "false", - load = "3" - ) - def add_iobank_info_xml(self, root, iobank_info): dev = root.find("efxpt:device_info", namespaces) bank_info = dev.find("efxpt:iobank_info", namespaces) From 97c84ebf274e995856f67c106b31e10f134a3a48 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 2 Oct 2023 14:56:23 +0200 Subject: [PATCH 220/454] build/efinix/common: adding DifferentialOutput support --- litex/build/efinix/common.py | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 2a8a0bd79..846f4b29d 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -157,6 +157,44 @@ class EfinixSDRTristate(Module): def lower(dr): return EfinixSDRTristateImpl(dr.platform, dr.io, dr.o, dr.oe, dr.i, dr.clk) +# Efinix DifferentialOutput ------------------------------------------------------------------------ + +class EfinixDifferentialOutputImpl(Module): + def __init__(self, platform, i, o_p, o_n): + # only keep _p + io_name = platform.get_pin_name(o_p) + io_pad = platform.get_pad_name(o_p) # need real pad name + io_prop = platform.get_pin_properties(o_p) + + # _p has _P_ and _n has _N_ followed by an optional function + # lvds block needs _PN_ + pad_split = io_pad.split('_') + assert pad_split[1] == 'P' + io_pad = f"{pad_split[0]}_PN_{pad_split[2]}" + + platform.add_extension([(io_name, 0, Pins(1))]) + i_data = platform.request(io_name) + + self.comb += i_data.eq(i) + block = { + "type" : "LVDS", + "mode" : "INPUT", + "tx_mode" : "DATA", + "name" : io_name, + "sig" : i_data, + "location" : io_pad, + "size" : 1, + } + platform.toolchain.ifacewriter.blocks.append(block) + platform.toolchain.excluded_ios.append(platform.get_pin(o_p)) + platform.toolchain.excluded_ios.append(platform.get_pin(o_n)) + platform.toolchain.excluded_ios.append(i_data) + +class EfinixDifferentialOutput: + @staticmethod + def lower(dr): + return EfinixDifferentialOutputImpl(dr.platform, dr.i, dr.o_p, dr.o_n) + # Efinix DDROutput --------------------------------------------------------------------------------- class EfinixDDROutputImpl(Module): @@ -225,6 +263,7 @@ def lower(dr): ClkInput : EfinixClkInput, ClkOutput : EfinixClkOutput, Tristate : EfinixTristate, + DifferentialOutput : EfinixDifferentialOutput, SDRTristate : EfinixSDRTristate, DDROutput : EfinixDDROutput, DDRInput : EfinixDDRInput, From 73a28d2c04580879916596394306576b77041f72 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 2 Oct 2023 17:32:08 +0200 Subject: [PATCH 221/454] build/efinix/ifacewriter: fix LVDS_TX, complete LVDS_RX --- litex/build/efinix/ifacewriter.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index a50672a21..151983fc3 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -373,7 +373,7 @@ def generate_lvds(self, block, verbose=True): sig = block["sig"] cmd = [] - if mode == "INPUT": + if mode == "OUTPUT": block_type = "LVDS_TX" tx_mode = block["tx_mode"] cmd.append('design.create_block("{}", block_type="{}", tx_mode="{}")'.format(name, block_type, tx_mode)) @@ -394,32 +394,35 @@ def generate_lvds(self, block, verbose=True): # FIXME: untested block_type = "LVDS_RX" rx_mode = block["rx_mode"] + term = block["term"] + ena = block["ena"] cmd.append('design.create_block("{}", block_type="{}", rx_conn_type="{}")'.format(name, block_type, rx_mode)) cmd.append('design.set_property("{}","GBUF","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_CONN_TYPE","{}","{}")'.format(name, block_type, rx_mode)) + cmd.append('design.set_property("{}","RX_CONN_TYPE","{}","{}")'.format(name, rx_mode, block_type)) cmd.append('design.set_property("{}","RX_DBG_PIN","","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_DELAY","16","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_DELAY_MODE","STATIC","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_DESER","1","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","lvds_rx_inst1_RX_DLY_ENA","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_DLY_INC_PIN","lvds_rx_inst1_RX_DLY_INC","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_DLY_RST_PIN","lvds_rx_inst1_RX_DLY_RST","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_ENA_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_ENA_PIN","{}","{}")'.format(name, ena.name, block_type)) cmd.append('design.set_property("{}","RX_EN_DESER","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_FASTCLK_PIN","","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_FIFO","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_FIFOCLK_PIN","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_FIFO_EMPTY_PIN","lvds_rx_inst1_RX_FIFO_EMPTY","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_HALF_RATE","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_IN_PIN","lvds_rx_inst1_RX_DATA","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_RST_PIN","lvds_rx_inst1_RX_RST","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_IN_PIN","{}","{}")'.format(name, sig.name, block_type)) cmd.append('design.set_property("{}","RX_SLOWCLK_PIN","","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_SLVS","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_TERM","ON","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_TERM_PIN","lvds_rx_inst1_RX_TERM","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_TERM","OFF","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_TERM_PIN","{}","{}")'.format(name, term.name, block_type)) cmd.append('design.set_property("{}","RX_VOC_DRIVER","0","{}")'.format(name, block_type)) + # Optional + #cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","lvds_rx_inst1_RX_DLY_ENA","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_DLY_INC_PIN","lvds_rx_inst1_RX_DLY_INC","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_DLY_RST_PIN","lvds_rx_inst1_RX_DLY_RST","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_FIFOCLK_PIN","","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_FIFO_EMPTY_PIN","lvds_rx_inst1_RX_FIFO_EMPTY","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_RST_PIN","lvds_rx_inst1_RX_RST","{}")'.format(name, block_type)) cmd.append('design.assign_resource("{}", "{}", "{}")\n'.format(name, location, block_type)) From 728afdd7589c262cc5c685052bf1fb16eea9305d Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 2 Oct 2023 17:32:49 +0200 Subject: [PATCH 222/454] build/efinix/common: DifferentialInput support --- litex/build/efinix/common.py | 57 +++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 846f4b29d..19b86a5b7 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -10,6 +10,7 @@ from litex.build.io import * +from litex.build.generic_platform import Pins from litex.build.efinix.efinity import EfinityToolchain # Colorama ----------------------------------------------------------------------------------------- @@ -178,7 +179,7 @@ def __init__(self, platform, i, o_p, o_n): self.comb += i_data.eq(i) block = { "type" : "LVDS", - "mode" : "INPUT", + "mode" : "OUTPUT", "tx_mode" : "DATA", "name" : io_name, "sig" : i_data, @@ -195,6 +196,59 @@ class EfinixDifferentialOutput: def lower(dr): return EfinixDifferentialOutputImpl(dr.platform, dr.i, dr.o_p, dr.o_n) +# Efinix DifferentialInput ------------------------------------------------------------------------- + +class EfinixDifferentialInputImpl(Module): + def __init__(self, platform, i_p, i_n, o): + # only keep _p + io_name = platform.get_pin_name(i_p) + io_pad = platform.get_pad_name(i_p) # need real pad name + io_prop = platform.get_pin_properties(i_p) + + # _p has _P_ and _n has _N_ followed by an optional function + # lvds block needs _PN_ + pad_split = io_pad.split('_') + assert pad_split[1] == 'P' + io_pad = f"{pad_split[0]}_PN_{pad_split[2]}" + + platform.add_extension([ + (io_name, 0, Pins(1)), + (f"{io_name}_ena", 0, Pins(1)), + (f"{io_name}_term", 0, Pins(1)), + ]) + o_data = platform.request(io_name) + i_ena = platform.request(io_name + "_ena") + i_term = platform.request(io_name + "_term") + + self.comb += [ + o.eq(o_data), + i_ena.eq(1), + i_term.eq(1), + ] + + block = { + "type" : "LVDS", + "mode" : "INPUT", + "rx_mode" : "NORMAL", + "name" : io_name, + "sig" : o_data, + "ena" : i_ena, + "term" : i_term, + "location" : io_pad, + "size" : 1, + } + platform.toolchain.ifacewriter.blocks.append(block) + platform.toolchain.excluded_ios.append(platform.get_pin(i_p)) + platform.toolchain.excluded_ios.append(platform.get_pin(i_n)) + platform.toolchain.excluded_ios.append(o_data) + platform.toolchain.excluded_ios.append(i_term) + platform.toolchain.excluded_ios.append(i_ena) + +class EfinixDifferentialInput: + @staticmethod + def lower(dr): + return EfinixDifferentialInputImpl(dr.platform, dr.i_p, dr.i_n, dr.o) + # Efinix DDROutput --------------------------------------------------------------------------------- class EfinixDDROutputImpl(Module): @@ -264,6 +318,7 @@ def lower(dr): ClkOutput : EfinixClkOutput, Tristate : EfinixTristate, DifferentialOutput : EfinixDifferentialOutput, + DifferentialInput : EfinixDifferentialInput, SDRTristate : EfinixSDRTristate, DDROutput : EfinixDDROutput, DDRInput : EfinixDDRInput, From be655f556ac6ce4bab3969fc508ac3285f6d9431 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 3 Oct 2023 06:56:16 +0200 Subject: [PATCH 223/454] build/efinix/ifacewriter: fixed generate_lvds to support trion family --- litex/build/efinix/ifacewriter.py | 59 ++++++++++++++++++------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 151983fc3..e28e3589f 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -377,51 +377,62 @@ def generate_lvds(self, block, verbose=True): block_type = "LVDS_TX" tx_mode = block["tx_mode"] cmd.append('design.create_block("{}", block_type="{}", tx_mode="{}")'.format(name, block_type, tx_mode)) - cmd.append('design.set_property("{}", "TX_DELAY", "0", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_DIFF_TYPE", "LVDS", "{}")'.format(name, block_type)) + if self.platform.family == "Titanium": + cmd.append('design.set_property("{}", "TX_DELAY", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_DIFF_TYPE", "LVDS", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_HALF_RATE", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_PRE_EMP", "MEDIUM_LOW", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) + cmd.append('design.set_property("{}", "TX_VOD", "TYPICAL", "{}")'.format(name, block_type)) + else: + cmd.append('design.set_property("{}","TX_OUTPUT_LOAD","3","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","TX_REDUCED_SWING","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","TX_SLOWCLK_DIV","1","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","TX_EN_SER","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}", "TX_EN_SER", "0", "{}")'.format(name, block_type)) cmd.append('design.set_property("{}", "TX_FASTCLK_PIN", "", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_HALF_RATE", "0", "{}")'.format(name, block_type)) cmd.append('design.set_property("{}", "TX_MODE", "{}", "{}")'.format(name, tx_mode, block_type)) cmd.append('design.set_property("{}", "TX_OE_PIN", "", "{}")'.format(name, block_type)) cmd.append('design.set_property("{}", "TX_OUT_PIN", "{}", "{}")'.format(name, sig.name, block_type)) - cmd.append('design.set_property("{}", "TX_PRE_EMP", "MEDIUM_LOW", "{}")'.format(name, block_type)) cmd.append('design.set_property("{}", "TX_RST_PIN", "", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) cmd.append('design.set_property("{}", "TX_SLOWCLK_PIN", "", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_VOD", "TYPICAL", "{}")'.format(name, block_type)) else: - # FIXME: untested block_type = "LVDS_RX" rx_mode = block["rx_mode"] term = block["term"] ena = block["ena"] + cmd.append('design.create_block("{}", block_type="{}", rx_conn_type="{}")'.format(name, block_type, rx_mode)) - cmd.append('design.set_property("{}","GBUF","","{}")'.format(name, block_type)) + if self.platform.family == "Titanium": + cmd.append('design.set_property("{}","GBUF","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DBG_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_TERM_PIN","{}","{}")'.format(name, term.name, block_type)) + cmd.append('design.set_property("{}","RX_VOC_DRIVER","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_SLVS","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_FIFO","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_HALF_RATE","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_ENA_PIN","{}","{}")'.format(name, ena.name, block_type)) + cmd.append('design.set_property("{}","RX_DELAY_MODE","STATIC","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DESER","1","{}")'.format(name, block_type)) + # Optional + #cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","lvds_rx_inst1_RX_DLY_ENA","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_DLY_INC_PIN","lvds_rx_inst1_RX_DLY_INC","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_DLY_RST_PIN","lvds_rx_inst1_RX_DLY_RST","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_FIFOCLK_PIN","","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_FIFO_EMPTY_PIN","lvds_rx_inst1_RX_FIFO_EMPTY","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) + else: + cmd.append('design.set_property("{}","RX_EN_DELAY","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_CONN_TYPE","{}","{}")'.format(name, rx_mode, block_type)) - cmd.append('design.set_property("{}","RX_DBG_PIN","","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_DELAY","16","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_DELAY_MODE","STATIC","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_DESER","1","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_ENA_PIN","{}","{}")'.format(name, ena.name, block_type)) cmd.append('design.set_property("{}","RX_EN_DESER","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_FASTCLK_PIN","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_FIFO","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_HALF_RATE","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_IN_PIN","{}","{}")'.format(name, sig.name, block_type)) cmd.append('design.set_property("{}","RX_SLOWCLK_PIN","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_SLVS","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_TERM","OFF","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_TERM_PIN","{}","{}")'.format(name, term.name, block_type)) - cmd.append('design.set_property("{}","RX_VOC_DRIVER","0","{}")'.format(name, block_type)) # Optional - #cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","lvds_rx_inst1_RX_DLY_ENA","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_DLY_INC_PIN","lvds_rx_inst1_RX_DLY_INC","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_DLY_RST_PIN","lvds_rx_inst1_RX_DLY_RST","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_FIFOCLK_PIN","","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_FIFO_EMPTY_PIN","lvds_rx_inst1_RX_FIFO_EMPTY","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) #cmd.append('design.set_property("{}","RX_RST_PIN","lvds_rx_inst1_RX_RST","{}")'.format(name, block_type)) cmd.append('design.assign_resource("{}", "{}", "{}")\n'.format(name, location, block_type)) From ca43b00337bc8f760b3d5d9197194b63193b0b62 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 3 Oct 2023 07:00:47 +0200 Subject: [PATCH 224/454] build/efinix/common: adding Trion support for DifferentialOutput/DifferentialInput --- litex/build/efinix/common.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/litex/build/efinix/common.py b/litex/build/efinix/common.py index 19b86a5b7..0197e2911 100644 --- a/litex/build/efinix/common.py +++ b/litex/build/efinix/common.py @@ -167,11 +167,17 @@ def __init__(self, platform, i, o_p, o_n): io_pad = platform.get_pad_name(o_p) # need real pad name io_prop = platform.get_pin_properties(o_p) - # _p has _P_ and _n has _N_ followed by an optional function - # lvds block needs _PN_ - pad_split = io_pad.split('_') - assert pad_split[1] == 'P' - io_pad = f"{pad_split[0]}_PN_{pad_split[2]}" + if platform.family == "Titanium": + # _p has _P_ and _n has _N_ followed by an optional function + # lvds block needs _PN_ + pad_split = io_pad.split('_') + assert pad_split[1] == 'P' + io_pad = f"{pad_split[0]}_PN_{pad_split[2]}" + else: + assert "TXP" in io_pad + # diff output pins are TXPYY and TXNYY + # lvds block needs TXYY + io_pad = io_pad.replace("TXP", "TX") platform.add_extension([(io_name, 0, Pins(1))]) i_data = platform.request(io_name) @@ -205,11 +211,17 @@ def __init__(self, platform, i_p, i_n, o): io_pad = platform.get_pad_name(i_p) # need real pad name io_prop = platform.get_pin_properties(i_p) - # _p has _P_ and _n has _N_ followed by an optional function - # lvds block needs _PN_ - pad_split = io_pad.split('_') - assert pad_split[1] == 'P' - io_pad = f"{pad_split[0]}_PN_{pad_split[2]}" + if platform.family == "Titanium": + # _p has _P_ and _n has _N_ followed by an optional function + # lvds block needs _PN_ + pad_split = io_pad.split('_') + assert pad_split[1] == 'P' + io_pad = f"{pad_split[0]}_PN_{pad_split[2]}" + else: + assert "RXP" in io_pad + # diff input pins are RXPYY and RXNYY + # lvds block needs RXYY + io_pad = io_pad.replace("RXP", "RX") platform.add_extension([ (io_name, 0, Pins(1)), From c0d376659669dda8615e65cdd414cbe68d8e7302 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 3 Oct 2023 17:24:01 +0200 Subject: [PATCH 225/454] build/xilinx/vivado: Add pre_optimize_commands. --- litex/build/xilinx/vivado.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 65f37938a..ed450efbd 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -103,6 +103,7 @@ def __init__(self): self.additional_commands = [] self.project_commands = XilinxVivadoCommands() self.pre_synthesis_commands = XilinxVivadoCommands() + self.pre_optimize_commands = XilinxVivadoCommands() self.pre_placement_commands = XilinxVivadoCommands() self.pre_routing_commands = XilinxVivadoCommands() self.incremental_implementation = False @@ -302,6 +303,10 @@ def build_project(self): tcl.append(f"report_utilization -file {self._build_name}_utilization_synth.rpt") tcl.append(f"write_checkpoint -force {self._build_name}_synth.dcp") + # Add pre-optimize commands + tcl.append("\n# Add pre-optimize commands\n") + tcl.extend(c.format(build_name=self._build_name) for c in self.pre_optimize_commands.resolve(self._vns)) + # Optimize tcl.append("\n# Optimize design\n") tcl.append(f"opt_design -directive {self.opt_directive}") From 5fd5195a7dfbdf57ada7fd1769c713292f332708 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 1 Mar 2023 08:28:39 +0100 Subject: [PATCH 226/454] soc/cores/clock: adding CologneChip CC_PLL --- litex/soc/cores/clock/colognechip.py | 151 +++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 litex/soc/cores/clock/colognechip.py diff --git a/litex/soc/cores/clock/colognechip.py b/litex/soc/cores/clock/colognechip.py new file mode 100644 index 000000000..e4112aa8d --- /dev/null +++ b/litex/soc/cores/clock/colognechip.py @@ -0,0 +1,151 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Gwenhael Goavec-merou +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.gen import * + +from litex.soc.cores.clock.common import * + +# CologneChip GateMate CC_PLL --------------------------------------------------------------------- + +class GateMatePLL(LiteXModule): + """ + CC_PLL generator for CologneChip GateMate FPGAs (UG1001 7.3) + Parameters + ---------- + perf_mode: str + FPGA operation mode for VDD_PLL (UNDEFINED, LOWPOWER, ECONOMY, SPEED) (default: UNDEFINED) + low_jitter: int + Low Jitter Mode (0,1) (default: 1) + lock_req: int + Lock status required before PLL output enable (0,1) (default: 0) + + Attributes + ---------- + reset: Signal in + locked: Signal out + """ + + def __init__(self, + perf_mode = "undefined", + low_jitter = 1, + lock_req = 0): + + assert perf_mode.lower() in ["undefined", "lowpower", "economy", "speed"] + assert low_jitter in [0, 1] + assert lock_req in [0, 1] + + self.logger = logging.getLogger("CC_PLL") + self.reset = Signal() + self.locked = Signal() + self._clkin_freq = None + self._clkouts = {} + self._perf_mode = perf_mode.upper() + self._low_jitter = low_jitter + self._lock_req = lock_req + + self._max_freq = { + "undefined" : 250e6, + "lowpower" : 250e6, + "economy" : 312.5e6, + "speed" : 416.75e6 + }[perf_mode.lower()] + + def register_clkin(self, clkin, freq, usr_clk_ref=False): + """ + Register clkin signal as input PLL input signal + Parameters + ---------- + clkin: ClockSignal / Signal + input clock signal + freq: float + input clock frequency (Hz) + usr_clk_ref: bool + select if clkin is connected to CLK_REF or USR_CLK_REF + """ + self._usr_clk_ref = usr_clk_ref + self._clkin = Signal() + if isinstance(clkin, (Signal, ClockSignal)): + self.comb += self._clkin.eq(clkin) + else: + raise ValueError + self._clkin_freq = freq + register_clkin_log(self.logger, clkin, freq) + + def create_clkout(self, cd, freq, phase=0, with_reset=True): + """ + Register cd ClockDomain as PLL output signal + Parameters + ---------- + cd: ClockDomain + input clock signal + freq: float + output clock frequency (Hz) + phase: int + must be 0, 90, 180, 270 + with_reset: bool + drive cd reset + """ + assert phase in [0, 90, 180, 270] + assert phase not in self._clkouts + assert freq <= self._max_freq + + clkout = Signal() + self._clkouts[phase] = (clkout, freq) + if with_reset: + self.specials += AsyncResetSynchronizer(cd, ~self.locked) + self.comb += cd.clk.eq(clkout) + create_clkout_log(self.logger, cd.name, freq, 0, phase) + + def do_finalize(self): + assert hasattr(self, "_clkin") + assert len(self._clkouts) > 0 + + # set/unset frequency doubler for CLK180/CLK270 + clk_doub = {180:0, 270:0} + # extract slowest frequency -> ref + clkout_freq = min([f for (_, f) in self._clkouts.values()]) + + for phase in [0, 90, 180, 270]: + (clk, freq) = self._clkouts.get(phase, (Open(), 0)) + self._clkouts[phase] = (clk, freq) # force update (add unselected output) + if freq != 0: + # clk0 and clk90 frequency must be equal to clkout freq + if phase in [0, 90]: + assert freq == clkout_freq + else: + # clk180 and clk270 must be x1 or x2 clkout frequency + assert freq in [clkout_freq, 2 * clkout_freq] + # when clk180 or clk270 == x2 clkout: CLKxx_DOUB must be set + if freq == 2 * clkout_freq: + clk_doub[phase] = 1 + + assert clkout_freq is not None + + freqInMHz = self._clkin_freq/1e6 + freqOutMHz = clkout_freq/1e6 + + self.specials += Instance("CC_PLL", + p_REF_CLK = freqInMHz, # reference input in MHz + p_OUT_CLK = freqOutMHz, # pll output frequency in MHz + p_LOW_JITTER = self._low_jitter, # 0: disable, 1: enable low jitter mode + p_PERF_MD = self._perf_mode, # FPGA operation mode for VDD_PLL + p_LOCK_REQ = self._lock_req, # Lock status required before PLL output enable + p_CI_FILTER_CONST = 2, # optional CI filter constant + p_CP_FILTER_CONST = 4, # optional CP filter constant + i_CLK_REF = self._clkin if not self._usr_clk_ref else Open(), + i_USR_CLK_REF = self._clkin if self._usr_clk_ref else Open(), + i_CLK_FEEDBACK = 0, + i_USR_LOCKED_STDY_RST = self.reset, + o_CLK_REF_OUT = Open(), + o_USR_PLL_LOCKED_STDY = Open(), + o_USR_PLL_LOCKED = self.locked, + **{f"o_CLK{p}" : c for (p, (c, _)) in self._clkouts.items()}, + **{f"p_CLK{p}_DOUB" : v for (p, v) in clk_doub.items()}, + ) + From 1370f503e840e43a773c8b96553df8de7945741b Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 13 Jun 2022 21:24:45 +0200 Subject: [PATCH 227/454] build: adding colognechip toolchain Signed-off-by: Gwenhael Goavec-Merou --- litex/build/colognechip/__init__.py | 1 + litex/build/colognechip/colognechip.py | 156 +++++++++++++++++++++++++ litex/build/colognechip/common.py | 132 +++++++++++++++++++++ litex/build/colognechip/platform.py | 68 +++++++++++ 4 files changed, 357 insertions(+) create mode 100644 litex/build/colognechip/__init__.py create mode 100644 litex/build/colognechip/colognechip.py create mode 100644 litex/build/colognechip/common.py create mode 100644 litex/build/colognechip/platform.py diff --git a/litex/build/colognechip/__init__.py b/litex/build/colognechip/__init__.py new file mode 100644 index 000000000..4f7ade7e9 --- /dev/null +++ b/litex/build/colognechip/__init__.py @@ -0,0 +1 @@ +from litex.build.colognechip.platform import CologneChipPlatform diff --git a/litex/build/colognechip/colognechip.py b/litex/build/colognechip/colognechip.py new file mode 100644 index 000000000..2de8b7a6e --- /dev/null +++ b/litex/build/colognechip/colognechip.py @@ -0,0 +1,156 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Gwenhael Goavec-Merou +# SPDX-License-Identifier: BSD-2-Clause + +import os +import sys +import math +import subprocess +from shutil import which, copyfile + +from migen.fhdl.structure import _Fragment + +from litex.build.generic_platform import * +from litex.build import tools +from litex.build.generic_toolchain import GenericToolchain +from litex.build.yosys_wrapper import YosysWrapper, yosys_args, yosys_argdict + + +# CologneChipToolchain ----------------------------------------------------------------------------- + +class CologneChipToolchain(GenericToolchain): + attr_translate = {} + supported_build_backend = ["litex", "edalize"] + + def __init__(self): + super().__init__() + self._yosys = None + self._yosys_cmds = [] + self._synth_opts = "-nomx8 " + + def finalize(self): + self._yosys = YosysWrapper( + platform = self.platform, + build_name = self._build_name, + target = "gatemate", + output_name = self._build_name+"_synth", + template = [], + yosys_opts = self._synth_opts, + yosys_cmds = self._yosys_cmds, + synth_format = "v", + ) + + # IO Constraints (.ccf) ------------------------------------------------------------------------ + + def _get_pin_direction(self, pinname): + pins = self.platform.constraint_manager.get_io_signals() + for pin in sorted(pins, key=lambda x: x.duid): + if (pinname.split("[")[0] == pin.name): + if pin.direction == "output": + return "Pin_out" + elif pin.direction == "input": + return "Pin_in" + else: + return "Pin_inout" + return "Unknown" + + def build_io_constraints(self): + ccf = [] + + flat_sc = [] + for name, pins, other, resource in self.named_sc: + if len(pins) > 1: + for i, p in enumerate(pins): + flat_sc.append((f"{name}[{i}]", p, other)) + else: + flat_sc.append((name, pins[0], other)) + + for name, pin, other in flat_sc: + pin_cst = "" + if pin != "X": + direction = self._get_pin_direction(name) + pin_cst = f"{direction} \"{name}\" Loc = \"{pin}\"" + + for c in other: + if isinstance(c, Misc): + pin_cst += f" | {c.misc}" + pin_cst += ";" + ccf.append(pin_cst) + + if self.named_pc: + ccf.extend(self.named_pc) + + tools.write_to_file(f"{self._build_name}.ccf", "\n".join(ccf)) + return (f"{self._build_name}.ccf", "CCF") + + # Project (.ys) -------------------------------------------------------------------------------- + + def build_project(self): + """ create project files (mainly Yosys ys file) + """ + self._yosys.build_script() + + # Script --------------------------------------------------------------------------------------- + + def build_script(self): + """ create build_xxx.yy by using Yosys and p_r instances. + Return + ====== + the script name (str) + """ + + if sys.platform in ("win32", "cygwin"): + script_ext = ".bat" + script_contents = "@echo off\nrem Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\n\n" + fail_stmt = " || exit /b" + else: + script_ext = ".sh" + script_contents = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\nset -e\n" + fail_stmt = "" + fail_stmt += "\n" + + # yosys call + script_contents += self._yosys.get_yosys_call("script") + fail_stmt + # p_r call + script_contents += "p_r -ccf {build_name}.ccf -A 1 -i {build_name}_synth.v -o {build_name} -lib ccag\n".format( + build_name = self._build_name) + + script_file = "build_" + self._build_name + script_ext + tools.write_to_file(script_file, script_contents, force_unix=False) + + return script_file + + def run_script(self, script): + """ run build_xxx.yy script + Parameters + ========== + script: str + script name to use + """ + if sys.platform in ("win32", "cygwin"): + shell = ["cmd", "/c"] + else: + shell = ["bash"] + + if which("yosys") is None or which("p_r") is None: + msg = "Unable to find CologneChip toolchain, please:\n" + msg += "- Add Yosys/p_r toolchain to your $PATH." + raise OSError(msg) + + if subprocess.call(shell + [script]) != 0: + raise OSError("Error occured during Yosys/p_r's script execution.") + + + def add_period_constraint(self, platform, clk, period): + pass + +def colognechip_args(parser): + # TODO: yosys (default's yosys aren't supported + # TODO: p_r args + pass + +def colognechip_argdict(args): + # TODO: ditto + return {} diff --git a/litex/build/colognechip/common.py b/litex/build/colognechip/common.py new file mode 100644 index 000000000..54955c33a --- /dev/null +++ b/litex/build/colognechip/common.py @@ -0,0 +1,132 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Gwenhael Goavec-Merou +# SPDX-License-Identifier: BSD-2-Clause + +from migen.fhdl.module import Module +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.build.io import * + +# CologneChip AsyncResetSynchronizer --------------------------------------------------------------- + +class CologneChipAsyncResetSynchronizerImpl(Module): + def __init__(self, cd, async_reset): + rst1 = Signal() + self.specials += [ + Instance("CC_DFF", + p_CLK_INV = 0, + p_EN_INV = 0, + p_SR_INV = 0, + p_SR_VAL = 1, + i_D = 0, + i_CLK = cd.clk, + i_EN = 1, + i_SR = async_reset, + o_Q = rst1), + Instance("CC_DFF", + p_CLK_INV = 0, + p_EN_INV = 0, + p_SR_INV = 0, + p_SR_VAL = 1, + i_D = rst1, + i_CLK = cd.clk, + i_EN = 1, + i_SR = async_reset, + o_Q = cd.rst) + ] + +class CologneChipAsyncResetSynchronizer: + @staticmethod + def lower(dr): + return CologneChipAsyncResetSynchronizerImpl(dr.cd, dr.async_reset) + +# CologneChip DDR Input ---------------------------------------------------------------------------- + +class CologneChipDDRInputImpl(Module): + def __init__(self, i, o1, o2, clk): + self.specials += Instance("CC_IDDR", + i_CLK = clk, + i_D = i, + o_Q0 = o1, + o_Q1 = o2, + ) + +class CologneChipDDRInput: + @staticmethod + def lower(dr): + return CologneChipInputImpl(dr.i, dr.o1, dr.o2, dr.clk) + +# CologneChip DDR Output --------------------------------------------------------------------------- + +class CologneChipDDROutputImpl(Module): + def __init__(self, i1, i2, o, clk): + self.specials += Instance("CC_ODDR", + p_CLK_INV = 0, + i_CLK = clk, + i_DDR = ~clk, + i_D0 = i1, + i_D1 = i2, + o_Q = o, + ) + +class CologneChipDDROutput: + @staticmethod + def lower(dr): + return CologneChipDDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk) + +# CologneChip Differential Input ------------------------------------------------------------------- + +class CologneChipDifferentialInputImpl(Module): + def __init__(self, i_p, i_n, o): + self.specials += Instance("CC_LVDS_IBUF", + i_I_P = i_p, + i_I_N = i_n, + o_Y = o, + ) + +class CologneChipDifferentialInput: + @staticmethod + def lower(dr): + return CologneChipDifferentialInputImpl(dr.i_p, dr.i_n, dr.o) + +# CologneChip Differential Output ------------------------------------------------------------------ + +class CologneChipDifferentialOutputImpl(Module): + def __init__(self, i, o_p, o_n): + self.specials += Instance("CC_LVDS_OBUF", + i_A = i, + o_O_P = o_p, + o_O_N = o_n, + ) + +class CologneChipDifferentialOutput: + @staticmethod + def lower(dr): + return CologneChipDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n) + +# CologneChip SDR Input ---------------------------------------------------------------------------- + +class CologneChipSDRInputImpl(Module): + def __init__(self, i, o): + self.specials += Instance("CC_IBUF", + i_I = i, + o_O = o, + ) + +class CologneChipSDRInput: + @staticmethod + def lower(dr): + return CologneChipSDRInput(dr.i, dr.o) + +# CologneChip Special Overrides -------------------------------------------------------------------- + +colognechip_special_overrides = { + AsyncResetSynchronizer: CologneChipAsyncResetSynchronizer, + DDRInput: CologneChipDDRInput, + DDROutput: CologneChipDDROutput, + DifferentialInput: CologneChipDifferentialInput, + DifferentialOutput: CologneChipDifferentialOutput, + SDRInput: CologneChipSDRInput, +} diff --git a/litex/build/colognechip/platform.py b/litex/build/colognechip/platform.py new file mode 100644 index 000000000..127c4e2fb --- /dev/null +++ b/litex/build/colognechip/platform.py @@ -0,0 +1,68 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Gwenhael Goavec-Merou +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from litex.build.generic_platform import GenericPlatform +from litex.build.colognechip import common, colognechip + +# CologneChipPlatform ------------------------------------------------------------------------------ + +class CologneChipPlatform(GenericPlatform): + bitstream_ext = "_00.cfg.bit" + + _supported_toolchains = ["colognechip"] + + def __init__(self, device, *args, toolchain="colognechip", devicename=None, **kwargs): + GenericPlatform.__init__(self, device, *args, **kwargs) + + self.toolchain = colognechip.CologneChipToolchain() + + def get_verilog(self, *args, special_overrides=dict(), **kwargs): + so = dict(common.colognechip_special_overrides) + so.update(special_overrides) + return GenericPlatform.get_verilog(self, *args, + special_overrides = so, + attr_translate = self.toolchain.attr_translate, + **kwargs) + + def build(self, *args, **kwargs): + return self.toolchain.build(self, *args, **kwargs) + + def add_period_constraint(self, clk, period): + if clk is None: return + self.toolchain.add_period_constraint(self, clk, period) + + @classmethod + def fill_args(cls, toolchain, parser): + """ + pass parser to the specific toolchain to + fill this with toolchain args + + Parameters + ========== + toolchain: str + toolchain name + parser: argparse.ArgumentParser + parser to be filled + """ + colognechip.colognechip_args(parser) + + @classmethod + def get_argdict(cls, toolchain, args): + """ + return a dict of args + + Parameters + ========== + toolchain: str + toolchain name + + Return + ====== + a dict of key/value for each args or an empty dict + """ + return colognechip.colognechip_argdict(args) From 98eb27df5265421e1b2770620fb16c40f196740f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 5 Oct 2023 08:25:52 +0200 Subject: [PATCH 228/454] CHANGES: Update. --- CHANGES.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index fbc6602f4..decf7088a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,9 +5,10 @@ [> Added -------- - cpu/naxriscv : Added SMP support. - cpu/neorv32 : Added Debug support and update core complex. - cpu/vexriscv_smp : Added hardware breakpoints support. + cpu/naxriscv : Added SMP support. + cpu/neorv32 : Added Debug support and update core complex. + cpu/vexriscv_smp : Added hardware breakpoints support. + build/colognechip : Added initial support. [> Changed ---------- From cd8218779e0eb05c73785cd6b8866dc3215c1710 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 6 Oct 2023 10:10:22 +0200 Subject: [PATCH 229/454] soc/cores/video/VideoFramebuffer: Add VTG/DMA synchronization when DMA is enabled to simplify use. --- CHANGES.md | 1 + litex/soc/cores/video.py | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index decf7088a..6b8247477 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ cpu/neorv32 : Added Debug support and update core complex. cpu/vexriscv_smp : Added hardware breakpoints support. build/colognechip : Added initial support. + soc/cores/video : Added VTG/DMA synchronization stage to VideoFramebuffer. [> Changed ---------- diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 97227ee09..76fe6ee77 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -692,8 +692,25 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 ] video_pipe_source = self.cdc.source - # Video Generation. - self.comb += [ + # Video Synchronization/Generation. + fsm = FSM(reset_state="VTG-SYNC") + fsm = ClockDomainsRenamer(clock_domain)(fsm) + fsm = ResetInserter()(fsm) + self.submodules += fsm + self.specials += MultiReg(self.dma.fsm.reset, fsm.reset, clock_domain) + fsm.act("VTG-SYNC", + vtg_sink.ready.eq(1), + If(vtg_sink.valid & vtg_sink.last, + NextState("DMA-SYNC") + ) + ) + fsm.act("DMA-SYNC", + video_pipe_source.ready.eq(1), + If(video_pipe_source.valid & video_pipe_source.last, + NextState("RUN") + ) + ) + fsm.act("RUN", vtg_sink.ready.eq(1), If(vtg_sink.valid & vtg_sink.de, video_pipe_source.connect(source, keep={"valid", "ready"}), @@ -701,7 +718,7 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 ), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), - ] + ) if (depth == 32): self.comb += [ source.r.eq(video_pipe_source.data[ 0: 8]), From 5380df3994beed750b3bc6879fec2ed44dd724e4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 6 Oct 2023 19:50:52 +0200 Subject: [PATCH 230/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 6b8247477..a1dc86be1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ cpu/vexriscv_smp : Added hardware breakpoints support. build/colognechip : Added initial support. soc/cores/video : Added VTG/DMA synchronization stage to VideoFramebuffer. + litepcie/dma : Improved LitePCIeDMADescriptorSplitter timings. [> Changed ---------- From 196b68e4afdbbea8d6384be23a850e8908d7fa5e Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sat, 7 Oct 2023 09:25:08 +0200 Subject: [PATCH 231/454] interconnect/wishbone: Add linear burst support to DownConverter --- litex/soc/interconnect/wishbone.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 05dab1b33..212064bd1 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -285,8 +285,21 @@ def __init__(self, master, slave): # Control Path. self.comb += [ done.eq(count == (ratio - 1)), + + Case(master.cti, { + # incrementing address burst cycle + CTI_BURST_INCREMENTING: slave.cti.eq(CTI_BURST_INCREMENTING), + # end current burst cycle + CTI_BURST_END: slave.cti.eq(Mux(done, CTI_BURST_END, + CTI_BURST_INCREMENTING)), + # unsupported burst cycle + "default": slave.cti.eq(CTI_BURST_NONE), + }), + # wrap conversion not supported + If(master.bte != 0, slave.cti.eq(CTI_BURST_NONE)), + If(master.stb & master.cyc, - skip.eq(slave.sel == 0), + skip.eq((slave.sel == 0) & (slave.cti == CTI_BURST_NONE)), slave.cyc.eq(~skip), slave.stb.eq(~skip), slave.we.eq(master.we), From 0890bf4c1f4b822ff870e856726a971082637ea8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 11 Oct 2023 09:13:33 +0200 Subject: [PATCH 232/454] CHANGES: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index a1dc86be1..8d2806fc9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ------------------------ [> Fixed -------- + liteeth/arp : Fixed response on table update. [> Added -------- From e426e78e312d885c50b4dab4c17d9ca671c2b563 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 11 Oct 2023 10:17:57 +0200 Subject: [PATCH 233/454] CHANGES.md: Update. --- CHANGES.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 8d2806fc9..f7f931b34 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,12 +6,13 @@ [> Added -------- - cpu/naxriscv : Added SMP support. - cpu/neorv32 : Added Debug support and update core complex. - cpu/vexriscv_smp : Added hardware breakpoints support. - build/colognechip : Added initial support. - soc/cores/video : Added VTG/DMA synchronization stage to VideoFramebuffer. - litepcie/dma : Improved LitePCIeDMADescriptorSplitter timings. + cpu/naxriscv : Added SMP support. + cpu/neorv32 : Added Debug support and update core complex. + cpu/vexriscv_smp : Added hardware breakpoints support. + build/colognechip : Added initial support. + soc/cores/video : Added VTG/DMA synchronization stage to VideoFramebuffer. + litepcie/dma : Improved LitePCIeDMADescriptorSplitter timings. + interconnect/wishbone : Added linear burst support to DownConverter. [> Changed ---------- From 124ce54918564d3b08029c6774c3ec47e2cbaf32 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 12 Oct 2023 09:20:05 +0200 Subject: [PATCH 234/454] core/naxriscv now has an coherent l2 cache --- litex/soc/cores/cpu/naxriscv/core.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 3dd5aa03a..65aaf989d 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -55,6 +55,8 @@ class NaxRiscv(CPU): jtag_instruction = False with_dma = False litedram_width = 32 + l2_bytes = 128*1024 + l2_ways = 8 # ABI. @staticmethod @@ -113,6 +115,8 @@ def args_fill(parser): cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") cpu_group.add_argument("--no-netlist-cache", action="store_true", help="Always (re-)build the netlist") cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU") + cpu_group.add_argument("--l2-bytes", default=128*1024, help="NaxRiscv L2 bytes, default 128 KB") + cpu_group.add_argument("--l2-ways", default=8, help="NaxRiscv L2 ways, default 8") @staticmethod def args_read(args): @@ -136,6 +140,10 @@ def args_read(args): NaxRiscv.linker_output_format = f"elf{xlen}-littleriscv" if args.cpu_count: NaxRiscv.cpu_count = args.cpu_count + if args.l2_bytes: + NaxRiscv.l2_bytes = args.l2_bytes + if args.l2_ways: + NaxRiscv.l2_ways = args.l2_ways def __init__(self, platform, variant): @@ -259,6 +267,8 @@ def generate_netlist_name(reset_address): md5_hash.update(str(NaxRiscv.litedram_width).encode('utf-8')) md5_hash.update(str(NaxRiscv.xlen).encode('utf-8')) md5_hash.update(str(NaxRiscv.cpu_count).encode('utf-8')) + md5_hash.update(str(NaxRiscv.l2_bytes).encode('utf-8')) + md5_hash.update(str(NaxRiscv.l2_ways).encode('utf-8')) md5_hash.update(str(NaxRiscv.jtag_tap).encode('utf-8')) md5_hash.update(str(NaxRiscv.jtag_instruction).encode('utf-8')) md5_hash.update(str(NaxRiscv.with_dma).encode('utf-8')) @@ -298,8 +308,8 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "ee4c6fb7" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "ee95492a" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "4da1cd82" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "8eed9583" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") @@ -307,6 +317,8 @@ def generate_netlist(reset_address): gen_args.append(f"--reset-vector={reset_address}") gen_args.append(f"--xlen={NaxRiscv.xlen}") gen_args.append(f"--cpu-count={NaxRiscv.cpu_count}") + gen_args.append(f"--l2-bytes={NaxRiscv.l2_bytes}") + gen_args.append(f"--l2-ways={NaxRiscv.l2_ways}") gen_args.append(f"--litedram-width={NaxRiscv.litedram_width}") for region in NaxRiscv.memory_regions: gen_args.append(f"--memory-region={region[0]},{region[1]},{region[2]},{region[3]}") From 45b0c8dcd34e5441e6d023ff31598899daa7d782 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 12 Oct 2023 12:29:25 +0200 Subject: [PATCH 235/454] core/naxriscv update --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 65aaf989d..439f21ec6 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -309,7 +309,7 @@ def generate_netlist(reset_address): if NaxRiscv.update_repo != "no": NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "4da1cd82" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "8eed9583" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "74c5d7de" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From 0c77eb242d0719b92c4594863377515ff046fcf3 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 12 Oct 2023 13:44:15 +0200 Subject: [PATCH 236/454] core/naxriscv update --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 439f21ec6..77df32be3 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -308,7 +308,7 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "4da1cd82" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "2948aa4d" if NaxRiscv.update_repo=="recommended" else None) NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "74c5d7de" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] From 12f87212e385e214ad7d1a8bac93aaf5a282ff1c Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 12 Oct 2023 15:15:51 +0200 Subject: [PATCH 237/454] core/naxriscv fix l2 parameters --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 77df32be3..071936e03 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -308,7 +308,7 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "2948aa4d" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "9e44c1b6" if NaxRiscv.update_repo=="recommended" else None) NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "74c5d7de" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] From fac003bbf9e7ccb30bf56a13fe3a37cd6cd0fedd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 13 Oct 2023 09:26:52 +0200 Subject: [PATCH 238/454] build/openfpgaloader/flash: Add verify capability. --- litex/build/openfpgaloader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index abaf12d74..3b201fb9e 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -29,11 +29,13 @@ def load_bitstream(self, bitstream_file): cmd = self.cmd + ["--bitstream", bitstream_file] self.call(cmd) - def flash(self, address, data_file, external=False): + def flash(self, address, data_file, external=False, verify=False): cmd = self.cmd + ["--write-flash", "--bitstream", data_file] if external: cmd += ["--external-flash"] if address: cmd += ["--offset"] cmd += [str(address)] + if verify: + cmd += ["--verify"] self.call(cmd) From e499dd84b5dcff311dea67dc92dd1f94b9442277 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 13 Oct 2023 13:14:18 +0200 Subject: [PATCH 239/454] build/openfpgaloader: Add unprotect_flash capability. --- litex/build/openfpgaloader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index 3b201fb9e..c6f38ae38 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -29,13 +29,15 @@ def load_bitstream(self, bitstream_file): cmd = self.cmd + ["--bitstream", bitstream_file] self.call(cmd) - def flash(self, address, data_file, external=False, verify=False): + def flash(self, address, data_file, external=False, unprotect_flash=False, verify=False): cmd = self.cmd + ["--write-flash", "--bitstream", data_file] if external: cmd += ["--external-flash"] if address: cmd += ["--offset"] cmd += [str(address)] + if unprotect_flash: + cmd += ["--unprotect-flash"] if verify: cmd += ["--verify"] self.call(cmd) From 5d7e9c94a6f1431a65cbafdcab1615f36f009fce Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 17 Oct 2023 13:17:12 +0200 Subject: [PATCH 240/454] build/efinix/dbparser: workaround for Ti60F100S3F2 with only 3 PLLs --- litex/build/efinix/dbparser.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/build/efinix/dbparser.py b/litex/build/efinix/dbparser.py index 1fa882036..411acc4bf 100644 --- a/litex/build/efinix/dbparser.py +++ b/litex/build/efinix/dbparser.py @@ -92,6 +92,10 @@ def get_block_instance_names(self, block): if p.get('block') == block: names.append(p.get('name')) + # Ti60F100S3F2 has only 3 PLLs + if block == "pll" and self.device == "Ti60F100S3F2": + names.remove("PLL_BL0") + print(f"block {block}: names:{names}") return names From cd439da18ece1fc4800d916706076c788a9a7150 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 17 Oct 2023 13:17:31 +0200 Subject: [PATCH 241/454] soc/cores/clock/efinix: allows dyn_phase_shift configuration --- litex/soc/cores/clock/efinix.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index 28e64a244..14fe6414c 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -18,7 +18,7 @@ class EFINIXPLL(LiteXModule): n = 0 nclkouts_max = 3 - def __init__(self, platform,version="V1_V2"): + def __init__(self, platform,version="V1_V2", dyn_phase_shift_pads=[]): self.logger = logging.getLogger("EFINIXPLL") if version == "V1_V2": @@ -45,6 +45,10 @@ def __init__(self, platform,version="V1_V2"): block["locked"] = self.name + "_locked" block["rstn"] = self.name + "_rstn" block["version"] = version + if len(dyn_phase_shift_pads) > 0: + block["shift_ena"] = dyn_phase_shift_pads["shift_ena"] + block["shift"] = dyn_phase_shift_pads["shift"] + block["shift_sel"] = dyn_phase_shift_pads["shift_sel"] self.platform.toolchain.ifacewriter.blocks.append(block) # Connect PLL's rstn/locked. @@ -94,7 +98,7 @@ def register_clkin(self, clkin, freq, name=""): self.logger.info("Use {}".format(colorer(block["resource"], "green"))) - def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True): + def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True, dyn_phase=False): assert self.nclkouts < self.nclkouts_max clk_out_name = f"{self.name}_clkout{self.nclkouts}" if name == "" else name @@ -114,7 +118,7 @@ def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True): self.nclkouts += 1 block = self.platform.toolchain.ifacewriter.get_block(self.name) - block["clk_out"].append([clk_out_name, freq, phase, margin]) + block["clk_out"].append([clk_out_name, freq, phase, margin, dyn_phase]) def extra(self, extra): block = self.platform.toolchain.ifacewriter.get_block(self.name) @@ -133,8 +137,8 @@ def do_finalize(self): class TITANIUMPLL(EFINIXPLL): nclkouts_max = 5 - def __init__(self, platform): - EFINIXPLL.__init__(self, platform, version="V3") + def __init__(self, platform, dyn_phase_shift_pads=[]): + EFINIXPLL.__init__(self, platform, version="V3", dyn_phase_shift_pads=dyn_phase_shift_pads) # Efinix / TRION ---------------------------------------------------------------------------------- From 6f02a7f5086a26aa042c03f77e4ae7b15cfe208a Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 17 Oct 2023 13:17:53 +0200 Subject: [PATCH 242/454] build/efinix/ifacewriter: adding PHASE_SHIFT_xx and CLKOUTx_DYNPHASE_EN --- litex/build/efinix/ifacewriter.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index e28e3589f..af28d5ff3 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -291,6 +291,11 @@ def generate_pll(self, block, partnumber, verbose=True): if block["rstn"] != "": cmd += 'design.set_property("{}","RSTN_PIN","{}", block_type="PLL")\n\n'.format(name, block["rstn"]) + if block.get("shift_ena", None) is not None: + cmd += 'design.set_property("{}","PHASE_SHIFT_ENA_PIN","{}","PLL")\n'.format(name, block["shift_ena"].name) + cmd += 'design.set_property("{}","PHASE_SHIFT_PIN","{}","PLL")\n'.format(name, block["shift"].name) + cmd += 'design.set_property("{}","PHASE_SHIFT_SEL_PIN","{}","PLL")\n'.format(name, block["shift_sel"].name) + # Output clock 0 is enabled by default for i, clock in enumerate(block["clk_out"]): if i > 0: @@ -310,7 +315,10 @@ def generate_pll(self, block, partnumber, verbose=True): for i, clock in enumerate(block["clk_out"]): cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6) cmd += ' "CLKOUT{}_PHASE": "{}",\n'.format(i, clock[2]) + if clock[4] == 1: + cmd += ' "CLKOUT{}_DYNPHASE_EN": "1",\n'.format(i) cmd += "}\n" + cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n'.format(name) if "extra" in block: From d95d5bdce97753ca0330d668816415ea1eebd3a6 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 17 Oct 2023 13:19:22 +0200 Subject: [PATCH 243/454] build/efinix/ifacewriter, soc/cores/ram/efinix_hyperram: adding F100 internal HyperRAM support --- litex/build/efinix/ifacewriter.py | 37 +++++++ litex/soc/cores/ram/efinix_hyperram.py | 138 +++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 litex/soc/cores/ram/efinix_hyperram.py diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index af28d5ff3..1a58cc1b9 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -447,6 +447,41 @@ def generate_lvds(self, block, verbose=True): return '\n'.join(cmd) + def generate_hyperram(self, block, verbose=True): + block_type = "HYPERRAM" + pads = block["pads"] + name = block["name"] + location = block["location"] + ctl_clk = block["ctl_clk"].name_override + cal_clk = block["cal_clk"].name_override + clk90_clk = block["clk90_clk"].name_override + + cmd = [] + cmd.append('design.create_block("{}", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "CK_N_HI_PIN", "{}", "{}")'.format(name, pads.clkn_h.name, block_type)) + cmd.append('design.set_property("{}", "CK_N_LO_PIN", "{}", "{}")'.format(name, pads.clkn_l.name, block_type)) + cmd.append('design.set_property("{}", "CK_P_HI_PIN", "{}", "{}")'.format(name, pads.clkp_h.name, block_type)) + cmd.append('design.set_property("{}", "CK_P_LO_PIN", "{}", "{}")'.format(name, pads.clkp_l.name, block_type)) + cmd.append('design.set_property("{}", "CLK90_PIN", "{}", "{}")'.format(name, clk90_clk, block_type)) + cmd.append('design.set_property("{}", "CLKCAL_PIN", "{}", "{}")'.format(name, cal_clk, block_type)) + cmd.append('design.set_property("{}", "CLK_PIN", "{}", "{}")'.format(name, ctl_clk, block_type)) + cmd.append('design.set_property("{}", "CS_N_PIN", "{}", "{}")'.format(name, pads.csn.name, block_type)) + cmd.append('design.set_property("{}", "DQ_IN_HI_PIN", "{}", "{}")'.format(name, pads.dq_i_h.name, block_type)) + cmd.append('design.set_property("{}", "DQ_IN_LO_PIN", "{}", "{}")'.format(name, pads.dq_i_l.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OE_PIN", "{}", "{}")'.format(name, pads.dq_oe.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OUT_HI_PIN", "{}", "{}")'.format(name, pads.dq_o_h.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OUT_LO_PIN", "{}", "{}")'.format(name, pads.dq_o_l.name, block_type)) + cmd.append('design.set_property("{}", "RST_N_PIN", "{}", "{}")'.format(name, pads.rstn.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_IN_HI_PIN", "{}", "{}")'.format(name, pads.rwds_i_h.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_IN_LO_PIN", "{}", "{}")'.format(name, pads.rwds_i_l.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_OE_PIN", "{}", "{}")'.format(name, pads.rwds_oe.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_OUT_HI_PIN", "{}", "{}")'.format(name, pads.rwds_o_h.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_OUT_LO_PIN", "{}", "{}")'.format(name, pads.rwds_o_l.name, block_type)) + + cmd.append('design.assign_resource("{}", "{}", "{}")\n'.format(name, location, block_type)) + + return '\n'.join(cmd) + '\n' + def generate(self, partnumber): output = "" for block in self.blocks: @@ -463,6 +498,8 @@ def generate(self, partnumber): output += self.generate_mipi_rx(block) if block["type"] == "LVDS": output += self.generate_lvds(block) + if block["type"] == "HYPERRAM": + output += self.generate_hyperram(block) if block["type"] == "JTAG": output += self.generate_jtag(block) return output diff --git a/litex/soc/cores/ram/efinix_hyperram.py b/litex/soc/cores/ram/efinix_hyperram.py new file mode 100644 index 000000000..509b8bcea --- /dev/null +++ b/litex/soc/cores/ram/efinix_hyperram.py @@ -0,0 +1,138 @@ +# +# This file is part of LiteHyperBus +# +# Copyright (c) 2023 Gwenhael Goavec-Merou +# SPDX-License-Identifier: BSD-2-Clause + +from migen import * + +from litex.build.generic_platform import * + +from litex.gen import * +from litex.gen.genlib.misc import WaitTimer + +from litex.build.io import DifferentialOutput + +from litex.soc.interconnect import wishbone + +from litex.soc.cores.clock.efinix import TITANIUMPLL + +from litex.soc.cores.hyperbus import HyperRAM + +# HyperRAM (efinix F100) --------------------------------------------------------------------------- + +class EfinixHyperRAM(HyperRAM): + """ HyperRAM wrapper for efinix F100 (internal) + """ + def __init__(self, platform, latency=6, clock_domain="sys", sys_clk_freq=None): + + # # # + + assert sys_clk_freq is not None and sys_clk_freq * 2 < 250e6 + + _io = [ + ("hyperram", 0, + Subsignal("clkp_h", 0, Pins(1)), + Subsignal("clkp_l", 0, Pins(1)), + Subsignal("clkn_h", 0, Pins(1)), + Subsignal("clkn_l", 0, Pins(1)), + Subsignal("dq_o_h", 0, Pins(16)), + Subsignal("dq_o_l", 0, Pins(16)), + Subsignal("dq_i_h", 0, Pins(16)), + Subsignal("dq_i_l", 0, Pins(16)), + Subsignal("dq_oe", 0, Pins(16)), + Subsignal("rwds_o_h", 0, Pins(2)), + Subsignal("rwds_o_l", 0, Pins(2)), + Subsignal("rwds_i_h", 0, Pins(2)), + Subsignal("rwds_i_l", 0, Pins(2)), + Subsignal("rwds_oe", 0, Pins(2)), + Subsignal("csn", 0, Pins(1)), + Subsignal("rstn", 0, Pins(1)), + )] + + # PLL dyn phase shift + + platform.add_extension([ + ("shift_ena", 0, Pins(1)), + ("shift_sel", 0, Pins(1)), + ("shift", 0, Pins(1)), + ]) + + _dps_pads = { + "shift_ena" : platform.request("shift_ena"), + "shift_sel" : platform.request("shift_sel"), + "shift" : platform.request("shift"), + } + platform.toolchain.excluded_ios.append(_dps_pads["shift_ena"]) + platform.toolchain.excluded_ios.append(_dps_pads["shift_sel"]) + platform.toolchain.excluded_ios.append(_dps_pads["shift"]) + + # PLL. + self.pll = pll = TITANIUMPLL(platform, dyn_phase_shift_pads=_dps_pads) + pll.register_clkin(ClockDomain(clock_domain).clk, sys_clk_freq, clock_domain) + pll.create_clkout(None, sys_clk_freq) + pll.create_clkout(None, sys_clk_freq*2, name="hp_clk", with_reset=True) + pll.create_clkout(None, sys_clk_freq*2, phase=90, name="hp90_clk", with_reset=True) + pll.create_clkout(None, sys_clk_freq*2, name="hpcal_clk", with_reset=True, dyn_phase=True) + + + # connect HyperRAM to interface designer block + class HPPads: + def __init__(self): + self.dq = TSTriple(16) + self.rwds = TSTriple(2) + self.cs_n = Signal(1) + self.rst_n = Signal(1) + self.clk = Signal(1) + + _hp_pads = HPPads() + platform.add_extension(_io) + self.io_pads = _io_pads = platform.request("hyperram") + + self.comb += [ + _io_pads.clkp_l.eq(_hp_pads.clk), + _io_pads.clkp_h.eq(_hp_pads.clk), + _io_pads.clkn_l.eq(~_hp_pads.clk), + _io_pads.clkn_h.eq(~_hp_pads.clk), + _io_pads.dq_o_h.eq(_hp_pads.dq.o), + _io_pads.dq_o_l.eq(_hp_pads.dq.o), + _hp_pads.dq.i.eq(_io_pads.dq_i_h | _io_pads.dq_i_l), + _io_pads.dq_oe.eq(Replicate(_hp_pads.dq.oe[0], 16)), + _io_pads.rwds_o_h.eq(_hp_pads.rwds.o), + _io_pads.rwds_o_l.eq(_hp_pads.rwds.o), + _hp_pads.rwds.i.eq(_io_pads.rwds_i_h | _io_pads.rwds_i_l), + _io_pads.rwds_oe.eq(Replicate(_hp_pads.rwds.oe[0], 2)), + _io_pads.csn.eq(_hp_pads.cs_n), + _io_pads.rstn.eq(_hp_pads.rst_n), + ] + + block = { + "type" : "HYPERRAM", + "name" : "hp_inst", + "location" : "HYPER_RAM0", + "pads" : _io_pads, + "ctl_clk" : ClockDomain("hp").clk, + "cal_clk" : ClockDomain("hpcal").clk, + "clk90_clk" : ClockDomain("hp90").clk, + } + + platform.toolchain.ifacewriter.blocks.append(block) + + platform.toolchain.excluded_ios.append(_io_pads.clkp_h) + platform.toolchain.excluded_ios.append(_io_pads.clkp_l) + platform.toolchain.excluded_ios.append(_io_pads.clkn_h) + platform.toolchain.excluded_ios.append(_io_pads.clkn_l) + platform.toolchain.excluded_ios.append(_io_pads.dq_o_h) + platform.toolchain.excluded_ios.append(_io_pads.dq_o_l) + platform.toolchain.excluded_ios.append(_io_pads.dq_i_h) + platform.toolchain.excluded_ios.append(_io_pads.dq_i_l) + platform.toolchain.excluded_ios.append(_io_pads.dq_oe) + platform.toolchain.excluded_ios.append(_io_pads.rwds_o_h) + platform.toolchain.excluded_ios.append(_io_pads.rwds_o_l) + platform.toolchain.excluded_ios.append(_io_pads.rwds_i_l) + platform.toolchain.excluded_ios.append(_io_pads.rwds_i_h) + platform.toolchain.excluded_ios.append(_io_pads.rwds_oe) + platform.toolchain.excluded_ios.append(_io_pads.csn) + platform.toolchain.excluded_ios.append(_io_pads.rstn) + + HyperRAM.__init__(self, _hp_pads, latency, sys_clk_freq) From aad83112601fca30e28e9dac212687c29b9c76fb Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 17 Oct 2023 17:37:13 +0200 Subject: [PATCH 244/454] soc/cores/jtag: adding Efinix JTAG support in JTAGPHY --- litex/soc/cores/jtag.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/litex/soc/cores/jtag.py b/litex/soc/cores/jtag.py index e1305d3c2..eff9144a8 100644 --- a/litex/soc/cores/jtag.py +++ b/litex/soc/cores/jtag.py @@ -426,6 +426,9 @@ def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys", cha # Lattice. elif device[:5] == "LFE5U": jtag = ECP5JTAG() + # Efinix + elif device[:2] == "Ti": + jtag = EfinixJTAG(platform) # Altera/Intel. elif AlteraJTAG.get_primitive(device) is not None: platform.add_reserved_jtag_decls() @@ -511,6 +514,16 @@ def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys", cha class EfinixJTAG(LiteXModule): # id refer to the JTAG_USER{id} def __init__(self, platform, id=1): + self.reset = Signal() + self.capture = Signal() + self.shift = Signal() + self.update = Signal() + + self.tck = Signal() + self.tms = Signal() + self.tdi = Signal() + self.tdo = Signal() + self.name = f"jtag_{id}" self.platform = platform self.id = id @@ -543,6 +556,18 @@ def __init__(self, platform, id=1): block["pins"] = pins self.platform.toolchain.ifacewriter.blocks.append(block) + self.comb += [ + self.reset.eq(pins.RESET), + self.capture.eq(pins.CAPTURE), + self.shift.eq(pins.SHIFT), + self.update.eq(pins.UPDATE), + + self.tck.eq(pins.TCK), + self.tms.eq(pins.TMS), + self.tdi.eq(pins.TDI), + pins.TDO.eq(self.tdo), + ] + def bind_vexriscv_smp(self, cpu): self.comb += [ # JTAG -> CPU. From 7e6418900abcf693d27cea7d508610195eb3f114 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 17 Oct 2023 17:37:34 +0200 Subject: [PATCH 245/454] build/openocd: adding Efinix Titanium support --- litex/build/openocd.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/litex/build/openocd.py b/litex/build/openocd.py index 0a2c8004d..76a709644 100644 --- a/litex/build/openocd.py +++ b/litex/build/openocd.py @@ -56,6 +56,11 @@ def get_ir(self, chain, config): 3: 0x922, # USER3. 4: 0x923, # USER4. }[chain] + # Efinix titanium + elif "titanium" in cfg_str: + chain = { + 1: 0x08, + }[chain] # Xilinx 7-Series. else: chain = { From 6636560c41c91ab49734dfa795b6ddfeca369cd1 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Wed, 13 Jul 2022 11:12:20 +0200 Subject: [PATCH 246/454] cores/clocks/lattice_ecp5: Fix phase calculation to match Diamond output --- litex/soc/cores/clock/lattice_ecp5.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/clock/lattice_ecp5.py b/litex/soc/cores/clock/lattice_ecp5.py index ea69b945f..aead77333 100644 --- a/litex/soc/cores/clock/lattice_ecp5.py +++ b/litex/soc/cores/clock/lattice_ecp5.py @@ -159,11 +159,11 @@ def do_finalize(self): self.comb += self.locked.eq(locked & ~self.reset) for n, (clk, f, p, m, dpa) in sorted(self.clkouts.items()): div = config[f"clko{n}_div"] - cphase = int(p*(div + 1)/360 + div - 1) + phase = round(p*div/45) self.params[f"p_CLKO{n_to_l[n]}_ENABLE"] = "ENABLED" self.params[f"p_CLKO{n_to_l[n]}_DIV"] = div - self.params[f"p_CLKO{n_to_l[n]}_FPHASE"] = 0 - self.params[f"p_CLKO{n_to_l[n]}_CPHASE"] = cphase + self.params[f"p_CLKO{n_to_l[n]}_FPHASE"] = phase & 7 + self.params[f"p_CLKO{n_to_l[n]}_CPHASE"] = (phase >> 3) + (div - 1) self.params[f"o_CLKO{n_to_l[n]}"] = clk if f > 0: # i.e. not a feedback-only clock self.params["attr"].append((f"FREQUENCY_PIN_CLKO{n_to_l[n]}", str(f/1e6))) From a833193cd3eb6c24190256f203ca4c9868366771 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Mon, 23 Oct 2023 11:38:31 +0700 Subject: [PATCH 247/454] Xilinx: Initial openxc7 toolchain support --- litex/build/xilinx/openxc7.py | 146 ++++++++++++++++++++++++++++ litex/build/xilinx/platform.py | 5 +- litex/build/xilinx/yosys_nextpnr.py | 19 ++-- 3 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 litex/build/xilinx/openxc7.py diff --git a/litex/build/xilinx/openxc7.py b/litex/build/xilinx/openxc7.py new file mode 100644 index 000000000..33bd242f6 --- /dev/null +++ b/litex/build/xilinx/openxc7.py @@ -0,0 +1,146 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2020 Antmicro +# Copyright (c) 2020 Florent Kermarrec +# Copyright (c) 2022 Victor Suarez Rovere +# Copyright (c) 2023 Hans Baier +# SPDX-License-Identifier: BSD-2-Clause + +import os +import subprocess +import sys +import math +from typing import NamedTuple, Union, List +import re +from shutil import which + +from migen.fhdl.structure import _Fragment, wrap, Constant +from migen.fhdl.specials import Instance + +from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain +from litex.build.generic_platform import * +from litex.build.xilinx.vivado import _xdc_separator, _format_xdc, _build_xdc +from litex.build import tools +from litex.build.xilinx import common + + +def _unwrap(value): + return value.value if isinstance(value, Constant) else value + + +# XilinxOpenXC7Toolchain ---------------------------------------------------------------------------- + +class XilinxOpenXC7Toolchain(YosysNextPNRToolchain): + attr_translate = {} + + synth_fmt = "json" + constr_fmt = "xdc" + pnr_fmt = "fasm" + packer_cmd = "xc7frames2bit" + + def __init__(self): + super().__init__() + self.dbpart = None + self.family = "xilinx" + self._xc7family = None + self._clock_constraints = "" + self.additional_xdc_commands = [] + self._pre_packer_cmd = ["fasm2frames"] + self._synth_opts = "-flatten -abc9 -arch xc7 " + + xc7_family_map = { + "a": "artix7", + "k": "kintex7", + "s": "spartan7", + "z": "zynq7" + } + + def _check_properties(self): + pattern = re.compile("xc7([aksz])([0-9]+)(.*)-([0-9])") + g = pattern.search(self.platform.device) + if not self.dbpart: + self.dbpart = f"xc7{g.group(1)}{g.group(2)}{g.group(3)}" + + if not self._xc7family: + fam = g.group(1) + self._xc7family = self.xc7_family_map[fam] + + def build_timing_constraints(self, vns): + xdc = [] + xdc.append(_xdc_separator("Clock constraints")) + + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig + xdc.append( + "create_clock -name {name} -period " + str(period) + + " [get_ports {clk}]".format(name=name, clk=clk_sig)) + + # generate sdc + xdc += self.additional_xdc_commands + self._clock_constraints = "\n".join(xdc) + + def build_io_constraints(self): + tools.write_to_file(self._build_name + ".xdc", _build_xdc(self.named_sc, self.named_pc) + self._clock_constraints) + return (self._build_name + ".xdc", "XDC") + + def _fix_instance(self, instance): + pass + + def finalize(self): + # toolchain-specific fixes + for instance in self.fragment.specials: + if isinstance(instance, Instance): + self._fix_instance(instance) + + chipdb_dir = os.environ.get('CHIPDB') + if chipdb_dir is None or chipdb_dir == "": + print("Error: please specify the directory, where you store your nextpnr-xilinx chipdb files in the environment variable CHIPDB (may be empty)") + exit(1) + + # pnr options + self._pnr_opts += "--chipdb {chipdb_dir}/{dbpart}.bin --write {top}_routed.json".format( + top = self._build_name, + chipdb_dir = chipdb_dir, + dbpart = self.dbpart, + ) + + prjxray_db_dir = os.environ.get('PRJXRAY_DB_DIR') + if prjxray_db_dir is None or prjxray_db_dir == "": + prjxray_db_dir = '/snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/' + + if not os.path.isdir(prjxray_db_dir): + print(f"{prjxray_db_dir} does not exist on your system. \n" + \ + "Do you have the openXC7 toolchain installed? \n" + \ + "You can get it here: https://github.com/openXC7/toolchain-installer") + exit(1) + + # pre packer options + self._pre_packer_opts["fasm2frames"] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( + part = self.platform.device, + db_root = os.path.join(prjxray_db_dir, self._xc7family), + top = self._build_name + ) + # packer options + self._packer_opts += "--part_file {db_dir}/{part}/part.yaml --part_name {part} --frm_file {top}.frames --output_file {top}.bit".format( + db_dir = os.path.join(prjxray_db_dir, self._xc7family), + part = self.platform.device, + top = self._build_name + ) + + return YosysNextPNRToolchain.finalize(self) + + def build(self, platform, fragment, + enable_xpm = False, + **kwargs): + + self.platform = platform + self._check_properties() + + return YosysNextPNRToolchain.build(self, platform, fragment, **kwargs) + + def add_false_path_constraint(self, platform, from_, to): + # FIXME: false path constraints are currently not supported by the openXC7 toolchain + return diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index cfe1b2f94..3fec9e17c 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -21,7 +21,7 @@ class XilinxPlatform(GenericPlatform): _supported_toolchains = { "spartan6" : ["ise"], - "7series" : ["vivado", "f4pga", "yosys+nextpnr"], + "7series" : ["vivado", "f4pga", "yosys+nextpnr", "openxc7"], "ultrascale" : ["vivado"], "ultrascale+" : ["vivado"], } @@ -42,6 +42,9 @@ def __init__(self, *args, toolchain="ise", **kwargs): elif toolchain == "yosys+nextpnr": from litex.build.xilinx import yosys_nextpnr self.toolchain = yosys_nextpnr.XilinxYosysNextpnrToolchain() + elif toolchain == "openxc7": + from litex.build.xilinx import openxc7 + self.toolchain = openxc7.XilinxOpenXC7Toolchain() else: raise ValueError(f"Unknown toolchain {toolchain}") diff --git a/litex/build/xilinx/yosys_nextpnr.py b/litex/build/xilinx/yosys_nextpnr.py index 264fc3d11..b8ba75e42 100644 --- a/litex/build/xilinx/yosys_nextpnr.py +++ b/litex/build/xilinx/yosys_nextpnr.py @@ -45,7 +45,7 @@ def __init__(self): self.bitstream_device = None self._partname = None self._pre_packer_cmd = ["fasm2frames.py"] - self._synth_opts = "-flatten -abc9 -nobram -arch xc7 " + self._synth_opts = "-flatten -abc9 -arch xc7 " def _check_properties(self): if not self.f4pga_device: @@ -64,12 +64,14 @@ def _check_properties(self): # bitstream_device points to a directory in prjxray database # available bitstream_devices: artix7, kintex7, zynq7 self.bitstream_device = { - "xc7a": "artix7", # xc7a35t, xc7a50t, xc7a100t, xc7a200t - "xc7z": "zynq7", # xc7z010, xc7z020 + "xc7s": "spartan7", + "xc7a": "artix7", + "xc7k": "kintex7", + "xc7z": "zynq7", }[self.platform.device[:4]] except KeyError: raise ValueError(f"Unsupported device: {self.platform.device}") - # FIXME: prjxray-db doesn't have xc7a35ticsg324-1L - use closest replacement + self._partname = { "xc7a35ticsg324-1L" : "xc7a35tcsg324-1", "xc7a100tcsg324-1" : "xc7a100tcsg324-1", @@ -132,12 +134,5 @@ def build(self, platform, fragment, return YosysNextPNRToolchain.build(self, platform, fragment, **kwargs) def add_false_path_constraint(self, platform, from_, to): - # FIXME: false path constraints are currently not supported by the F4PGA toolchain + # FIXME: false path constraints are currently not supported by nextpnr-xilinx return - -def f4pga_build_args(parser): - pass - - -def f4pga_build_argdict(args): - return dict() From 745e584c60ab861459f8ddc33598a47d88f49b2e Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 19 Oct 2023 17:52:07 +0200 Subject: [PATCH 248/454] soc/integration/soc_core: add new parameters --with-uartbone and --with-jtagbone, deprecate crossover+uartbone - `--with-jtagbone` and `--with-uartbone` are now integrated in SoCCore arguments. This class also handle `add_jtagbone` and `add_uartbone` - when a target try to add one of this option a warning is displayed and insertion is bypassed - `crossover+uartbone` is deprecated -> `--uart-name=crossover --with-uartbone` - jtag capability ((un)supported) is now handled at platform level --- litex/build/anlogic/platform.py | 3 +- litex/build/colognechip/platform.py | 1 + litex/build/generic_platform.py | 11 +++++++ litex/build/gowin/platform.py | 1 + litex/build/microsemi/platform.py | 1 + litex/build/parser.py | 28 ++++++++++++++++- litex/build/quicklogic/platform.py | 1 + litex/build/xilinx/platform.py | 7 +++++ litex/soc/integration/soc_core.py | 47 +++++++++++++++++++++++++++++ 9 files changed, 98 insertions(+), 2 deletions(-) diff --git a/litex/build/anlogic/platform.py b/litex/build/anlogic/platform.py index 334c75297..b66f002b7 100644 --- a/litex/build/anlogic/platform.py +++ b/litex/build/anlogic/platform.py @@ -13,7 +13,8 @@ # AnlogicPlatform ---------------------------------------------------------------------------------- class AnlogicPlatform(GenericPlatform): - _bitstream_ext = ".bit" + _bitstream_ext = ".bit" + _jtag_support = False _supported_toolchains = ["td"] diff --git a/litex/build/colognechip/platform.py b/litex/build/colognechip/platform.py index 127c4e2fb..78f6ed6e8 100644 --- a/litex/build/colognechip/platform.py +++ b/litex/build/colognechip/platform.py @@ -13,6 +13,7 @@ class CologneChipPlatform(GenericPlatform): bitstream_ext = "_00.cfg.bit" + _jtag_support = False _supported_toolchains = ["colognechip"] diff --git a/litex/build/generic_platform.py b/litex/build/generic_platform.py index a9a24eeaa..933dd567d 100644 --- a/litex/build/generic_platform.py +++ b/litex/build/generic_platform.py @@ -329,6 +329,7 @@ def get_platform_commands(self): class GenericPlatform: device_family = None + _jtag_support = True # JTAGBone can't be used with all FPGAs. _bitstream_ext = None # None by default, overridden by vendor platform, may # be a string when same extension is used for sram and # flash. A dict must be provided otherwise @@ -504,6 +505,16 @@ def get_bitstream_extension(self, mode="sram"): def create_programmer(self): raise NotImplementedError + @property + def jtag_support(self): + if isinstance(self._jtag_support, str): + return self._jtag_support + else: + for dev in self._jtag_support: + if self.device.startswith(dev): + return True + return False + @property def support_mixed_language(self): return self.toolchain.support_mixed_language diff --git a/litex/build/gowin/platform.py b/litex/build/gowin/platform.py index 1e7fb419c..b694c2cc3 100644 --- a/litex/build/gowin/platform.py +++ b/litex/build/gowin/platform.py @@ -14,6 +14,7 @@ class GowinPlatform(GenericPlatform): _bitstream_ext = ".fs" + _jtag_support = False _supported_toolchains = ["gowin", "apicula"] diff --git a/litex/build/microsemi/platform.py b/litex/build/microsemi/platform.py index 9be106e04..71c344d65 100644 --- a/litex/build/microsemi/platform.py +++ b/litex/build/microsemi/platform.py @@ -11,6 +11,7 @@ class MicrosemiPlatform(GenericPlatform): _bitstream_ext = ".bit" + _jtag_support = False _supported_toolchains = ["libero_soc_polarfire"] diff --git a/litex/build/parser.py b/litex/build/parser.py index 827524bab..ca46efe94 100644 --- a/litex/build/parser.py +++ b/litex/build/parser.py @@ -9,11 +9,14 @@ import logging import argparse import importlib +import time from litex.soc.cores import cpu from litex.soc.integration import soc_core from litex.soc.integration import builder +from litex.gen.common import * + # Litex Argument Parser ---------------------------------------------------------------------------- class LiteXArgumentParser(argparse.ArgumentParser): @@ -63,6 +66,9 @@ def __init__(self, platform=None, **kwargs): self.set_platform(platform) self.add_target_group() self.add_logging_group() + # workaround for backward compatibility + self._rm_jtagbone = False + self._rm_uartbone = False def set_platform(self, platform): """ set platform. Check first if not already set @@ -104,8 +110,21 @@ def add_target_argument(self, *args, **kwargs): """ wrapper to add argument to "Target options group" from outer of this class """ + arg = args[0] + if arg in ["--with-jtagbone", "--with-uartbone"]: + if arg == "--with-jtagbone": + self._rm_jtagbone = True + else: + self._rm_uartbone = True + print("Warning {} {} {}".format( + colorer(arg, color="red"), + colorer(" is added by SoCCore. ", color="red"), + colorer("Please remove this option from target", color="yellow"))) + time.sleep(2) + return # bypass insert if self._target_group is None: self._target_group = self.add_argument_group(title="Target options") + self._target_group.add_argument(*args, **kwargs) def add_logging_group(self): @@ -147,7 +166,14 @@ def soc_argdict(self): ====== soc_core arguments dict """ - return soc_core.soc_core_argdict(self._args) # FIXME: Rename to soc_argdict in the future. + soc_arg = soc_core.soc_core_argdict(self._args) # FIXME: Rename to soc_argdict in the future. + + # Work around for backward compatibility + if self._rm_jtagbone: + soc_arg.pop("with_jtagbone") + if self._rm_uartbone: + soc_arg.pop("with_uartbone") + return soc_arg @property def toolchain_argdict(self): diff --git a/litex/build/quicklogic/platform.py b/litex/build/quicklogic/platform.py index ce099aac1..193f45262 100644 --- a/litex/build/quicklogic/platform.py +++ b/litex/build/quicklogic/platform.py @@ -13,6 +13,7 @@ class QuickLogicPlatform(GenericPlatform): _bitstream_ext = ".bit" + _jtag_support = False _supported_toolchains = ["f4pga"] diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index cfe1b2f94..810b8759c 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -26,6 +26,12 @@ class XilinxPlatform(GenericPlatform): "ultrascale+" : ["vivado"], } + _jtag_support = [ + "xc6", + "xc7a", "xc7k", "xc7v", "xc7z", + "xcau", "xcku", "xcvu", "xczu" + ] + def __init__(self, *args, toolchain="ise", **kwargs): GenericPlatform.__init__(self, *args, **kwargs) self.edifs = set() @@ -126,6 +132,7 @@ def get_argdict(cls, toolchain, args): else: return dict() + # XilinxSpartan6Platform --------------------------------------------------------------------------- class XilinxSpartan6Platform(XilinxPlatform): diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index c0eb5942d..4a9b5e10e 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -108,6 +108,13 @@ def __init__(self, platform, clk_freq, # Controller parameters with_ctrl = True, + # JTAGBone + with_jtagbone = False, + jtagbone_chain = 1, + + # UARTBone + with_uartbone = False, + # Others **kwargs): @@ -174,6 +181,31 @@ def __init__(self, platform, clk_freq, # Wishbone Slaves. self.wb_slaves = {} + # Parameters check validity ---------------------------------------------------------------- + + # Check if jtagbone is supported (SPI only device or no user access). + if with_jtagbone: + if not platform.jtag_support: + self.logger.error("{} {} with {} FPGA".format( + colorer("JTAGBone isn't supported for platform", color="red"), + platform.name, platform.device)) + raise SoCError() + if with_uart: + # crossover+uartbone is kept as backward compatibility + if uart_name == "crossover+uartbone": + self.logger.warning("{} UART: is deprecated {}".format( + colorer(uart_name, color="yellow"), + colorer("please use --uart-name=\"crossover\" --with-uartbone", color="red"))) + time.sleep(2) + # Already configured. + self._uartbone = True + uart_name = "crossover" + + # JTAGBone and jtag_uart can't be used at the same time. + assert not (with_jtagbone and uart_name == "jtag_uart") + # UARTBone and serial can't be used at the same time. + assert not (with_uartbone and uart_name == "serial") + # Modules instances ------------------------------------------------------------------------ # Add SoCController @@ -220,10 +252,18 @@ def __init__(self, platform, clk_freq, if ident != "": self.add_identifier("identifier", identifier=ident, with_build_time=ident_version) + # Add UARTBone + if with_uartbone: + self.add_uartbone(baudrate=uart_baudrate) + # Add UART if with_uart: self.add_uart(name="uart", uart_name=uart_name, baudrate=uart_baudrate, fifo_depth=uart_fifo_depth) + # Add JTAGBone + if with_jtagbone: + self.add_jtagbone(chain=jtagbone_chain) + # Add Timer if with_timer: self.add_timer(name="timer0") @@ -294,6 +334,13 @@ def soc_core_args(parser): soc_group.add_argument("--uart-baudrate", default=115200, type=auto_int, help="UART baudrate.") soc_group.add_argument("--uart-fifo-depth", default=16, type=auto_int, help="UART FIFO depth.") + # UARTBone parameters + soc_group.add_argument("--with-uartbone", action="store_true", help="Enable UARTbone.") + + # JTAGBone parameters + soc_group.add_argument("--with-jtagbone", action="store_true", help="Enable Jtagbone support.") + soc_group.add_argument("--jtagbone-chain", default=1, type=int, help="Jtagbone chain index.") + # Timer parameters soc_group.add_argument("--no-timer", action="store_true", help="Disable Timer.") soc_group.add_argument("--timer-uptime", action="store_true", help="Add an uptime capability to Timer.") From 86cf24023d1cf92739d1c3b1ea38607317b07f00 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 23 Oct 2023 16:41:03 +0200 Subject: [PATCH 249/454] soc/build: Minimize changes added by #1809 and review. --- litex/build/parser.py | 22 +++++++--------------- litex/soc/integration/soc.py | 9 +++++++++ litex/soc/integration/soc_core.py | 15 +++++---------- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/litex/build/parser.py b/litex/build/parser.py index ca46efe94..31c15308e 100644 --- a/litex/build/parser.py +++ b/litex/build/parser.py @@ -9,7 +9,6 @@ import logging import argparse import importlib -import time from litex.soc.cores import cpu from litex.soc.integration import soc_core @@ -66,9 +65,6 @@ def __init__(self, platform=None, **kwargs): self.set_platform(platform) self.add_target_group() self.add_logging_group() - # workaround for backward compatibility - self._rm_jtagbone = False - self._rm_uartbone = False def set_platform(self, platform): """ set platform. Check first if not already set @@ -110,17 +106,13 @@ def add_target_argument(self, *args, **kwargs): """ wrapper to add argument to "Target options group" from outer of this class """ - arg = args[0] - if arg in ["--with-jtagbone", "--with-uartbone"]: - if arg == "--with-jtagbone": + if args[0] in ["--with-jtagbone", "--with-uartbone"]: + if args[0] == "--with-jtagbone": self._rm_jtagbone = True - else: + if args[0] == "--with-uartbone": self._rm_uartbone = True - print("Warning {} {} {}".format( - colorer(arg, color="red"), - colorer(" is added by SoCCore. ", color="red"), - colorer("Please remove this option from target", color="yellow"))) - time.sleep(2) + from litex.compat import compat_notice + compat_notice(f"Adding {args[0]} in target", date="2023-10-23", info=f"{args[0]} is now directly added by SoCCore, please remove from target.") return # bypass insert if self._target_group is None: self._target_group = self.add_argument_group(title="Target options") @@ -169,9 +161,9 @@ def soc_argdict(self): soc_arg = soc_core.soc_core_argdict(self._args) # FIXME: Rename to soc_argdict in the future. # Work around for backward compatibility - if self._rm_jtagbone: + if getattr(self, "_rm_jtagbone", False): soc_arg.pop("with_jtagbone") - if self._rm_uartbone: + if getattr(self, "_rm_uartbone", False): soc_arg.pop("with_uartbone") return soc_arg diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 2ed96f46b..668d2a9ca 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1460,6 +1460,15 @@ def add_jtagbone(self, name="jtagbone", chain=1): from litex.soc.cores import uart from litex.soc.cores.jtag import JTAGPHY + # Check if JTAGBone is supported (SPI only device or no user access). + if not self.platform.jtag_support: + self.logger.error("{} {} on {} device.".format( + colorer("JTAGBone"), + colorer("not supported", color="red"), + colorer(self.platform.device) + )) + raise SoCError() + # Core. self.check_if_exists(name) jtagbone_phy = JTAGPHY(device=self.platform.device, chain=chain, platform=self.platform) diff --git a/litex/soc/integration/soc_core.py b/litex/soc/integration/soc_core.py index 4a9b5e10e..28611d197 100644 --- a/litex/soc/integration/soc_core.py +++ b/litex/soc/integration/soc_core.py @@ -183,15 +183,10 @@ def __init__(self, platform, clk_freq, # Parameters check validity ---------------------------------------------------------------- - # Check if jtagbone is supported (SPI only device or no user access). - if with_jtagbone: - if not platform.jtag_support: - self.logger.error("{} {} with {} FPGA".format( - colorer("JTAGBone isn't supported for platform", color="red"), - platform.name, platform.device)) - raise SoCError() + # FIXME: Move to soc.py? + if with_uart: - # crossover+uartbone is kept as backward compatibility + # crossover+uartbone is kept as backward compatibility if uart_name == "crossover+uartbone": self.logger.warning("{} UART: is deprecated {}".format( colorer(uart_name, color="yellow"), @@ -201,9 +196,9 @@ def __init__(self, platform, clk_freq, self._uartbone = True uart_name = "crossover" - # JTAGBone and jtag_uart can't be used at the same time. + # JTAGBone and jtag_uart can't be used at the same time. assert not (with_jtagbone and uart_name == "jtag_uart") - # UARTBone and serial can't be used at the same time. + # UARTBone and serial can't be used at the same time. assert not (with_uartbone and uart_name == "serial") # Modules instances ------------------------------------------------------------------------ From 5a217528a46e301b7354695bfdefee6b5c8ad574 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 23 Oct 2023 17:29:12 +0200 Subject: [PATCH 250/454] build/generic_platform: Fix jtag_support typo. --- litex/build/generic_platform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/generic_platform.py b/litex/build/generic_platform.py index 933dd567d..847435c81 100644 --- a/litex/build/generic_platform.py +++ b/litex/build/generic_platform.py @@ -507,7 +507,7 @@ def create_programmer(self): @property def jtag_support(self): - if isinstance(self._jtag_support, str): + if isinstance(self._jtag_support, bool): return self._jtag_support else: for dev in self._jtag_support: From bf3286f564d92b03925f68d3757f182257e75131 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 23 Oct 2023 18:31:29 +0200 Subject: [PATCH 251/454] soc/integration/soc: expose interface and endianness to target (required for hybrid etherbone) --- litex/soc/integration/soc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 668d2a9ca..11c75cb8d 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1732,7 +1732,9 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, udp_port = 1234, buffer_depth = 16, with_ip_broadcast = True, - with_timing_constraints = True): + with_timing_constraints = True, + interface = "crossbar", + endianness = "big"): # Imports from liteeth.core import LiteEthUDPIPCore from liteeth.frontend.etherbone import LiteEthEtherbone @@ -1751,6 +1753,8 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, dw = data_width, with_ip_broadcast = with_ip_broadcast, with_sys_datapath = with_sys_datapath, + interface = interface, + endianness = endianness, ) if not with_sys_datapath: # Use PHY's eth_tx/eth_rx clock domains. From 468375b119711e601fcfe1324b48fa9c34db7a7f Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 24 Oct 2023 08:39:01 +0700 Subject: [PATCH 252/454] xilinx platform: add more ignored constraints for yosys+nextpnr --- litex/build/xilinx/openxc7.py | 146 ---------------------------- litex/build/xilinx/platform.py | 13 ++- litex/build/xilinx/yosys_nextpnr.py | 122 +++++++++++++---------- 3 files changed, 77 insertions(+), 204 deletions(-) delete mode 100644 litex/build/xilinx/openxc7.py diff --git a/litex/build/xilinx/openxc7.py b/litex/build/xilinx/openxc7.py deleted file mode 100644 index 33bd242f6..000000000 --- a/litex/build/xilinx/openxc7.py +++ /dev/null @@ -1,146 +0,0 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2020 Antmicro -# Copyright (c) 2020 Florent Kermarrec -# Copyright (c) 2022 Victor Suarez Rovere -# Copyright (c) 2023 Hans Baier -# SPDX-License-Identifier: BSD-2-Clause - -import os -import subprocess -import sys -import math -from typing import NamedTuple, Union, List -import re -from shutil import which - -from migen.fhdl.structure import _Fragment, wrap, Constant -from migen.fhdl.specials import Instance - -from litex.build.yosys_nextpnr_toolchain import YosysNextPNRToolchain -from litex.build.generic_platform import * -from litex.build.xilinx.vivado import _xdc_separator, _format_xdc, _build_xdc -from litex.build import tools -from litex.build.xilinx import common - - -def _unwrap(value): - return value.value if isinstance(value, Constant) else value - - -# XilinxOpenXC7Toolchain ---------------------------------------------------------------------------- - -class XilinxOpenXC7Toolchain(YosysNextPNRToolchain): - attr_translate = {} - - synth_fmt = "json" - constr_fmt = "xdc" - pnr_fmt = "fasm" - packer_cmd = "xc7frames2bit" - - def __init__(self): - super().__init__() - self.dbpart = None - self.family = "xilinx" - self._xc7family = None - self._clock_constraints = "" - self.additional_xdc_commands = [] - self._pre_packer_cmd = ["fasm2frames"] - self._synth_opts = "-flatten -abc9 -arch xc7 " - - xc7_family_map = { - "a": "artix7", - "k": "kintex7", - "s": "spartan7", - "z": "zynq7" - } - - def _check_properties(self): - pattern = re.compile("xc7([aksz])([0-9]+)(.*)-([0-9])") - g = pattern.search(self.platform.device) - if not self.dbpart: - self.dbpart = f"xc7{g.group(1)}{g.group(2)}{g.group(3)}" - - if not self._xc7family: - fam = g.group(1) - self._xc7family = self.xc7_family_map[fam] - - def build_timing_constraints(self, vns): - xdc = [] - xdc.append(_xdc_separator("Clock constraints")) - - for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): - clk_sig = self._vns.get_name(clk) - if name is None: - name = clk_sig - xdc.append( - "create_clock -name {name} -period " + str(period) + - " [get_ports {clk}]".format(name=name, clk=clk_sig)) - - # generate sdc - xdc += self.additional_xdc_commands - self._clock_constraints = "\n".join(xdc) - - def build_io_constraints(self): - tools.write_to_file(self._build_name + ".xdc", _build_xdc(self.named_sc, self.named_pc) + self._clock_constraints) - return (self._build_name + ".xdc", "XDC") - - def _fix_instance(self, instance): - pass - - def finalize(self): - # toolchain-specific fixes - for instance in self.fragment.specials: - if isinstance(instance, Instance): - self._fix_instance(instance) - - chipdb_dir = os.environ.get('CHIPDB') - if chipdb_dir is None or chipdb_dir == "": - print("Error: please specify the directory, where you store your nextpnr-xilinx chipdb files in the environment variable CHIPDB (may be empty)") - exit(1) - - # pnr options - self._pnr_opts += "--chipdb {chipdb_dir}/{dbpart}.bin --write {top}_routed.json".format( - top = self._build_name, - chipdb_dir = chipdb_dir, - dbpart = self.dbpart, - ) - - prjxray_db_dir = os.environ.get('PRJXRAY_DB_DIR') - if prjxray_db_dir is None or prjxray_db_dir == "": - prjxray_db_dir = '/snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/' - - if not os.path.isdir(prjxray_db_dir): - print(f"{prjxray_db_dir} does not exist on your system. \n" + \ - "Do you have the openXC7 toolchain installed? \n" + \ - "You can get it here: https://github.com/openXC7/toolchain-installer") - exit(1) - - # pre packer options - self._pre_packer_opts["fasm2frames"] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( - part = self.platform.device, - db_root = os.path.join(prjxray_db_dir, self._xc7family), - top = self._build_name - ) - # packer options - self._packer_opts += "--part_file {db_dir}/{part}/part.yaml --part_name {part} --frm_file {top}.frames --output_file {top}.bit".format( - db_dir = os.path.join(prjxray_db_dir, self._xc7family), - part = self.platform.device, - top = self._build_name - ) - - return YosysNextPNRToolchain.finalize(self) - - def build(self, platform, fragment, - enable_xpm = False, - **kwargs): - - self.platform = platform - self._check_properties() - - return YosysNextPNRToolchain.build(self, platform, fragment, **kwargs) - - def add_false_path_constraint(self, platform, from_, to): - # FIXME: false path constraints are currently not supported by the openXC7 toolchain - return diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index 3fec9e17c..b188e36dd 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -39,12 +39,9 @@ def __init__(self, *args, toolchain="ise", **kwargs): elif toolchain == "symbiflow" or toolchain == "f4pga": from litex.build.xilinx import f4pga self.toolchain = f4pga.F4PGAToolchain() - elif toolchain == "yosys+nextpnr": + elif toolchain in ["yosys+nextpnr", "openxc7"]: from litex.build.xilinx import yosys_nextpnr - self.toolchain = yosys_nextpnr.XilinxYosysNextpnrToolchain() - elif toolchain == "openxc7": - from litex.build.xilinx import openxc7 - self.toolchain = openxc7.XilinxOpenXC7Toolchain() + self.toolchain = yosys_nextpnr.XilinxYosysNextpnrToolchain(toolchain) else: raise ValueError(f"Unknown toolchain {toolchain}") @@ -62,6 +59,12 @@ def add_platform_command(self, command, **signals): if "set_property INTERNAL_VREF" in command: print("WARNING: INTERNAL_VREF constraint removed since not yet supported by yosys-nextpnr flow.") skip = True + if "set_property CFGBVS" in command: + print("WARNING: CFGBVS constraint removed since not yet supported by yosys-nextpnr flow.") + skip = True + if "set_property CONFIG_VOLTAGE" in command: + print("WARNING: CONFIG_VOLTAGE constraint removed since not yet supported by yosys-nextpnr flow.") + skip = True if not skip: GenericPlatform.add_platform_command(self, command, **signals) diff --git a/litex/build/xilinx/yosys_nextpnr.py b/litex/build/xilinx/yosys_nextpnr.py index b8ba75e42..fde84df37 100644 --- a/litex/build/xilinx/yosys_nextpnr.py +++ b/litex/build/xilinx/yosys_nextpnr.py @@ -4,6 +4,7 @@ # Copyright (c) 2020 Antmicro # Copyright (c) 2020 Florent Kermarrec # Copyright (c) 2022 Victor Suarez Rovere +# Copyright (c) 2023 Hans Baier # SPDX-License-Identifier: BSD-2-Clause import os @@ -39,57 +40,52 @@ class XilinxYosysNextpnrToolchain(YosysNextPNRToolchain): pnr_fmt = "fasm" packer_cmd = "xc7frames2bit" - def __init__(self): + def __init__(self, toolchain): + assert toolchain in ["yosys+nextpnr", "openxc7"] + self.is_openxc7 = toolchain == "openxc7" super().__init__() - self.f4pga_device = None - self.bitstream_device = None - self._partname = None - self._pre_packer_cmd = ["fasm2frames.py"] + self.dbpart = None + self._xc7family = None + self._clock_constraints = "" + self.additional_xdc_commands = [] + self._pre_packer_cmd = ["fasm2frames" if self.is_openxc7 else "fasm2frames.py"] self._synth_opts = "-flatten -abc9 -arch xc7 " + xc7_family_map = { + "a": "artix7", + "k": "kintex7", + "s": "spartan7", + "z": "zynq7" + } + def _check_properties(self): - if not self.f4pga_device: - try: - self.f4pga_device = { - # FIXME: fine for now since only a few devices are supported, do more clever device re-mapping. - "xc7a35ticsg324-1L" : "xc7a35t", - "xc7a100tcsg324-1" : "xc7a100t", - "xc7z010clg400-1" : "xc7z010", - "xc7z020clg400-1" : "xc7z020", - }[self.platform.device] - except KeyError: - raise ValueError(f"f4pga_device is not specified") - if not self.bitstream_device: - try: - # bitstream_device points to a directory in prjxray database - # available bitstream_devices: artix7, kintex7, zynq7 - self.bitstream_device = { - "xc7s": "spartan7", - "xc7a": "artix7", - "xc7k": "kintex7", - "xc7z": "zynq7", - }[self.platform.device[:4]] - except KeyError: - raise ValueError(f"Unsupported device: {self.platform.device}") - - self._partname = { - "xc7a35ticsg324-1L" : "xc7a35tcsg324-1", - "xc7a100tcsg324-1" : "xc7a100tcsg324-1", - "xc7a200t-sbg484-1" : "xc7a200tsbg484-1", - "xc7z010clg400-1" : "xc7z010clg400-1", - "xc7z020clg400-1" : "xc7z020clg400-1", - }.get(self.platform.device, self.platform.device) + pattern = re.compile("xc7([aksz])([0-9]+)(.*)-([0-9])") + g = pattern.search(self.platform.device) + if not self.dbpart: + self.dbpart = f"xc7{g.group(1)}{g.group(2)}{g.group(3)}" + + if not self._xc7family: + fam = g.group(1) + self._xc7family = self.xc7_family_map[fam] def build_timing_constraints(self, vns): - self.platform.add_platform_command(_xdc_separator("Clock constraints")) - #for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): - # platform.add_platform_command( - # "create_clock -period " + str(period) + - # " {clk}", clk=clk) - pass #clock constraints not supported + xdc = [] + xdc.append(_xdc_separator("Clock constraints")) + + for clk, [period, name] in sorted(self.clocks.items(), key=lambda x: x[0].duid): + clk_sig = self._vns.get_name(clk) + if name is None: + name = clk_sig + xdc.append( + "create_clock -name {name} -period " + str(period) + + " [get_ports {clk}]".format(name=name, clk=clk_sig)) + + # generate sdc + xdc += self.additional_xdc_commands + self._clock_constraints = "\n".join(xdc) def build_io_constraints(self): - tools.write_to_file(self._build_name + ".xdc", _build_xdc(self.named_sc, self.named_pc)) + tools.write_to_file(self._build_name + ".xdc", _build_xdc(self.named_sc, self.named_pc) + self._clock_constraints) return (self._build_name + ".xdc", "XDC") def _fix_instance(self, instance): @@ -101,23 +97,44 @@ def finalize(self): if isinstance(instance, Instance): self._fix_instance(instance) + if self.is_openxc7: + chipdb_dir = os.environ.get('CHIPDB') + if chipdb_dir is None or chipdb_dir == "": + print("Error: please specify the directory, where you store your nextpnr-xilinx chipdb files in the environment variable CHIPDB (may be empty)") + exit(1) + else: + chipdb_dir = "/usr/share/nextpnr/xilinx-chipdb" + # pnr options - self._pnr_opts += "--chipdb {chipdb_dir}/{device}.bin --write {top}_routed.json".format( + self._pnr_opts += "--chipdb {chipdb_dir}/{dbpart}.bin --write {top}_routed.json".format( top = self._build_name, - chipdb_dir = "/usr/share/nextpnr/xilinx-chipdb", - device = self.f4pga_device, + chipdb_dir = chipdb_dir, + dbpart = self.dbpart, ) + if self.is_openxc7: + prjxray_db_dir = os.environ.get('PRJXRAY_DB_DIR') + if prjxray_db_dir is None or prjxray_db_dir == "": + prjxray_db_dir = '/snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/' + else: + prjxray_db_dir = f"/usr/share/nextpnr/prjxray-db/ + + if not os.path.isdir(prjxray_db_dir): + print(f"{prjxray_db_dir} does not exist on your system. \n" + \ + "Do you have the openXC7 toolchain installed? \n" + \ + "You can get it here: https://github.com/openXC7/toolchain-installer") + exit(1) + # pre packer options - self._pre_packer_opts["fasm2frames.py"] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( - part = self._partname, - db_root = f"/usr/share/nextpnr/prjxray-db/{self.bitstream_device}", + self._pre_packer_opts[self._pre_packer_cmd] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( + part = self.platform.device, + db_root = os.path.join(prjxray_db_dir, self._xc7family), top = self._build_name ) # packer options self._packer_opts += "--part_file {db_dir}/{part}/part.yaml --part_name {part} --frm_file {top}.frames --output_file {top}.bit".format( - db_dir = f"/usr/share/nextpnr/prjxray-db/{self.bitstream_device}", - part = self._partname, + db_dir = os.path.join(prjxray_db_dir, self._xc7family), + part = self.platform.device, top = self._build_name ) @@ -127,12 +144,11 @@ def build(self, platform, fragment, enable_xpm = False, **kwargs): - #FIXME self.platform = platform self._check_properties() return YosysNextPNRToolchain.build(self, platform, fragment, **kwargs) def add_false_path_constraint(self, platform, from_, to): - # FIXME: false path constraints are currently not supported by nextpnr-xilinx + # FIXME: false path constraints are currently not supported by the toolchain return From 8d0f08a57e66e0d2390ce404802de614244625ac Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 24 Oct 2023 08:49:46 +0700 Subject: [PATCH 253/454] fix syntax errors --- litex/build/xilinx/yosys_nextpnr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/build/xilinx/yosys_nextpnr.py b/litex/build/xilinx/yosys_nextpnr.py index fde84df37..99cfb28a7 100644 --- a/litex/build/xilinx/yosys_nextpnr.py +++ b/litex/build/xilinx/yosys_nextpnr.py @@ -117,7 +117,7 @@ def finalize(self): if prjxray_db_dir is None or prjxray_db_dir == "": prjxray_db_dir = '/snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/' else: - prjxray_db_dir = f"/usr/share/nextpnr/prjxray-db/ + prjxray_db_dir = "/usr/share/nextpnr/prjxray-db/" if not os.path.isdir(prjxray_db_dir): print(f"{prjxray_db_dir} does not exist on your system. \n" + \ @@ -126,7 +126,7 @@ def finalize(self): exit(1) # pre packer options - self._pre_packer_opts[self._pre_packer_cmd] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( + self._pre_packer_opts[self._pre_packer_cmd[0]] = "--part {part} --db-root {db_root} {top}.fasm > {top}.frames".format( part = self.platform.device, db_root = os.path.join(prjxray_db_dir, self._xc7family), top = self._build_name From f3f46e8cf10c7b1e72a6178a4d006890620d2eaf Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Tue, 24 Oct 2023 12:01:35 +0700 Subject: [PATCH 254/454] openxc7 toolchain: auto generate chipdb, if missing --- litex/build/xilinx/yosys_nextpnr.py | 32 ++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/litex/build/xilinx/yosys_nextpnr.py b/litex/build/xilinx/yosys_nextpnr.py index 99cfb28a7..c8a017eb7 100644 --- a/litex/build/xilinx/yosys_nextpnr.py +++ b/litex/build/xilinx/yosys_nextpnr.py @@ -100,16 +100,38 @@ def finalize(self): if self.is_openxc7: chipdb_dir = os.environ.get('CHIPDB') if chipdb_dir is None or chipdb_dir == "": - print("Error: please specify the directory, where you store your nextpnr-xilinx chipdb files in the environment variable CHIPDB (may be empty)") + print("Error: please specify the directory, where you store your nextpnr-xilinx chipdb files in the environment variable CHIPDB (directory may be empty)") exit(1) else: chipdb_dir = "/usr/share/nextpnr/xilinx-chipdb" + chipdb = os.path.join(chipdb_dir, self.dbpart) + ".bin" + if not os.path.exists(chipdb): + if self.is_openxc7: + print(f"Chip database file '{chipdb}' not found, generating...") + pypy3 = os.environ.get('PYPY3') + if pypy3 is None or pypy3 == "": + pypy3 = which("pypy3") + if pypy3 is None: + pypy3 = "python3" + + nextpnr_xilinx_python_dir = os.environ.get('NEXTPNR_XILINX_PYTHON_DIR') + if nextpnr_xilinx_python_dir is None or nextpnr_xilinx_python_dir == "": + nextpnr_xilinx_python_dir = "/snap/openxc7/current/opt/nextpnr-xilinx/python" + bba = self.dbpart + ".bba" + bbaexport = [pypy3, os.path.join(nextpnr_xilinx_python_dir, "bbaexport.py"), "--device", self.platform.device, "--bba", bba] + print(str(bbaexport)) + subprocess.run(bbaexport) + subprocess.run(["bbasm", "-l", bba, chipdb]) + os.remove(bba) + else: + print("Chip database file '{chipdb}' not found. Please check your toolchain installation!") + exit(1) + # pnr options - self._pnr_opts += "--chipdb {chipdb_dir}/{dbpart}.bin --write {top}_routed.json".format( - top = self._build_name, - chipdb_dir = chipdb_dir, - dbpart = self.dbpart, + self._pnr_opts += "--chipdb {chipdb} --write {top}_routed.json".format( + top = self._build_name, + chipdb = chipdb ) if self.is_openxc7: From 69dc666177587aa7f4860b96c006210dc166cf1c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 25 Oct 2023 16:01:45 +0200 Subject: [PATCH 255/454] CHANGES: Update. --- CHANGES.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f7f931b34..035510b3d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,22 +2,26 @@ ------------------------ [> Fixed -------- - liteeth/arp : Fixed response on table update. + - liteeth/arp : Fixed response on table update. + - litesata/us(p)sataphy : Fixed data_width=32 case. [> Added -------- - cpu/naxriscv : Added SMP support. - cpu/neorv32 : Added Debug support and update core complex. - cpu/vexriscv_smp : Added hardware breakpoints support. - build/colognechip : Added initial support. - soc/cores/video : Added VTG/DMA synchronization stage to VideoFramebuffer. - litepcie/dma : Improved LitePCIeDMADescriptorSplitter timings. - interconnect/wishbone : Added linear burst support to DownConverter. + - cpu/naxriscv : Added SMP support. + - cpu/neorv32 : Added Debug support and update core complex. + - cpu/vexriscv_smp : Added hardware breakpoints support. + - build/colognechip : Added initial support. + - soc/cores/video : Added VTG/DMA synchronization stage to VideoFramebuffer. + - litepcie/dma : Improved LitePCIeDMADescriptorSplitter timings. + - interconnect/wishbone : Added linear burst support to DownConverter. + - integration/SoC : Added with_jtagbone/with_uartbone support. + - soc/cores : Added Ti60F100 HyperRAM support. + - build/xilinx : Added initial OpenXC7 support (and improved Yosys-NextPnr). + - build/efinix : Added JTAG-UART/JTAGBone support. [> Changed ---------- - build/osfpga: Removed initial support (would need feedbacks/updates). - + - build/osfpga: Removed initial support (would need feedbacks/updates). [> 2023.08, released on September 14th 2023 ------------------------------------------- From ba2913f13778aafe501891e61e0ac4eab4d64e4e Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 12 Oct 2023 17:34:45 +0200 Subject: [PATCH 256/454] build/efinix/ifacewriter: adding internal Ti60F100 SPI Flash support Signed-off-by: Gwenhael Goavec-Merou --- litex/build/efinix/ifacewriter.py | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 1a58cc1b9..1326c96c3 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -482,6 +482,54 @@ def generate_hyperram(self, block, verbose=True): return '\n'.join(cmd) + '\n' + def generate_spiflash(self, block, verbose=True): + pads = block["pads"] + name = block["name"] + location = block["location"] + mode = block["mode"] + + assert mode in ["x1"] # FIXME: support x4 + assert location == "SPI_FLASH0" + + dq0 = pads.mosi.name + dq1 = pads.miso.name + dq2 = pads.wp.name + dq3 = pads.hold.name + + cmd = [] + cmd.append('design.create_block("{}", "SPI_FLASH")'.format(name)) + cmd.append('design.set_property("{}", "MULT_CTRL_EN","0","SPI_FLASH")'.format(name)) + cmd.append('design.set_property("{}", "REG_EN","0","SPI_FLASH")'.format(name)) + cmd.append('design.set_property("{}", "CLK_PIN","","SPI_FLASH")'.format(name)) # only required when REG_EN==1 + cmd.append('design.set_property("{}", "RW_WIDTH","{}","SPI_FLASH")'.format(name, mode)) + + cmd.append('design.set_property("{}", "CS_N_OUT_PIN","{}","SPI_FLASH")'.format(name, pads.cs_n.name)) + cmd.append('design.set_property("{}", "SCLK_OUT_PIN","{}","SPI_FLASH")'.format(name, pads.clk.name)) + cmd.append('design.set_property("{}", "MOSI_OUT_PIN","{}","SPI_FLASH")'.format(name, dq0)) + cmd.append('design.set_property("{}", "MISO_IN_PIN","{}","SPI_FLASH")'.format(name, dq1)) + cmd.append('design.set_property("{}", "WP_N_OUT_PIN","{}","SPI_FLASH")'.format(name, dq2)) + cmd.append('design.set_property("{}", "HOLD_N_OUT_PIN","{}","SPI_FLASH")'.format(name, dq3)) + + if mode == "x4": + cmd.append('design.set_property("{}", "HOLD_N_IN_PIN","{}","SPI_FLASH")'.format(name, dq3_i)) + cmd.append('design.set_property("{}", "HOLD_N_OE_PIN","{}","SPI_FLASH")'.format(name, dq3_oe)) + cmd.append('design.set_property("{}", "MISO_OUT_PIN","{}","SPI_FLASH")'.format(name, dq1_o)) + cmd.append('design.set_property("{}", "MISO_OE_PIN","{}","SPI_FLASH")'.format(name, dq1_oe)) + cmd.append('design.set_property("{}", "MOSI_IN_PIN","{}","SPI_FLASH")'.format(name, dq0_i)) + cmd.append('design.set_property("{}", "MOSI_OE_PIN","{}","SPI_FLASH")'.format(name, dq0_oe)) + cmd.append('design.set_property("{}", "WP_N_IN_PIN","{}","SPI_FLASH")'.format(name, dq2_i)) + cmd.append('design.set_property("{}", "WP_N_OE_PIN","{}","SPI_FLASH")'.format(name, dq2_oe)) + + # mult ctrl en only + #cmd.append('design.set_property("{}", "CS_N_OE_PIN","{}","SPI_FLASH")'.format(name, cs_n_oe)) + #cmd.append('design.set_property("{}", "SCLK_OE_PIN","{}","SPI_FLASH")'.format(name, clk_oe)) + + cmd.append('design.assign_resource("{}", "{}","SPI_FLASH")\n'.format(name, location)) + + cmd.append('design.set_device_property("ext_flash","EXT_FLASH_CTRL_EN","0","EXT_FLASH")') + + return '\n'.join(cmd) + '\n' + def generate(self, partnumber): output = "" for block in self.blocks: @@ -502,6 +550,8 @@ def generate(self, partnumber): output += self.generate_hyperram(block) if block["type"] == "JTAG": output += self.generate_jtag(block) + if block["type"] == "SPI_FLASH": + output += self.generate_spiflash(block) return output def footer(self): From a4539c3dae2a82b8aad919c126ae1ab09426a55a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:16:59 +0200 Subject: [PATCH 257/454] interconnect/wishbone: Add addressing parameter/property to allow Wishbone to use byte addressing (Currently using word addressing). --- litex/soc/interconnect/wishbone.py | 45 ++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 212064bd1..1bd05bbd7 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -45,18 +45,21 @@ class Interface(Record): - def __init__(self, data_width=32, adr_width=30, bursting=False, **kwargs): + def __init__(self, data_width=32, adr_width=30, bursting=False, addressing="word", **kwargs): self.data_width = data_width if kwargs.get("address_width", False): # FIXME: Improve or switch Wishbone to byte addressing instead of word addressing. adr_width = kwargs["address_width"] - int(log2(data_width//8)) self.adr_width = adr_width - self.address_width = adr_width + int(log2(data_width//8)) + self.address_width = adr_width + int(log2(data_width//8)) self.bursting = bursting + assert addressing in ["word", "byte"] + self.addressing = addressing Record.__init__(self, set_layout_parameters(_layout, - adr_width = adr_width, + adr_width = adr_width + (int(log2(data_width//8)) if (addressing == "byte") else 0), data_width = data_width, - sel_width = data_width//8)) + sel_width = data_width//8, + )) self.adr.reset_less = True self.dat_w.reset_less = True self.dat_r.reset_less = True @@ -272,12 +275,16 @@ class DownConverter(Module): """ def __init__(self, master, slave): + # Parameters/Checks. + assert master.addressing == "word" # FIXME: Test/Remove byte addressing limitation. + assert master.addressing == "word" # FIXME: Test/Remove byte addressing limitation. dw_from = len(master.dat_w) dw_to = len(slave.dat_w) ratio = dw_from//dw_to # # # + # Signals. skip = Signal() done = Signal() count = Signal(max=ratio) @@ -332,6 +339,9 @@ def __init__(self, master, slave): class UpConverter(Module): """UpConverter""" def __init__(self, master, slave): + # Parameters/Checks. + assert master.addressing == "word" # FIXME: Test/Remove byte addressing limitation. + assert master.addressing == "word" # FIXME: Test/Remove byte addressing limitation. dw_from = len(master.dat_w) dw_to = len(slave.dat_w) ratio = dw_to//dw_from @@ -359,17 +369,24 @@ class Converter(Module): def __init__(self, master, slave): self.master = master self.slave = slave + assert master.addressing == "word" # FIXME: Test/Remove byte addressing limitation. + assert master.addressing == "word" # FIXME: Test/Remove byte addressing limitation. # # # + # Signals. dw_from = len(master.dat_r) - dw_to = len(slave.dat_r) + dw_to = len(slave.dat_r) + + # DownConverter. if dw_from > dw_to: downconverter = DownConverter(master, slave) self.submodules += downconverter + # UpConverter. elif dw_from < dw_to: upconverter = UpConverter(master, slave) self.submodules += upconverter + # Direct Connect. else: self.comb += master.connect(slave) @@ -379,6 +396,7 @@ class SRAM(Module): def __init__(self, mem_or_size, read_only=None, write_only=None, init=None, bus=None, name=None): if bus is None: bus = Interface() + assert bus.addressing == "word" # FIXME: Test/Remove byte addressing limitation. self.bus = bus bus_data_width = len(self.bus.dat_r) if isinstance(mem_or_size, Memory): @@ -510,13 +528,18 @@ def __init__(self, bus_wishbone=None, bus_csr=None, register=True): # # # + wishbone_adr_shift = { + "word" : 0, + "byte" : log2_int(self.wishbone.data_width//8), + }[self.wishbone.addressing] + + # Registered Access. if register: - fsm = FSM(reset_state="IDLE") - self.submodules += fsm + self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(self.csr.dat_w, self.wishbone.dat_w), If(self.wishbone.cyc & self.wishbone.stb, - NextValue(self.csr.adr, self.wishbone.adr), + NextValue(self.csr.adr, self.wishbone.adr[wishbone_adr_shift:]), NextValue(self.csr.we, self.wishbone.we & (self.wishbone.sel != 0)), NextState("WRITE-READ") ) @@ -531,13 +554,13 @@ def __init__(self, bus_wishbone=None, bus_csr=None, register=True): self.wishbone.dat_r.eq(self.csr.dat_r), NextState("IDLE") ) + # Un-Registered Access. else: - fsm = FSM(reset_state="WRITE-READ") - self.submodules += fsm + self.submodules.fsm = fsm = FSM(reset_state="WRITE-READ") fsm.act("WRITE-READ", self.csr.dat_w.eq(self.wishbone.dat_w), If(self.wishbone.cyc & self.wishbone.stb, - self.csr.adr.eq(self.wishbone.adr), + self.csr.adr.eq(self.wishbone.adr[wishbone_adr_shift:]), self.csr.we.eq(self.wishbone.we & (self.wishbone.sel != 0)), NextState("ACK") ) From d6f7652b68babcae726b3c4ef45d3df48d9d3a0d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:18:23 +0200 Subject: [PATCH 258/454] axi/axi_full: Add addressing parameters and assert on byte. Useful to have similar properties than Wishbone. --- litex/soc/interconnect/axi/axi_full.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index e073ef356..83410819a 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -54,7 +54,7 @@ def r_description(data_width): ] class AXIInterface: - def __init__(self, data_width=32, address_width=32, id_width=1, version="axi4", clock_domain="sys", + def __init__(self, data_width=32, address_width=32, addressing="byte", id_width=1, version="axi4", clock_domain="sys", name = None, bursting = False, aw_user_width = 0, @@ -66,12 +66,14 @@ def __init__(self, data_width=32, address_width=32, id_width=1, version="axi4", # Parameters checks. # ------------------ assert data_width in [8, 16, 32, 64, 128, 256, 512, 1024] + assert addressing in ["byte"] assert version in ["axi3", "axi4"] # Parameters. # ----------- self.data_width = data_width self.address_width = address_width + self.addressing = addressing self.id_width = id_width self.version = version self.clock_domain = clock_domain From 4524262f64e5c0d860a20eba419ecb94528b9880 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:18:38 +0200 Subject: [PATCH 259/454] axi/axi_lite: Add addressing parameters and assert on byte. Useful to have similar properties than Wishbone. --- litex/soc/interconnect/axi/axi_lite.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_lite.py b/litex/soc/interconnect/axi/axi_lite.py index 26bb1dd46..6c7ad3db9 100644 --- a/litex/soc/interconnect/axi/axi_lite.py +++ b/litex/soc/interconnect/axi/axi_lite.py @@ -44,13 +44,22 @@ def r_lite_description(data_width): ] class AXILiteInterface: - def __init__(self, data_width=32, address_width=32, clock_domain="sys", name=None, bursting=False): + def __init__(self, data_width=32, address_width=32, addressing="byte", clock_domain="sys", name=None, bursting=False): + # Parameters checks. + # ------------------ + assert addressing == "byte" + if bursting is not False: + raise NotImplementedError("AXI-Lite does not support bursting") + + # Parameters. + # ----------- self.data_width = data_width self.address_width = address_width + self.addressing = addressing self.clock_domain = clock_domain - if bursting is not False: - raise NotImplementedError("AXI-Lite does not support bursting") + # Channels. + # --------- self.aw = stream.Endpoint(ax_lite_description(address_width), name=name) self.w = stream.Endpoint(w_lite_description(data_width), name=name) self.b = stream.Endpoint(b_lite_description(), name=name) From c5d869447a7f0380ef3e45485ca2796e92010bb5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:23:12 +0200 Subject: [PATCH 260/454] ahb: Add addressing property and different address shift in AHB2Wishbone when Wishbone is byte/word addressed. --- litex/soc/interconnect/ahb.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index 98ae407b4..a39d3d2e2 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -28,6 +28,7 @@ class Interface(Record): """Sets up the AHB interface signals for master and slave.""" adr_width = 32 data_width = 32 + addressing = "byte" master_signals = [ ("addr", adr_width), ("burst", 3), @@ -56,22 +57,25 @@ class AHB2Wishbone(LiteXModule): It takes as input an AHB interface and a Wishbone interface and does the conversion. """ def __init__(self, ahb, wishbone): - wishbone_adr_shift = log2_int(ahb.data_width // 8) + # Parameters/Checks. + wishbone_adr_shift = { + "word" : log2_int(ahb.data_width//8), + "byte" : 0 + }[wishbone.addressing] assert ahb.data_width == wishbone.data_width - assert ahb.adr_width == wishbone.adr_width + wishbone_adr_shift - - self.comb += ahb.resp.eq(wishbone.err) + assert ahb.adr_width == wishbone.adr_width + wishbone_adr_shift + # FSM. self.fsm = fsm = FSM() fsm.act("IDLE", ahb.readyout.eq(1), If(ahb.sel & (ahb.size == wishbone_adr_shift) & (ahb.trans == TransferType.NONSEQUENTIAL), - NextValue(wishbone.adr, ahb.addr[2:]), + NextValue(wishbone.adr, ahb.addr[wishbone_adr_shift:]), NextValue(wishbone.dat_w, ahb.wdata), - NextValue(wishbone.we, ahb.write), - NextValue(wishbone.sel, 2**len(wishbone.sel) - 1), + NextValue(wishbone.we, ahb.write), + NextValue(wishbone.sel, 2**len(wishbone.sel) - 1), NextState("ACT"), ) ) @@ -85,3 +89,5 @@ def __init__(self, ahb, wishbone): NextState("IDLE") ) ) + + self.comb += ahb.resp.eq(wishbone.err) From dde9605a5d031dd782a22b2e686987e1ab26764b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:23:31 +0200 Subject: [PATCH 261/454] csr_bus: Add addressing property. --- litex/soc/interconnect/csr_bus.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/soc/interconnect/csr_bus.py b/litex/soc/interconnect/csr_bus.py index 707ae0952..6a60f35cb 100644 --- a/litex/soc/interconnect/csr_bus.py +++ b/litex/soc/interconnect/csr_bus.py @@ -52,6 +52,7 @@ ] class Interface(Record): + addressing = "word" def __init__(self, data_width=8, address_width=14, alignment=32): self.data_width = data_width self.address_width = address_width From b19b7ed0010fa9cf4b409f4916707775f4795cbc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:24:37 +0200 Subject: [PATCH 262/454] axi/axi_lite_to_wishbone: Add different address shift when Wishbone is byte/word addressed. --- .../soc/interconnect/axi/axi_lite_to_wishbone.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_lite_to_wishbone.py b/litex/soc/interconnect/axi/axi_lite_to_wishbone.py index fa56b5c95..4b99c8592 100644 --- a/litex/soc/interconnect/axi/axi_lite_to_wishbone.py +++ b/litex/soc/interconnect/axi/axi_lite_to_wishbone.py @@ -17,10 +17,15 @@ class AXILite2Wishbone(LiteXModule): def __init__(self, axi_lite, wishbone, base_address=0x00000000): - wishbone_adr_shift = log2_int(axi_lite.data_width//8) + # Parameters/Checks. + wishbone_adr_shift = { + "word" : log2_int(axi_lite.data_width//8), + "byte" : 0 + }[wishbone.addressing] assert axi_lite.data_width == len(wishbone.dat_r) assert axi_lite.address_width == len(wishbone.adr) + wishbone_adr_shift + # Signals. _data = Signal(axi_lite.data_width) _r_addr = Signal(axi_lite.address_width) _w_addr = Signal(axi_lite.address_width) @@ -28,6 +33,7 @@ def __init__(self, axi_lite, wishbone, base_address=0x00000000): self.comb += _r_addr.eq(axi_lite.ar.addr - base_address) self.comb += _w_addr.eq(axi_lite.aw.addr - base_address) + # FSM. self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(axi_lite.ar.valid & axi_lite.aw.valid, @@ -92,15 +98,21 @@ def __init__(self, axi_lite, wishbone, base_address=0x00000000): class Wishbone2AXILite(LiteXModule): def __init__(self, wishbone, axi_lite, base_address=0x00000000): - wishbone_adr_shift = log2_int(axi_lite.data_width//8) + # Parameters/Checks. + wishbone_adr_shift = { + "word" : log2_int(axi_lite.data_width//8), + "byte" : 0 + }[wishbone.addressing] assert axi_lite.data_width == len(wishbone.dat_r) assert axi_lite.address_width == len(wishbone.adr) + wishbone_adr_shift + # Signals. _cmd_done = Signal() _data_done = Signal() _addr = Signal(len(wishbone.adr)) self.comb += _addr.eq(wishbone.adr - base_address//4) + # FSM. self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(_cmd_done, 0), From 7dc11e586b972adfdfe796b719140b5934c6add0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:25:30 +0200 Subject: [PATCH 263/454] soc/add_adapter: Add initial addressing conversion between byte/word addressed. --- litex/soc/integration/soc.py | 38 +++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 11c75cb8d..6c2a0a652 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -151,6 +151,11 @@ def __init__(self, name="SoCBusHandler", self.standard = standard self.data_width = data_width self.address_width = address_width + self.addressing = { + "wishbone" : "word", # FIXME: Allow selection for Wishbone. + "axi-lite" : "byte", + "axi" : "byte", + }[standard] self.bursting = bursting self.interconnect = interconnect self.interconnect_register = interconnect_register @@ -329,7 +334,8 @@ def data_width_convert(interface, direction): }[interface_cls] adapted_interface = interface_cls( data_width = self.data_width, - address_width = self.address_width + address_width = self.address_width, + addressing = self.addressing, ) if direction == "m2s": master, slave = interface, adapted_interface @@ -353,7 +359,8 @@ def bus_standard_convert(interface, direction): else: adapted_interface = main_bus_cls( data_width = self.data_width, - address_width = self.address_width + address_width = self.address_width, + addressing = self.addressing, ) if direction == "m2s": master, slave = interface, adapted_interface @@ -372,10 +379,35 @@ def bus_standard_convert(interface, direction): self.submodules += bridge return adapted_interface + # Addressing conversion helper. + def addressing_convert(interface, direction): + # Same Addressing, return un-modified interface. + if interface.addressing == self.addressing: + return interface + # Different Addressing: Return adapted interface. + else: + assert interface.addressing == "byte" # FIXME: Remove limitation. + assert self.addressing == "word" # FIXME: Remove limitation. + interface_cls = type(interface) + adapted_interface = interface_cls( + data_width = self.data_width, + address_width = self.address_width, + addressing = self.addressing, + ) + address_shift = log2_int(interface.data_width//8) + if direction == "m2s": + self.comb += interface.connect(adapted_interface) + self.comb += adapted_interface.adr.eq(interface.adr[address_shift:]) + elif direction == "s2m": + self.comb += adapted_interface.connect(interface) + self.comb += interface.adr.eq(adapted_interface.adr[address_shift:]) + return adapted_interface + # Interface conversion. adapted_interface = interface - adapted_interface = data_width_convert(adapted_interface, direction) + adapted_interface = data_width_convert(adapted_interface, direction) adapted_interface = bus_standard_convert(adapted_interface, direction) + adapted_interface = addressing_convert(adapted_interface, direction) if type(interface) != type(adapted_interface) or interface.data_width != adapted_interface.data_width: fmt = "{name} Bus {adapted} from {from_bus} {from_bits}-bit to {to_bus} {to_bits}-bit." From 75752b4bff01fe48a7852362ac8ab0f0a5db72c1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:40:16 +0200 Subject: [PATCH 264/454] cores/cpu: Make data_width/address_width/addressing explicit for all Wishbone interfaces. --- litex/soc/cores/cpu/blackparrot/core.py | 2 +- litex/soc/cores/cpu/cortex_m1/core.py | 4 ++-- litex/soc/cores/cpu/cortex_m3/core.py | 4 ++-- litex/soc/cores/cpu/cv32e40p/core.py | 12 ++++++------ litex/soc/cores/cpu/cv32e41p/core.py | 12 ++++++------ litex/soc/cores/cpu/cva5/core.py | 6 +++--- litex/soc/cores/cpu/eos_s3/core.py | 2 +- litex/soc/cores/cpu/femtorv/core.py | 2 +- litex/soc/cores/cpu/firev/core.py | 2 +- litex/soc/cores/cpu/gowin_emcu/core.py | 2 +- litex/soc/cores/cpu/ibex/core.py | 4 ++-- litex/soc/cores/cpu/lm32/core.py | 4 ++-- litex/soc/cores/cpu/marocchino/core.py | 8 ++++---- litex/soc/cores/cpu/microwatt/core.py | 8 ++++---- litex/soc/cores/cpu/minerva/core.py | 4 ++-- litex/soc/cores/cpu/mor1kx/core.py | 4 ++-- litex/soc/cores/cpu/neorv32/core.py | 2 +- litex/soc/cores/cpu/openc906/core.py | 9 ++++++--- litex/soc/cores/cpu/picorv32/core.py | 2 +- litex/soc/cores/cpu/rocket/core.py | 4 ++-- litex/soc/cores/cpu/serv/core.py | 4 ++-- litex/soc/cores/cpu/vexriscv/core.py | 10 +++++----- litex/soc/cores/cpu/vexriscv_smp/core.py | 12 ++++++------ 23 files changed, 63 insertions(+), 60 deletions(-) diff --git a/litex/soc/cores/cpu/blackparrot/core.py b/litex/soc/cores/cpu/blackparrot/core.py index 0f03ccdd7..fcf6482b1 100644 --- a/litex/soc/cores/cpu/blackparrot/core.py +++ b/litex/soc/cores/cpu/blackparrot/core.py @@ -91,7 +91,7 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.idbus = idbus = wishbone.Interface(data_width=64, adr_width=37) + self.idbus = idbus = wishbone.Interface(data_width=64, adr_width=37, addressing="word") self.periph_buses = [idbus] self.memory_buses = [] diff --git a/litex/soc/cores/cpu/cortex_m1/core.py b/litex/soc/cores/cpu/cortex_m1/core.py index ee036e777..5d6593a2d 100644 --- a/litex/soc/cores/cpu/cortex_m1/core.py +++ b/litex/soc/cores/cpu/cortex_m1/core.py @@ -64,7 +64,7 @@ def __init__(self, platform, variant="standard"): self.cpu_params = dict( # Clk/Rst. i_HCLK = ClockSignal("sys"), - i_SYSRESETn = ~(ResetSignal() | self.reset), + i_SYSRESETn = ~(ResetSignal("sys") | self.reset), # Control/Status. o_LOCKUP = Open(), @@ -85,7 +85,7 @@ def __init__(self, platform, variant="standard"): # Debug. p_SMALL_DEBUG = True, i_DBGRESTART = 0, - i_DBGRESETn = ~(ResetSignal() | self.reset), + i_DBGRESETn = ~(ResetSignal("sys") | self.reset), p_DEBUG_SEL = 1, # JTAG o_DBGRESTARTED = Open(), diff --git a/litex/soc/cores/cpu/cortex_m3/core.py b/litex/soc/cores/cpu/cortex_m3/core.py index d218c48d8..b2a852afc 100644 --- a/litex/soc/cores/cpu/cortex_m3/core.py +++ b/litex/soc/cores/cpu/cortex_m3/core.py @@ -65,7 +65,7 @@ def __init__(self, platform, variant="standard"): self.cpu_params = dict( # Clk/Rst. i_HCLK = ClockSignal("sys"), - i_SYSRESETn = ~(ResetSignal() | self.reset), + i_SYSRESETn = ~(ResetSignal("sys") | self.reset), # Control/Status. p_MPU_PRESENT = 0, @@ -82,7 +82,7 @@ def __init__(self, platform, variant="standard"): i_CFGITCMEN = 0, # 1 = alias ITCM at 0x0 # Debug. - i_DBGRESETn = ~(ResetSignal() | self.reset), + i_DBGRESETn = ~(ResetSignal("sys") | self.reset), # Instruction Bus (AXI). o_AWVALIDC = ibus.aw.valid, diff --git a/litex/soc/cores/cpu/cv32e40p/core.py b/litex/soc/cores/cpu/cv32e40p/core.py index 694e0460f..9fbaf93d5 100644 --- a/litex/soc/cores/cpu/cv32e40p/core.py +++ b/litex/soc/cores/cpu/cv32e40p/core.py @@ -232,7 +232,7 @@ def __init__(self, trace_depth=16384): class TraceDebugger(LiteXModule): def __init__(self): - self.bus = wishbone.Interface() + self.bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.source = source = stream.Endpoint([("data", 32)]) self.trace_if = trace_if = Record(trace_layout) @@ -292,8 +292,8 @@ def __init__(self, pads=None): if pads is None: pads = Record(self.jtag_layout) self.pads = pads - self.dmbus = wishbone.Interface() - self.sbbus = wishbone.Interface() + self.dmbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.sbbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") dmbus = Record(obi_layout) sbbus = Record(obi_layout) @@ -382,8 +382,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = wishbone.Interface() - self.dbus = wishbone.Interface() + self.ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [self.ibus, self.dbus] self.memory_buses = [] self.interrupt = Signal(15) @@ -458,7 +458,7 @@ def __init__(self, platform, variant="standard"): def add_debug_module(self, dm): self.cpu_params.update(i_debug_req_i=dm.debug_req) - self.cpu_params.update(i_rst_ni=~(ResetSignal() | dm.ndmreset)) + self.cpu_params.update(i_rst_ni=~(ResetSignal("sys") | dm.ndmreset)) def add_trace_core(self, trace): trace_if = trace.trace_if diff --git a/litex/soc/cores/cpu/cv32e41p/core.py b/litex/soc/cores/cpu/cv32e41p/core.py index ec8e76c6c..0345c9126 100644 --- a/litex/soc/cores/cpu/cv32e41p/core.py +++ b/litex/soc/cores/cpu/cv32e41p/core.py @@ -183,8 +183,8 @@ def __init__(self, pads=None): if pads is None: pads = Record(self.jtag_layout) self.pads = pads - self.dmbus = wishbone.Interface() - self.sbbus = wishbone.Interface() + self.dmbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.sbbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") dmbus = Record(obi_layout) sbbus = Record(obi_layout) @@ -267,8 +267,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = wishbone.Interface() - self.dbus = wishbone.Interface() + self.ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [self.ibus, self.dbus] self.memory_buses = [] self.interrupt = Signal(16) @@ -321,7 +321,7 @@ def __init__(self, platform, variant="standard"): i_apu_rvalid_i = 0, # IRQ. - i_irq_i = Cat(self.interrupt_padding,self.interrupt), + i_irq_i = Cat(self.interrupt_padding, self.interrupt), # Debug. i_debug_req_i = 0, @@ -335,7 +335,7 @@ def __init__(self, platform, variant="standard"): def add_debug_module(self, dm): self.cpu_params.update(i_debug_req_i=dm.debug_req) - self.cpu_params.update(i_rst_ni=~(ResetSignal() | dm.ndmreset)) + self.cpu_params.update(i_rst_ni=~(ResetSignal("sys") | dm.ndmreset)) def set_reset_address(self, reset_address): self.reset_address = reset_address diff --git a/litex/soc/cores/cpu/cva5/core.py b/litex/soc/cores/cpu/cva5/core.py index f973ca2b9..f2c8969ce 100644 --- a/litex/soc/cores/cpu/cva5/core.py +++ b/litex/soc/cores/cpu/cva5/core.py @@ -85,8 +85,8 @@ def __init__(self, platform, variant="standard"): if variant == "minimal": # Minimal variant has no caches, no multiply or divide support, and no branch predictor. # It also uses separate fetch and load-store wishbone interfaces. - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses.append(ibus) self.periph_buses.append(dbus) self.cpu_params.update( @@ -117,7 +117,7 @@ def __init__(self, platform, variant="standard"): if variant == "standard": # Standard variant includes instruction and data caches, multiply and divide support # along with the branch predictor. It uses a shared wishbone interface. - self.idbus = idbus = wishbone.Interface() + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses.append(idbus) self.cpu_params.update( o_idbus_adr = idbus.adr, diff --git a/litex/soc/cores/cpu/eos_s3/core.py b/litex/soc/cores/cpu/eos_s3/core.py index 7289e9252..4ba8773c2 100644 --- a/litex/soc/cores/cpu/eos_s3/core.py +++ b/litex/soc/cores/cpu/eos_s3/core.py @@ -47,7 +47,7 @@ def __init__(self, platform, variant, *args, **kwargs): self.platform = platform self.reset = Signal() self.interrupt = Signal(4) - self.pbus = wishbone.Interface(data_width=32, adr_width=15) + self.pbus = wishbone.Interface(data_width=32, adr_width=15, addressing="word") self.periph_buses = [self.pbus] self.memory_buses = [] diff --git a/litex/soc/cores/cpu/femtorv/core.py b/litex/soc/cores/cpu/femtorv/core.py index 20d86e379..3f118fa8a 100644 --- a/litex/soc/cores/cpu/femtorv/core.py +++ b/litex/soc/cores/cpu/femtorv/core.py @@ -71,7 +71,7 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.human_name = f"FemtoRV-{variant.upper()}" self.reset = Signal() - self.idbus = idbus = wishbone.Interface() + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/firev/core.py b/litex/soc/cores/cpu/firev/core.py index 0a15d0184..b18ffe0e9 100644 --- a/litex/soc/cores/cpu/firev/core.py +++ b/litex/soc/cores/cpu/firev/core.py @@ -59,7 +59,7 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.human_name = f"FireV-{variant.upper()}" self.reset = Signal() - self.idbus = idbus = wishbone.Interface() + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index ce492b39c..7af5ac90b 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -168,7 +168,7 @@ def __init__(self, platform, variant, *args, **kwargs): # Extension AHB -> Wishbone CSR via bridge - self.pbus = wishbone.Interface(data_width=32, adr_width=30) + self.pbus = wishbone.Interface(data_width=32, adr_width=30, addressing="word") self.periph_buses = [self.pbus] ahb_targexp0 = ahb.Interface() for s, _ in ahb_targexp0.master_signals: diff --git a/litex/soc/cores/cpu/ibex/core.py b/litex/soc/cores/cpu/ibex/core.py index 358356f40..e8b46d797 100644 --- a/litex/soc/cores/cpu/ibex/core.py +++ b/litex/soc/cores/cpu/ibex/core.py @@ -121,8 +121,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = wishbone.Interface() - self.dbus = wishbone.Interface() + self.ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [self.ibus, self.dbus] self.memory_buses = [] self.interrupt = Signal(15) diff --git a/litex/soc/cores/cpu/lm32/core.py b/litex/soc/cores/cpu/lm32/core.py index ac23717e7..2dd157dff 100644 --- a/litex/soc/cores/cpu/lm32/core.py +++ b/litex/soc/cores/cpu/lm32/core.py @@ -51,8 +51,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.interrupt = Signal(32) self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/marocchino/core.py b/litex/soc/cores/cpu/marocchino/core.py index 61cdb1e22..7b1b7eb07 100644 --- a/litex/soc/cores/cpu/marocchino/core.py +++ b/litex/soc/cores/cpu/marocchino/core.py @@ -84,8 +84,8 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -117,8 +117,8 @@ def __init__(self, platform, variant="standard"): **cpu_args, # Clk / Rst. - i_wb_clk = ClockSignal("sys"), - i_wb_rst = ResetSignal("sys") | self.reset, + i_wb_clk = ClockSignal("sys"), + i_wb_rst = ResetSignal("sys") | self.reset, i_cpu_clk = ClockSignal("sys"), i_cpu_rst = ResetSignal("sys") | self.reset, diff --git a/litex/soc/cores/cpu/microwatt/core.py b/litex/soc/cores/cpu/microwatt/core.py index e0e7778c5..e32648b5f 100644 --- a/litex/soc/cores/cpu/microwatt/core.py +++ b/litex/soc/cores/cpu/microwatt/core.py @@ -71,8 +71,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = ibus = wishbone.Interface(data_width=64, adr_width=29) - self.dbus = dbus = wishbone.Interface(data_width=64, adr_width=29) + self.ibus = ibus = wishbone.Interface(data_width=64, adr_width=29, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=64, adr_width=29, addressing="word") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). if "irq" in variant: @@ -240,8 +240,8 @@ class XICSSlave(Module, AutoCSR): def __init__(self, platform, core_irq_out=Signal(), int_level_in=Signal(16), variant="standard"): self.variant = variant - self.icp_bus = icp_bus = wishbone.Interface(data_width=32, adr_width=12) - self.ics_bus = ics_bus = wishbone.Interface(data_width=32, adr_width=12) + self.icp_bus = icp_bus = wishbone.Interface(data_width=32, adr_width=12, addressing="word") + self.ics_bus = ics_bus = wishbone.Interface(data_width=32, adr_width=12, addressing="word") # XICS Signals. self.ics_icp_xfer_src = Signal(4) diff --git a/litex/soc/cores/cpu/minerva/core.py b/litex/soc/cores/cpu/minerva/core.py index f0ad4324e..36f8ef23d 100644 --- a/litex/soc/cores/cpu/minerva/core.py +++ b/litex/soc/cores/cpu/minerva/core.py @@ -48,8 +48,8 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [self.ibus, self.dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/mor1kx/core.py b/litex/soc/cores/cpu/mor1kx/core.py index 4da94af21..b198dd379 100644 --- a/litex/soc/cores/cpu/mor1kx/core.py +++ b/litex/soc/cores/cpu/mor1kx/core.py @@ -84,8 +84,8 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/neorv32/core.py b/litex/soc/cores/cpu/neorv32/core.py index 3f9dc61ef..1de021f2e 100644 --- a/litex/soc/cores/cpu/neorv32/core.py +++ b/litex/soc/cores/cpu/neorv32/core.py @@ -75,7 +75,7 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.human_name = f"NEORV32-{variant}" self.reset = Signal() - self.ibus = idbus = wishbone.Interface() + self.ibus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/openc906/core.py b/litex/soc/cores/cpu/openc906/core.py index e0a16f61b..4e6846235 100644 --- a/litex/soc/cores/cpu/openc906/core.py +++ b/litex/soc/cores/cpu/openc906/core.py @@ -117,8 +117,11 @@ def __init__(self, platform, variant="standard", convert_periph_bus_to_wishbone= # Peripheral bus (Connected to main SoC's bus). self.axi_if = axi_if = axi.AXIInterface(data_width=128, address_width=40, id_width=8) if convert_periph_bus_to_wishbone: - self.wb_if = wishbone.Interface(data_width=axi_if.data_width, - adr_width=axi_if.address_width - log2_int(axi_if.data_width // 8)) + self.wb_if = wishbone.Interface( + data_width = axi_if.data_width, + adr_width = axi_if.address_width - log2_int(axi_if.data_width // 8), + addressing = "word", + ) self.submodules += axi.AXI2Wishbone(axi_if, self.wb_if) self.periph_buses = [self.wb_if] else: @@ -206,7 +209,7 @@ def __init__(self, platform, variant="standard", convert_periph_bus_to_wishbone= add_manifest_sources(platform, "gen_rtl/filelists/generic_fpga.fl") def add_debug(self): - self.debug_bus = wishbone.Interface() + self.debug_bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") debug_apb = Record(apb_layout) self.submodules += Wishbone2APB(self.debug_bus, debug_apb) diff --git a/litex/soc/cores/cpu/picorv32/core.py b/litex/soc/cores/cpu/picorv32/core.py index c42043da3..3d33a4038 100644 --- a/litex/soc/cores/cpu/picorv32/core.py +++ b/litex/soc/cores/cpu/picorv32/core.py @@ -74,7 +74,7 @@ def __init__(self, platform, variant="standard"): self.trap = Signal() self.reset = Signal() self.interrupt = Signal(32) - self.idbus = idbus = wishbone.Interface() + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/rocket/core.py b/litex/soc/cores/cpu/rocket/core.py index 1a6a9b22e..d7b83fbe0 100644 --- a/litex/soc/cores/cpu/rocket/core.py +++ b/litex/soc/cores/cpu/rocket/core.py @@ -130,8 +130,8 @@ def __init__(self, platform, variant="linux"): self.mmio_axi = mmio_axi = axi.AXIInterface(data_width=mmio_dw, address_width=32, id_width=4) self.l2fb_axi = l2fb_axi = axi.AXIInterface(data_width=mmio_dw, address_width=32, id_width=4) - self.mmio_wb = mmio_wb = wishbone.Interface(data_width=mmio_dw, adr_width=32-log2_int(mmio_dw//8)) - self.l2fb_wb = l2fb_wb = wishbone.Interface(data_width=mmio_dw, adr_width=32-log2_int(mmio_dw//8)) + self.mmio_wb = mmio_wb = wishbone.Interface(data_width=mmio_dw, adr_width=32-log2_int(mmio_dw//8), addressing="word") + self.l2fb_wb = l2fb_wb = wishbone.Interface(data_width=mmio_dw, adr_width=32-log2_int(mmio_dw//8), addressing="word") self.memory_buses = [mem_axi] # Peripheral buses (Connected to main SoC's bus). self.periph_buses = [mmio_wb] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index 982f8f3dc..4de458a2b 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -59,8 +59,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index 86fbaac0c..42bc67dca 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -140,8 +140,8 @@ def __init__(self, platform, variant="standard", with_timer=False): self.external_variant = None self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = wishbone.Interface() - self.dbus = dbus = wishbone.Interface() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -217,7 +217,7 @@ def add_debug(self): self.transfer_in_progress = Signal() self.transfer_wait_for_ack = Signal() - self.debug_bus = wishbone.Interface() + self.debug_bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.sync += self.debug_bus.dat_r.eq(self.o_rsp_data) self.sync += debug_reset.eq(reset_debug_logic | ResetSignal()) @@ -268,10 +268,10 @@ def add_debug(self): ] self.cpu_params.update( - i_reset = ResetSignal() | self.reset | debug_reset, + i_reset = ResetSignal("sys") | self.reset | debug_reset, i_iBusWishbone_ERR = self.ibus.err | ibus_err, i_dBusWishbone_ERR = self.dbus.err | dbus_err, - i_debugReset = ResetSignal(), + i_debugReset = ResetSignal("sys"), i_debug_bus_cmd_valid = self.i_cmd_valid, i_debug_bus_cmd_payload_wr = self.i_cmd_payload_wr, i_debug_bus_cmd_payload_address = self.i_cmd_payload_address, diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index 10133d1c5..4031dc70a 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -312,7 +312,7 @@ def __init__(self, platform, variant): False : 32, # Else max of I/DCache-width. True : max(VexRiscvSMP.icache_width, VexRiscvSMP.dcache_width), - }[VexRiscvSMP.wishbone_memory and not VexRiscvSMP.wishbone_force_32b]) + }[VexRiscvSMP.wishbone_memory and not VexRiscvSMP.wishbone_force_32b], addressing="word") self.periph_buses = [pbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -320,8 +320,8 @@ def __init__(self, platform, variant): self.cpu_params = dict( # Clk / Rst. - i_debugCd_external_clk = ClockSignal(), - i_debugCd_external_reset = ResetSignal() | self.reset, + i_debugCd_external_clk = ClockSignal("sys"), + i_debugCd_external_reset = ResetSignal("sys") | self.reset, # Interrupts. i_interrupts = self.interrupt, @@ -352,7 +352,7 @@ def __init__(self, platform, variant): # DMA. if VexRiscvSMP.coherent_dma: - self.dma_bus = dma_bus = wishbone.Interface(data_width=VexRiscvSMP.dcache_width, address_width=32) + self.dma_bus = dma_bus = wishbone.Interface(data_width=VexRiscvSMP.dcache_width, address_width=32, addressing="word") dma_bus_stall = Signal() dma_bus_inhibit = Signal() self.cpu_params.update( @@ -462,7 +462,7 @@ def add_soc_components(self, soc): soc.add_config("CPU_ITLB_WAYS", VexRiscvSMP.itlb_size) # Add PLIC as Bus Slave - self.plicbus = plicbus = wishbone.Interface() + self.plicbus = plicbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.cpu_params.update( i_plicWishbone_CYC = plicbus.cyc, i_plicWishbone_STB = plicbus.stb, @@ -475,7 +475,7 @@ def add_soc_components(self, soc): soc.bus.add_slave("plic", self.plicbus, region=SoCRegion(origin=soc.mem_map.get("plic"), size=0x40_0000, cached=False)) # Add CLINT as Bus Slave - self.clintbus = clintbus = wishbone.Interface() + self.clintbus = clintbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.cpu_params.update( i_clintWishbone_CYC = clintbus.cyc, i_clintWishbone_STB = clintbus.stb, From 6e928efe82870836c35231f30443b45607e172c9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 26 Oct 2023 17:50:39 +0200 Subject: [PATCH 265/454] cores/cpu: Switch Wishbone interfaces to byte addressing where possible and remove address shifting. --- litex/soc/cores/cpu/eos_s3/core.py | 4 ++-- litex/soc/cores/cpu/femtorv/core.py | 4 ++-- litex/soc/cores/cpu/firev/core.py | 4 ++-- litex/soc/cores/cpu/ibex/core.py | 8 ++++---- litex/soc/cores/cpu/lm32/core.py | 8 ++++---- litex/soc/cores/cpu/marocchino/core.py | 8 ++++---- litex/soc/cores/cpu/mor1kx/core.py | 8 ++++---- litex/soc/cores/cpu/neorv32/core.py | 4 ++-- litex/soc/cores/cpu/picorv32/core.py | 4 ++-- litex/soc/cores/cpu/serv/core.py | 12 ++++++------ 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/litex/soc/cores/cpu/eos_s3/core.py b/litex/soc/cores/cpu/eos_s3/core.py index 4ba8773c2..7cc208b08 100644 --- a/litex/soc/cores/cpu/eos_s3/core.py +++ b/litex/soc/cores/cpu/eos_s3/core.py @@ -47,7 +47,7 @@ def __init__(self, platform, variant, *args, **kwargs): self.platform = platform self.reset = Signal() self.interrupt = Signal(4) - self.pbus = wishbone.Interface(data_width=32, adr_width=15, addressing="word") + self.pbus = wishbone.Interface(data_width=32, adr_width=15, addressing="byte") self.periph_buses = [self.pbus] self.memory_buses = [] @@ -84,7 +84,7 @@ def __init__(self, platform, variant, *args, **kwargs): # ----------- i_WB_CLK = ClockSignal("eos_s3_0"), o_WB_RST = pbus_rst, - o_WBs_ADR = Cat(Signal(2), self.pbus.adr), + o_WBs_ADR = self.pbus.adr, o_WBs_CYC = self.pbus.cyc, o_WBs_BYTE_STB = self.pbus.sel, o_WBs_WE = self.pbus.we, diff --git a/litex/soc/cores/cpu/femtorv/core.py b/litex/soc/cores/cpu/femtorv/core.py index 3f118fa8a..4f3c6142c 100644 --- a/litex/soc/cores/cpu/femtorv/core.py +++ b/litex/soc/cores/cpu/femtorv/core.py @@ -71,7 +71,7 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.human_name = f"FemtoRV-{variant.upper()}" self.reset = Signal() - self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -119,7 +119,7 @@ def __init__(self, platform, variant="standard"): self.fsm = fsm = FSM(reset_state="WAIT") fsm.act("WAIT", # Latch Address + Bytes to Words conversion. - NextValue(idbus.adr, mbus.addr[2:]), + NextValue(idbus.adr, mbus.addr), # Latch Wdata/WMask. NextValue(idbus.dat_w, mbus.wdata), diff --git a/litex/soc/cores/cpu/firev/core.py b/litex/soc/cores/cpu/firev/core.py index b18ffe0e9..5904110a2 100644 --- a/litex/soc/cores/cpu/firev/core.py +++ b/litex/soc/cores/cpu/firev/core.py @@ -59,7 +59,7 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.human_name = f"FireV-{variant.upper()}" self.reset = Signal() - self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -115,7 +115,7 @@ def __init__(self, platform, variant="standard"): ) self.comb += [ idbus.we.eq(mbus.out_ram_rw), - idbus.adr.eq(mbus.out_ram_addr[2:]), + idbus.adr.eq(mbus.out_ram_addr), idbus.sel.eq(mbus.out_ram_wmask), idbus.dat_w.eq(mbus.out_ram_data_in), diff --git a/litex/soc/cores/cpu/ibex/core.py b/litex/soc/cores/cpu/ibex/core.py index e8b46d797..b3e88077e 100644 --- a/litex/soc/cores/cpu/ibex/core.py +++ b/litex/soc/cores/cpu/ibex/core.py @@ -57,7 +57,7 @@ def __init__(self, obi, wb): # On OBI request: If(obi.req, # Drive Wishbone bus from OBI bus. - wb.adr.eq(obi.addr[2:32]), + wb.adr.eq( obi.addr), wb.stb.eq( 1), wb.dat_w.eq( obi.wdata), wb.cyc.eq( 1), @@ -77,7 +77,7 @@ def __init__(self, obi, wb): ) fsm.act("ACK", # Drive Wishbone bus from stored OBI bus values. - wb.adr.eq(addr[2:32]), + wb.adr.eq( addr), wb.stb.eq( 1), wb.dat_w.eq( wdata), wb.cyc.eq( 1), @@ -121,8 +121,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - self.dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.ibus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.dbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [self.ibus, self.dbus] self.memory_buses = [] self.interrupt = Signal(15) diff --git a/litex/soc/cores/cpu/lm32/core.py b/litex/soc/cores/cpu/lm32/core.py index 2dd157dff..a6557f71a 100644 --- a/litex/soc/cores/cpu/lm32/core.py +++ b/litex/soc/cores/cpu/lm32/core.py @@ -51,8 +51,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.interrupt = Signal(32) self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -68,7 +68,7 @@ def __init__(self, platform, variant="standard"): i_interrupt=self.interrupt, # IBus. - o_I_ADR_O = Cat(Signal(2), ibus.adr), + o_I_ADR_O = ibus.adr, o_I_DAT_O = ibus.dat_w, o_I_SEL_O = ibus.sel, o_I_CYC_O = ibus.cyc, @@ -82,7 +82,7 @@ def __init__(self, platform, variant="standard"): i_I_RTY_I = 0, # DBus. - o_D_ADR_O = Cat(Signal(2), dbus.adr), + o_D_ADR_O = dbus.adr, o_D_DAT_O = dbus.dat_w, o_D_SEL_O = dbus.sel, o_D_CYC_O = dbus.cyc, diff --git a/litex/soc/cores/cpu/marocchino/core.py b/litex/soc/cores/cpu/marocchino/core.py index 7b1b7eb07..150e111d2 100644 --- a/litex/soc/cores/cpu/marocchino/core.py +++ b/litex/soc/cores/cpu/marocchino/core.py @@ -84,8 +84,8 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -123,7 +123,7 @@ def __init__(self, platform, variant="standard"): i_cpu_rst = ResetSignal("sys") | self.reset, # IBus. - o_iwbm_adr_o = Cat(Signal(2), ibus.adr), + o_iwbm_adr_o = ibus.adr, o_iwbm_stb_o = ibus.stb, o_iwbm_cyc_o = ibus.cyc, o_iwbm_sel_o = ibus.sel, @@ -137,7 +137,7 @@ def __init__(self, platform, variant="standard"): i_iwbm_rty_i = 0, # DBus. - o_dwbm_adr_o = Cat(Signal(2), dbus.adr), + o_dwbm_adr_o = dbus.adr, o_dwbm_stb_o = dbus.stb, o_dwbm_cyc_o = dbus.cyc, o_dwbm_sel_o = dbus.sel, diff --git a/litex/soc/cores/cpu/mor1kx/core.py b/litex/soc/cores/cpu/mor1kx/core.py index b198dd379..349be5ca9 100644 --- a/litex/soc/cores/cpu/mor1kx/core.py +++ b/litex/soc/cores/cpu/mor1kx/core.py @@ -84,8 +84,8 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.reset = Signal() self.interrupt = Signal(32) - self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -160,7 +160,7 @@ def __init__(self, platform, variant="standard"): i_irq_i=self.interrupt, # IBus. - o_iwbm_adr_o = Cat(Signal(2), ibus.adr), + o_iwbm_adr_o = ibus.adr, o_iwbm_dat_o = ibus.dat_w, o_iwbm_sel_o = ibus.sel, o_iwbm_cyc_o = ibus.cyc, @@ -174,7 +174,7 @@ def __init__(self, platform, variant="standard"): i_iwbm_rty_i = 0, # DBus. - o_dwbm_adr_o = Cat(Signal(2), dbus.adr), + o_dwbm_adr_o = dbus.adr, o_dwbm_dat_o = dbus.dat_w, o_dwbm_sel_o = dbus.sel, o_dwbm_cyc_o = dbus.cyc, diff --git a/litex/soc/cores/cpu/neorv32/core.py b/litex/soc/cores/cpu/neorv32/core.py index 1de021f2e..a3f953048 100644 --- a/litex/soc/cores/cpu/neorv32/core.py +++ b/litex/soc/cores/cpu/neorv32/core.py @@ -75,7 +75,7 @@ def __init__(self, platform, variant="standard"): self.variant = variant self.human_name = f"NEORV32-{variant}" self.reset = Signal() - self.ibus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.ibus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -98,7 +98,7 @@ def __init__(self, platform, variant="standard"): i_mext_irq_i = 0, # I/D Wishbone Bus. - o_wb_adr_o = Cat(Signal(2), idbus.adr), + o_wb_adr_o = idbus.adr, i_wb_dat_i = idbus.dat_r, o_wb_dat_o = idbus.dat_w, o_wb_we_o = idbus.we, diff --git a/litex/soc/cores/cpu/picorv32/core.py b/litex/soc/cores/cpu/picorv32/core.py index 3d33a4038..d7d5f4a1b 100644 --- a/litex/soc/cores/cpu/picorv32/core.py +++ b/litex/soc/cores/cpu/picorv32/core.py @@ -74,7 +74,7 @@ def __init__(self, platform, variant="standard"): self.trap = Signal() self.reset = Signal() self.interrupt = Signal(32) - self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -166,7 +166,7 @@ def __init__(self, platform, variant="standard"): # Adapt Memory Interface to Wishbone. self.comb += [ - idbus.adr.eq(mem_addr[2:]), + idbus.adr.eq(mem_addr), idbus.dat_w.eq(mem_wdata), idbus.we.eq(mem_wstrb != 0), idbus.sel.eq(mem_wstrb), diff --git a/litex/soc/cores/cpu/serv/core.py b/litex/soc/cores/cpu/serv/core.py index 4de458a2b..0e7835122 100644 --- a/litex/soc/cores/cpu/serv/core.py +++ b/litex/soc/cores/cpu/serv/core.py @@ -59,8 +59,8 @@ def __init__(self, platform, variant="standard"): self.platform = platform self.variant = variant self.reset = Signal() - self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="word") - self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.dbus = dbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus). self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). @@ -68,20 +68,20 @@ def __init__(self, platform, variant="standard"): self.cpu_params = dict( # Clk / Rst - i_clk = ClockSignal(), - i_i_rst = ResetSignal() | self.reset, + i_clk = ClockSignal("sys"), + i_i_rst = ResetSignal("sys") | self.reset, # Timer IRQ. i_i_timer_irq = 0, # Ibus. - o_o_ibus_adr = Cat(Signal(2), ibus.adr), + o_o_ibus_adr = ibus.adr, o_o_ibus_cyc = ibus.cyc, i_i_ibus_rdt = ibus.dat_r, i_i_ibus_ack = ibus.ack, # Dbus. - o_o_dbus_adr = Cat(Signal(2), dbus.adr), + o_o_dbus_adr = dbus.adr, o_o_dbus_dat = dbus.dat_w, o_o_dbus_sel = dbus.sel, o_o_dbus_we = dbus.we, From 203726bc03bdd4389ef12e7ab4792be7d7970f59 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Fri, 27 Oct 2023 13:05:14 +1100 Subject: [PATCH 266/454] test_csr: test cases for issue 'status' reads as 0 in simulation when CSRStatus has fields. --- test/test_csr.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/test_csr.py b/test/test_csr.py index 92b08ef35..c86e2350b 100644 --- a/test/test_csr.py +++ b/test/test_csr.py @@ -116,10 +116,17 @@ def generator(dut): self.assertEqual((yield dut._storage.fields.foo), 0xa) self.assertEqual((yield dut._storage.fields.bar), 0x5a) self.assertEqual((yield dut._storage.storage), 0x5a000a) + self.assertEqual((yield from dut._storage.read()), 0x5a000a) yield yield self.assertEqual((yield dut._status.fields.foo), 0xa) self.assertEqual((yield dut._status.fields.bar), 0x5a) + try: + self.assertEqual((yield dut._status.status), 0x5a000a) + self.assertEqual((yield from dut._status.read()), 0x5a000a) + except self.failureException as exc: + print("Skipping:" + repr(exc)) + raise self.skipTest("skip known failure") from None class DUT(Module): def __init__(self): From 002aad7a43c0a146914375f5ea8c361ce8ad16c8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 10:55:13 +0200 Subject: [PATCH 267/454] soc/test: Make data_width/address_width/addressing explicit on Wishbone.Interface calls. --- litex/soc/cores/cpu/cv32e40p/core.py | 2 +- litex/soc/cores/emif.py | 4 +- litex/soc/cores/hyperbus.py | 2 +- litex/soc/cores/i2s.py | 2 +- litex/soc/cores/led.py | 4 +- litex/soc/cores/ram/lattice_ice40.py | 2 +- litex/soc/cores/ram/lattice_nx.py | 2 +- litex/soc/cores/spi/spi_bone.py | 2 +- litex/soc/cores/spi/spi_mmap.py | 4 +- litex/soc/cores/spi_opi.py | 2 +- litex/soc/cores/uart.py | 2 +- litex/soc/cores/usb_ohci.py | 4 +- litex/soc/integration/soc.py | 40 ++++++++++++++----- .../avalon/avalon_mm_to_wishbone.py | 2 +- litex/soc/interconnect/wishbone.py | 4 +- litex/tools/litex_periph_gen.py | 8 ++-- test/test_axi.py | 4 +- test/test_axi_lite.py | 13 ++++-- test/test_wishbone.py | 16 ++++---- 19 files changed, 73 insertions(+), 46 deletions(-) diff --git a/litex/soc/cores/cpu/cv32e40p/core.py b/litex/soc/cores/cpu/cv32e40p/core.py index 9fbaf93d5..79dfbeb1d 100644 --- a/litex/soc/cores/cpu/cv32e40p/core.py +++ b/litex/soc/cores/cpu/cv32e40p/core.py @@ -186,7 +186,7 @@ def __init__(self, wb, apb): class TraceCollector(LiteXModule): def __init__(self, trace_depth=16384): - self.bus = bus = wishbone.Interface() + self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.sink = sink = stream.Endpoint([("data", 32)]) clear = Signal() diff --git a/litex/soc/cores/emif.py b/litex/soc/cores/emif.py index 0332dac52..923a30e99 100644 --- a/litex/soc/cores/emif.py +++ b/litex/soc/cores/emif.py @@ -18,7 +18,7 @@ class EMIF(LiteXModule): Provides a simple EMIF to Wishbone Master bridge. """ def __init__(self, pads): - self.bus = bus = wishbone.Interface() + self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") # # # @@ -87,7 +87,7 @@ def add_tristate(self, pad): class EMIF16To32Adapter(LiteXModule): def __init__(self, emif): - self.bus = bus = wishbone.Interface() + self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") # # # diff --git a/litex/soc/cores/hyperbus.py b/litex/soc/cores/hyperbus.py index f6c743c4e..da8c03d2b 100644 --- a/litex/soc/cores/hyperbus.py +++ b/litex/soc/cores/hyperbus.py @@ -29,7 +29,7 @@ class HyperRAM(LiteXModule): """ def __init__(self, pads, latency=6, sys_clk_freq=None): self.pads = pads - self.bus = bus = wishbone.Interface() + self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") # # # diff --git a/litex/soc/cores/i2s.py b/litex/soc/cores/i2s.py index 1113dcc87..d3d7d1ba4 100644 --- a/litex/soc/cores/i2s.py +++ b/litex/soc/cores/i2s.py @@ -163,7 +163,7 @@ def __init__(self, pads, fifo_depth=256, controller=False, master=False, concate self.comb += [rising_edge.eq(clk_pin & ~clk_d), falling_edge.eq(~clk_pin & clk_d)] # Wishbone bus - self.bus = bus = wishbone.Interface() + self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") rd_ack = Signal() wr_ack = Signal() self.comb += [ diff --git a/litex/soc/cores/led.py b/litex/soc/cores/led.py index 7ac782d4c..477b93e04 100644 --- a/litex/soc/cores/led.py +++ b/litex/soc/cores/led.py @@ -134,7 +134,7 @@ class WS2812(LiteXModule): """ def __init__(self, pad, nleds, sys_clk_freq, bus_mastering=False, bus_base=None, revision="new", init=None): if bus_mastering: - self.bus = bus = wishbone.Interface(data_width=32) + self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") else: # Memory. mem = Memory(32, nleds, init=init) @@ -145,7 +145,7 @@ def __init__(self, pad, nleds, sys_clk_freq, bus_mastering=False, bus_base=None, self.wb_mem = wishbone.SRAM( mem_or_size = mem, read_only = False, - bus = wishbone.Interface(data_width=32) + bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") ) self.bus = self.wb_mem.bus diff --git a/litex/soc/cores/ram/lattice_ice40.py b/litex/soc/cores/ram/lattice_ice40.py index 08ea05967..c1894cf60 100644 --- a/litex/soc/cores/ram/lattice_ice40.py +++ b/litex/soc/cores/ram/lattice_ice40.py @@ -27,7 +27,7 @@ class Up5kSPRAM(LiteXModule): def __init__(self, width=32, size=64*kB): - self.bus = wishbone.Interface(width) + self.bus = wishbone.Interface(data_width=width, address_width=32, addressing="word") # # # diff --git a/litex/soc/cores/ram/lattice_nx.py b/litex/soc/cores/ram/lattice_nx.py index 836c1a314..b2fa75fee 100644 --- a/litex/soc/cores/ram/lattice_nx.py +++ b/litex/soc/cores/ram/lattice_nx.py @@ -53,7 +53,7 @@ def initval_parameters(contents, width): class NXLRAM(LiteXModule): def __init__(self, width=32, size=128*kB, init=[]): - self.bus = wishbone.Interface(width) + self.bus = wishbone.Interface(data_width=width, address_width=32, addressing="word") assert width in [32, 64] self.width = width self.size = size diff --git a/litex/soc/cores/spi/spi_bone.py b/litex/soc/cores/spi/spi_bone.py index e0df08e20..c85aa7b34 100644 --- a/litex/soc/cores/spi/spi_bone.py +++ b/litex/soc/cores/spi/spi_bone.py @@ -133,7 +133,7 @@ class SPIBone(LiteXModule, ModuleDoc): The bridge core is designed to run at 1/4 the system clock. """ def __init__(self, pads, wires=4, with_tristate=True): - self.bus = bus = wishbone.Interface(address_width=32, data_width=32) + self.bus = bus = wishbone.Interface(address_width=32, data_width=32, addressing="word") # # # diff --git a/litex/soc/cores/spi/spi_mmap.py b/litex/soc/cores/spi/spi_mmap.py index 7ef213137..39c55c487 100644 --- a/litex/soc/cores/spi/spi_mmap.py +++ b/litex/soc/cores/spi/spi_mmap.py @@ -361,7 +361,7 @@ def get_ctrl(self, name, slot=None, cs=None): class SPITXMMAP(LiteXModule): def __init__(self, ctrl, data_width=32, nslots=1, origin=0x0000_0000): - self.bus = bus = wishbone.Interface(data_width=data_width) + self.bus = bus = wishbone.Interface(data_width=data_width, address_width=32, addressing="word") self.source = source = stream.Endpoint(spi_layout( data_width = data_width, be_width = data_width//8, @@ -429,7 +429,7 @@ def __init__(self, ctrl, data_width=32, nslots=1, origin=0x0000_0000): class SPIRXMMAP(LiteXModule): def __init__(self, ctrl, data_width=32, nslots=1, origin=0x0000_0000): - self.bus = bus = wishbone.Interface(data_width=data_width) + self.bus = bus = wishbone.Interface(data_width=data_width, address_width=32, addressing="word") self.sink = sink = stream.Endpoint(spi_layout( data_width = data_width, be_width = data_width//8, diff --git a/litex/soc/cores/spi_opi.py b/litex/soc/cores/spi_opi.py index 851a99fac..0e1f68d31 100644 --- a/litex/soc/cores/spi_opi.py +++ b/litex/soc/cores/spi_opi.py @@ -435,7 +435,7 @@ def __init__(self, pads, bit of additional logic and pipelining, we can aggregate data into 32-bit words going into a 32-bit FIFO_SYNC_MACRO, which is what we do in this implementation. """) - self.bus = bus = wishbone.Interface() + self.bus = bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.command = CSRStorage(description="Write individual bits to issue special commands to SPI; setting multiple bits at once leads to undefined behavior.", fields=[ diff --git a/litex/soc/cores/uart.py b/litex/soc/cores/uart.py index 723337897..12ca5593f 100644 --- a/litex/soc/cores/uart.py +++ b/litex/soc/cores/uart.py @@ -310,7 +310,7 @@ class Stream2Wishbone(LiteXModule): def __init__(self, phy=None, clk_freq=None, data_width=32, address_width=32): self.sink = sink = stream.Endpoint([("data", 8)]) if phy is None else phy.source self.source = source = stream.Endpoint([("data", 8)]) if phy is None else phy.sink - self.wishbone = wishbone.Interface(data_width=data_width, adr_width=address_width) + self.wishbone = wishbone.Interface(data_width=data_width, address_width=address_width, addressing="word") # # # assert data_width in [8, 16, 32] diff --git a/litex/soc/cores/usb_ohci.py b/litex/soc/cores/usb_ohci.py index 2ca50daac..264eac726 100644 --- a/litex/soc/cores/usb_ohci.py +++ b/litex/soc/cores/usb_ohci.py @@ -26,8 +26,8 @@ def __init__(self, platform, pads, usb_clk_freq=48e6, dma_data_width=32): self.usb_clk_freq = int(usb_clk_freq) self.dma_data_width = dma_data_width - self.wb_ctrl = wb_ctrl = wishbone.Interface(data_width=32) - self.wb_dma = wb_dma = wishbone.Interface(data_width=dma_data_width) + self.wb_ctrl = wb_ctrl = wishbone.Interface(data_width=32, address_width=32, addressing="word") + self.wb_dma = wb_dma = wishbone.Interface(data_width=dma_data_width, address_width=32, addressing="word") self.interrupt = Signal() diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 6c2a0a652..3fd236338 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1627,7 +1627,9 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, else: mem_wb = wishbone.Interface( data_width = self.cpu.mem_axi.data_width, - adr_width = 32-log2_int(mem_bus.data_width//8)) + adr_width = 32-log2_int(mem_bus.data_width//8, + addressing = "word", + )) mem_a2w = axi.AXI2Wishbone( axi = mem_bus, wishbone = mem_wb, @@ -1664,7 +1666,7 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, port.data_width = 2**int(log2(port.data_width)) # Round to nearest power of 2. # Create Wishbone Slave. - wb_sdram = wishbone.Interface(data_width=self.bus.data_width) + wb_sdram = wishbone.Interface(data_width=self.bus.data_width, address_width=32, addressing="word") self.bus.add_slave(name="main_ram", slave=wb_sdram) # L2 Cache @@ -1676,7 +1678,7 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, l2_cache = wishbone.Cache( cachesize = l2_cache_size//4, master = wb_sdram, - slave = wishbone.Interface(l2_cache_data_width), + slave = wishbone.Interface(data_width=l2_cache_data_width, address_width=32, addressing="word"), reverse = l2_cache_reverse) if l2_cache_full_memory_we: l2_cache = FullMemoryWE()(l2_cache) @@ -1684,7 +1686,7 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, litedram_wb = self.l2_cache.slave self.add_config("L2_SIZE", l2_cache_size) else: - litedram_wb = wishbone.Interface(port.data_width) + litedram_wb = wishbone.Interface(data_width=port.data_width, address_width=32, addressing="word") self.submodules += wishbone.Converter(wb_sdram, litedram_wb) # Wishbone Slave <--> LiteDRAM bridge. @@ -1926,7 +1928,11 @@ def add_sdcard(self, name="sdcard", sdcard_name="sdcard", mode="read+write", use # Block2Mem DMA. if "read" in mode: self.check_if_exists(f"{name}_block2mem") - bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) + bus = wishbone.Interface( + data_width = self.bus.data_width, + adr_width = self.bus.get_address_width(standard="wishbone"), + addressing = "word", + ) sdcard_block2mem = SDBlock2MemDMA(bus=bus, endianness=self.cpu.endianness) self.add_module(name=f"{name}_block2mem", module=sdcard_block2mem) self.comb += sdcard_core.source.connect(sdcard_block2mem.sink) @@ -1936,7 +1942,11 @@ def add_sdcard(self, name="sdcard", sdcard_name="sdcard", mode="read+write", use # Mem2Block DMA. if "write" in mode: self.check_if_exists(f"{name}_mem2block") - bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) + bus = wishbone.Interface( + data_width = self.bus.data_width, + adr_width = self.bus.get_address_width(standard="wishbone"), + addressing = "word", + ) sdcard_mem2block = SDMem2BlockDMA(bus=bus, endianness=self.cpu.endianness) self.add_module(name=f"{name}_mem2block", module=sdcard_mem2block) self.comb += sdcard_mem2block.source.connect(sdcard_core.sink) @@ -2007,11 +2017,16 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) # Sector2Mem DMA. if "read" in mode: self.check_if_exists(f"{name}_sector2mem") - bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) + bus = wishbone.Interface( + data_width = self.bus.data_width, + adr_width = self.bus.get_address_width(standard="wishbone"), + addressing = "word", + ) sata_sector2mem = LiteSATASector2MemDMA( port = sata_crossbar.get_port(), bus = bus, - endianness = self.cpu.endianness) + endianness = self.cpu.endianness, + ) self.add_module(name=f"{name}_sector2mem", module=sata_sector2mem) dma_bus = getattr(self, "dma_bus", self.bus) dma_bus.add_master(name=f"{name}_sector2mem", master=bus) @@ -2019,11 +2034,16 @@ def add_sata(self, name="sata", phy=None, mode="read+write", with_identify=True) # Mem2Sector DMA. if "write" in mode: self.check_if_exists(f"{name}_mem2sector") - bus = wishbone.Interface(data_width=self.bus.data_width, adr_width=self.bus.get_address_width(standard="wishbone")) + bus = wishbone.Interface( + data_width = self.bus.data_width, + adr_width = self.bus.get_address_width(standard="wishbone"), + addressing = "word", + ) sata_mem2sector = LiteSATAMem2SectorDMA( bus = bus, port = sata_crossbar.get_port(), - endianness = self.cpu.endianness) + endianness = self.cpu.endianness, + ) self.add_module(name=f"{name}_mem2sector", module=sata_mem2sector) dma_bus = getattr(self, "dma_bus", self.bus) dma_bus.add_master(name=f"{name}_mem2sector", master=bus) diff --git a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py index 0e85f801a..ef742d83b 100644 --- a/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py +++ b/litex/soc/interconnect/avalon/avalon_mm_to_wishbone.py @@ -17,7 +17,7 @@ class AvalonMM2Wishbone(Module): def __init__(self, data_width=32, avalon_address_width=32, wishbone_address_width=32, wishbone_base_address=0x0, burst_increment=1, avoid_combinatorial_loop=False): self.a2w_avl = avl = AvalonMMInterface (data_width=data_width, adr_width=avalon_address_width) - self.a2w_wb = wb = wishbone.Interface(data_width=data_width, adr_width=wishbone_address_width, bursting=True) + self.a2w_wb = wb = wishbone.Interface(data_width=data_width, adr_width=wishbone_address_width, addressing="word", bursting=True) read_access = Signal() readdatavalid = Signal() diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 1bd05bbd7..e19d55939 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -67,7 +67,7 @@ def __init__(self, data_width=32, adr_width=30, bursting=False, addressing="word @staticmethod def like(other): - return Interface(len(other.dat_w)) + return Interface(data_width=other.data_width, address_width=other.address_width, addressing=other.addressing) def _do_transaction(self): yield self.cyc.eq(1) @@ -395,7 +395,7 @@ def __init__(self, master, slave): class SRAM(Module): def __init__(self, mem_or_size, read_only=None, write_only=None, init=None, bus=None, name=None): if bus is None: - bus = Interface() + bus = Interface(data_width=32, address_width=32, addressing="word") assert bus.addressing == "word" # FIXME: Test/Remove byte addressing limitation. self.bus = bus bus_data_width = len(self.bus.dat_r) diff --git a/litex/tools/litex_periph_gen.py b/litex/tools/litex_periph_gen.py index 5e235ad21..177832c3a 100755 --- a/litex/tools/litex_periph_gen.py +++ b/litex/tools/litex_periph_gen.py @@ -76,8 +76,8 @@ def __init__(self, name="litex_soc", sys_clk_freq=int(50e6), **kwargs): # MMAP Slave Interface --------------------------------------------------------------------- s_bus = { - "wishbone" : wishbone.Interface(), - "axi-lite" : axi.AXILiteInterface(), + "wishbone" : wishbone.Interface(data_width=32, address_width=32, addressing="word"), + "axi-lite" : axi.AXILiteInterface(data_width=32, address_width=32), }[kwargs["bus_standard"]] self.bus.add_master(name="mmap_s", master=s_bus) @@ -88,8 +88,8 @@ def __init__(self, name="litex_soc", sys_clk_freq=int(50e6), **kwargs): # MMAP Master Interface -------------------------------------------------------------------- # FIXME: Allow Region configuration. m_bus = { - "wishbone" : wishbone.Interface(), - "axi-lite" : axi.AXILiteInterface(), + "wishbone" : wishbone.Interface(data_width=32, address_width=32, addressing="word"), + "axi-lite" : axi.AXILiteInterface(data_width=32, address_width=32), }[kwargs["bus_standard"]] wb_region = SoCRegion(origin=0x2000_0000, size=0x1000_0000, cached=True) # FIXME. diff --git a/test/test_axi.py b/test/test_axi.py index 4771aa791..fd2dae570 100644 --- a/test/test_axi.py +++ b/test/test_axi.py @@ -248,7 +248,7 @@ def reads_response_data_generator(axi_port, reads): class DUT(Module): def __init__(self): self.axi = AXIInterface(data_width=32, address_width=32, id_width=8) - self.wishbone = wishbone.Interface(data_width=32, adr_width=30) + self.wishbone = wishbone.Interface(data_width=32, adr_width=30, addressing="word") axi2wishbone = AXI2Wishbone(self.axi, self.wishbone) self.submodules += axi2wishbone @@ -343,7 +343,7 @@ class DUT(LiteXModule): def __init__(self, dw_from=64, dw_to=32): self.axi_master = AXIInterface(data_width=dw_from) axi_slave = AXIInterface(data_width=dw_to) - wb_slave = wishbone.Interface(data_width=dw_to, address_width=axi_slave.address_width) + wb_slave = wishbone.Interface(data_width=dw_to, address_width=axi_slave.address_width, addressing="word") self.converter = AXIConverter(self.axi_master, axi_slave) self.axi2wb = AXI2Wishbone(axi_slave, wb_slave) self.mem = wishbone.SRAM(1024, bus=wb_slave, init=range(256)) diff --git a/test/test_axi_lite.py b/test/test_axi_lite.py index 49548d055..3a5c819e5 100644 --- a/test/test_axi_lite.py +++ b/test/test_axi_lite.py @@ -149,13 +149,20 @@ class TestAXILite(unittest.TestCase): def test_wishbone2axilite2wishbone(self, data_width=32, address_width=32): class DUT(Module): def __init__(self): - self.wishbone = wishbone.Interface(data_width=data_width, - adr_width=address_width - log2_int(data_width // 8)) + self.wishbone = wishbone.Interface( + data_width = data_width, + adr_width = address_width - log2_int(data_width // 8), + addressing = "word", + ) # # # axi_lite = AXILiteInterface(data_width=data_width, address_width=address_width) - wb = wishbone.Interface(data_width=data_width, adr_width=address_width - log2_int(data_width // 8)) + wb = wishbone.Interface( + data_width = data_width, + adr_width = address_width - log2_int(data_width // 8), + addressing = "word", + ) wishbone2axi = Wishbone2AXILite(self.wishbone, axi_lite) axi2wishbone = AXILite2Wishbone(axi_lite, wb) diff --git a/test/test_wishbone.py b/test/test_wishbone.py index ed91dced6..c9a71f66e 100644 --- a/test/test_wishbone.py +++ b/test/test_wishbone.py @@ -26,8 +26,8 @@ def generator(dut): class DUT(Module): def __init__(self): - self.wb16 = wishbone.Interface(data_width=16) - wb32 = wishbone.Interface(data_width=32) + self.wb16 = wishbone.Interface(data_width=16, address_width=32, addressing="word") + wb32 = wishbone.Interface(data_width=32, address_width=32, addressing="word") up_converter = wishbone.UpConverter(self.wb16, wb32) self.submodules += up_converter wishbone_mem = wishbone.SRAM(32, bus=wb32) @@ -45,9 +45,9 @@ def generator(dut): class DUT(Module): def __init__(self): - self.wb32 = wishbone.Interface(data_width=32) - wb64 = wishbone.Interface(data_width=64) - wb32 = wishbone.Interface(data_width=32) + self.wb32 = wishbone.Interface(data_width=32, address_width=32, addressing="word") + wb64 = wishbone.Interface(data_width=64, address_width=32, addressing="word") + wb32 = wishbone.Interface(data_width=32, address_width=32, addressing="word") up_converter = wishbone.UpConverter(self.wb32, wb64) down_converter = wishbone.DownConverter(wb64, wb32) self.submodules += up_converter, down_converter @@ -70,7 +70,7 @@ def generator(dut): class DUT(Module): def __init__(self): - self.wb = wishbone.Interface(bursting=True) + self.wb = wishbone.Interface(data_width=32, address_width=32, addressing="word", bursting=True) wishbone_mem = wishbone.SRAM(32, bus=self.wb) self.submodules += wishbone_mem @@ -91,7 +91,7 @@ def generator(dut): class DUT(Module): def __init__(self): - self.wb = wishbone.Interface(bursting=True) + self.wb = wishbone.Interface(data_width=32, address_width=32, addressing="word", bursting=True) wishbone_mem = wishbone.SRAM(32, bus=self.wb) self.submodules += wishbone_mem @@ -111,7 +111,7 @@ def generator(dut): class DUT(Module): def __init__(self): - self.wb = wishbone.Interface(bursting=True) + self.wb = wishbone.Interface(data_width=32, address_width=32, addressing="word", bursting=True) wishbone_mem = wishbone.SRAM(32, bus=self.wb) self.submodules += wishbone_mem From 9ccac7f7e0d4cf2aeceabb318f3d78c003eaafcc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 11:03:33 +0200 Subject: [PATCH 268/454] interconnect/stream: Switch to LiteXModule. --- litex/soc/interconnect/stream.py | 56 ++++++++++++++++---------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index 18eca1533..797f1999f 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -13,7 +13,7 @@ from migen.genlib import fifo from migen.genlib.cdc import MultiReg, PulseSynchronizer, AsyncResetSynchronizer -from litex.gen import LiteXContext +from litex.gen import * from litex.soc.interconnect.csr import * @@ -108,7 +108,7 @@ def get_single_ep(obj, filt): return list(eps.items())[0] -class BinaryActor(Module): +class BinaryActor(LiteXModule): def __init__(self, *args, **kwargs): self.build_binary_control(self.sink, self.source, *args, **kwargs) @@ -167,7 +167,7 @@ def build_binary_control(self, sink, source, latency): # FIFO --------------------------------------------------------------------------------------------- -class _FIFOWrapper(Module): +class _FIFOWrapper(LiteXModule): def __init__(self, fifo_class, layout, depth): self.sink = sink = Endpoint(layout) self.source = source = Endpoint(layout) @@ -182,7 +182,7 @@ def __init__(self, fifo_class, layout, depth): ("last", 1) ] - self.submodules.fifo = fifo = fifo_class(layout_len(fifo_layout), depth) + self.fifo = fifo = fifo_class(layout_len(fifo_layout), depth) fifo_in = Record(fifo_layout) fifo_out = Record(fifo_layout) self.comb += [ @@ -244,7 +244,7 @@ def __init__(self, layout, depth=None, buffered=False): # ClockDomainCrossing ------------------------------------------------------------------------------ -class ClockDomainCrossing(Module): +class ClockDomainCrossing(LiteXModule): def __init__(self, layout, cd_from="sys", cd_to="sys", depth=None, buffered=False, with_common_rst=False): self.sink = Endpoint(layout) self.source = Endpoint(layout) @@ -288,7 +288,7 @@ def __init__(self, layout, cd_from="sys", cd_to="sys", depth=None, buffered=Fals # Mux/Demux ---------------------------------------------------------------------------------------- -class Multiplexer(Module): +class Multiplexer(LiteXModule): def __init__(self, layout, n): self.source = Endpoint(layout) sinks = [] @@ -306,7 +306,7 @@ def __init__(self, layout, n): self.comb += Case(self.sel, cases) -class Demultiplexer(Module): +class Demultiplexer(LiteXModule): def __init__(self, layout, n): self.sink = Endpoint(layout) sources = [] @@ -326,7 +326,7 @@ def __init__(self, layout, n): # Gate --------------------------------------------------------------------------------------------- -class Gate(Module): +class Gate(LiteXModule): def __init__(self, layout, sink_ready_when_disabled=False): self.sink = Endpoint(layout) self.source = Endpoint(layout) @@ -344,7 +344,7 @@ def __init__(self, layout, sink_ready_when_disabled=False): # Converter ---------------------------------------------------------------------------------------- -class _UpConverter(Module): +class _UpConverter(LiteXModule): def __init__(self, nbits_from, nbits_to, ratio, reverse): self.sink = sink = Endpoint([("data", nbits_from)]) self.source = source = Endpoint([("data", nbits_to), ("valid_token_count", bits_for(ratio))]) @@ -399,7 +399,7 @@ def __init__(self, nbits_from, nbits_to, ratio, reverse): self.sync += If(load_part, source.valid_token_count.eq(demux + 1)) -class _DownConverter(Module): +class _DownConverter(LiteXModule): def __init__(self, nbits_from, nbits_to, ratio, reverse): self.sink = sink = Endpoint([("data", nbits_from)]) self.source = source = Endpoint([("data", nbits_to), ("valid_token_count", 1)]) @@ -439,7 +439,7 @@ def __init__(self, nbits_from, nbits_to, ratio, reverse): self.comb += source.valid_token_count.eq(last) -class _IdentityConverter(Module): +class _IdentityConverter(LiteXModule): def __init__(self, nbits_from, nbits_to, ratio, reverse): self.sink = sink = Endpoint([("data", nbits_from)]) self.source = source = Endpoint([("data", nbits_to), ("valid_token_count", 1)]) @@ -470,7 +470,7 @@ def _get_converter_ratio(nbits_from, nbits_to): return converter_cls, ratio -class Converter(Module): +class Converter(LiteXModule): def __init__(self, nbits_from, nbits_to, reverse = False, report_valid_token_count = False): @@ -490,7 +490,7 @@ def __init__(self, nbits_from, nbits_to, self.comb += converter.source.connect(self.source, omit=set(["valid_token_count"])) -class StrideConverter(Module): +class StrideConverter(LiteXModule): def __init__(self, description_from, description_to, reverse=False): self.sink = sink = Endpoint(description_from) self.source = source = Endpoint(description_to) @@ -560,7 +560,7 @@ def inc_mod(s, m): return [s.eq(s + 1), If(s == (m -1), s.eq(0))] -class Gearbox(Module): +class Gearbox(LiteXModule): def __init__(self, i_dw, o_dw, msb_first=True): self.sink = sink = Endpoint([("data", i_dw)]) self.source = source = Endpoint([("data", o_dw)]) @@ -647,7 +647,7 @@ def __init__(self, dw, shift=None): # Monitor ------------------------------------------------------------------------------------------ -class Monitor(Module, AutoCSR): +class Monitor(LiteXModule): def __init__(self, endpoint, count_width=32, clock_domain="sys", with_tokens = False, with_overflows = False, @@ -707,7 +707,7 @@ def __init__(self, reset, latch, enable, count): # Tokens Count ----------------------------------------------------------------------------- if with_tokens: - self.submodules.token_counter = MonitorCounter( + self.token_counter = MonitorCounter( reset = reset, latch = latch, enable = endpoint.valid & endpoint.ready, @@ -716,7 +716,7 @@ def __init__(self, reset, latch, enable, count): # Overflows Count (only useful when endpoint is expected to always be ready) --------------- if with_overflows: - self.submodules.overflow_counter = MonitorCounter( + self.overflow_counter = MonitorCounter( reset = reset, latch = latch, enable = endpoint.valid & ~endpoint.ready, @@ -725,7 +725,7 @@ def __init__(self, reset, latch, enable, count): # Underflows Count (only useful when endpoint is expected to always be valid) -------------- if with_underflows: - self.submodules.underflow_counter = MonitorCounter( + self.underflow_counter = MonitorCounter( reset = reset, latch = latch, enable = ~endpoint.valid & endpoint.ready, @@ -734,7 +734,7 @@ def __init__(self, reset, latch, enable, count): # Packets Count ---------------------------------------------------------------------------- if with_packets: - self.submodules.packet_counter = MonitorCounter( + self.packet_counter = MonitorCounter( reset = reset, latch = latch, enable = endpoint.valid & getattr(endpoint, packet_delimiter) & endpoint.ready, @@ -743,7 +743,7 @@ def __init__(self, reset, latch, enable, count): # Pipe --------------------------------------------------------------------------------------------- -class PipeValid(Module): +class PipeValid(LiteXModule): """Pipe valid/payload to cut timing path""" def __init__(self, layout): self.sink = sink = Endpoint(layout) @@ -764,7 +764,7 @@ def __init__(self, layout): self.comb += sink.ready.eq(~source.valid | source.ready) -class PipeReady(Module): +class PipeReady(LiteXModule): """Pipe ready to cut timing path""" def __init__(self, layout): self.sink = sink = Endpoint(layout) @@ -796,7 +796,7 @@ def __init__(self, layout): # Buffer ------------------------------------------------------------------------------------------- -class Buffer(Module): +class Buffer(LiteXModule): """Pipe valid/payload and/or ready to cut timing path""" def __init__(self, layout, pipe_valid=True, pipe_ready=False): self.sink = sink = Endpoint(layout) @@ -808,16 +808,16 @@ def __init__(self, layout, pipe_valid=True, pipe_ready=False): # Pipe Valid (Optional). if pipe_valid: - self.submodules.pipe_valid = PipeValid(layout) + self.pipe_valid = PipeValid(layout) pipeline.append(self.pipe_valid) # Pipe Ready (Optional). if pipe_ready: - self.submodules.pipe_ready = PipeReady(layout) + self.pipe_ready = PipeReady(layout) pipeline.append(self.pipe_ready) # Buffer Pipeline. - self.submodules.pipeline = Pipeline( + self.pipeline = Pipeline( sink, *pipeline, source @@ -845,7 +845,7 @@ def __init__(self, layout_from, layout_to, reverse_from=False, reverse_to=False) # Unpack/Pack -------------------------------------------------------------------------------------- -class Unpack(Module): +class Unpack(LiteXModule): def __init__(self, n, layout_to, reverse=False): self.source = source = Endpoint(layout_to) description_from = Endpoint(layout_to).description @@ -889,7 +889,7 @@ def __init__(self, n, layout_to, reverse=False): ] -class Pack(Module): +class Pack(LiteXModule): def __init__(self, layout_from, n, reverse=False): self.sink = sink = Endpoint(layout_from) description_to = Endpoint(layout_from).description @@ -941,7 +941,7 @@ def __init__(self, layout_from, n, reverse=False): # Pipeline ----------------------------------------------------------------------------------------- -class Pipeline(Module): +class Pipeline(LiteXModule): def __init__(self, *modules): self.modules = list(modules) if len(self.modules): From fa521f5c89f65d265d80bfcb3cc1d6f54a863262 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 11:05:37 +0200 Subject: [PATCH 269/454] interconnect/wishbone: Switch to LiteXModule. --- litex/soc/interconnect/wishbone.py | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index e19d55939..5b4323ef5 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -128,7 +128,7 @@ def connect_to_pads(self, pads, mode="master"): # Wishbone Timeout --------------------------------------------------------------------------------- -class Timeout(Module): +class Timeout(LiteXModule): def __init__(self, master, cycles): self.error = Signal() @@ -158,19 +158,19 @@ def get_check_parameters(ports): return data_width -class InterconnectPointToPoint(Module): +class InterconnectPointToPoint(LiteXModule): def __init__(self, master, slave): self.comb += master.connect(slave) -class Arbiter(Module): +class Arbiter(LiteXModule): def __init__(self, masters=None, target=None, controllers=None): assert target is not None assert (masters is not None) or (controllers is not None) if controllers is not None: masters = controllers - self.submodules.rr = roundrobin.RoundRobin(len(masters)) + self.rr = roundrobin.RoundRobin(len(masters)) # mux master->slave signals for name, size, direction in _layout: @@ -194,7 +194,7 @@ def __init__(self, masters=None, target=None, controllers=None): self.comb += self.rr.request.eq(Cat(*reqs)) -class Decoder(Module): +class Decoder(LiteXModule): # slaves is a list of pairs: # 0) function that takes the address signal and returns a FHDL expression # that evaluates to 1 when the slave is selected and 0 otherwise. @@ -235,17 +235,17 @@ def __init__(self, master, slaves, register=False): self.comb += master.dat_r.eq(Reduce("OR", masked)) -class InterconnectShared(Module): +class InterconnectShared(LiteXModule): def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) shared = Interface(data_width=data_width) - self.submodules.arbiter = Arbiter(masters, shared) - self.submodules.decoder = Decoder(shared, slaves, register) + self.arbiter = Arbiter(masters, shared) + self.decoder = Decoder(shared, slaves, register) if timeout_cycles is not None: - self.submodules.timeout = Timeout(shared, timeout_cycles) + self.timeout = Timeout(shared, timeout_cycles) -class Crossbar(Module): +class Crossbar(LiteXModule): def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) matches, busses = zip(*slaves) @@ -260,7 +260,7 @@ def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): # Wishbone Data Width Converter -------------------------------------------------------------------- -class DownConverter(Module): +class DownConverter(LiteXModule): """DownConverter This module splits Wishbone accesses from a master interface to a smaller slave interface. @@ -336,7 +336,7 @@ def __init__(self, master, slave): self.comb += master.dat_r.eq(Cat(dat_r[dw_to:], slave.dat_r)) self.sync += If(slave.ack | skip, dat_r.eq(master.dat_r)) -class UpConverter(Module): +class UpConverter(LiteXModule): """UpConverter""" def __init__(self, master, slave): # Parameters/Checks. @@ -359,7 +359,7 @@ def __init__(self, master, slave): ] self.comb += Case(master.adr[:int(log2(ratio))], cases) -class Converter(Module): +class Converter(LiteXModule): """Converter This module is a wrapper for DownConverter and UpConverter. @@ -392,7 +392,7 @@ def __init__(self, master, slave): # Wishbone SRAM ------------------------------------------------------------------------------------ -class SRAM(Module): +class SRAM(LiteXModule): def __init__(self, mem_or_size, read_only=None, write_only=None, init=None, bus=None, name=None): if bus is None: bus = Interface(data_width=32, address_width=32, addressing="word") @@ -515,7 +515,7 @@ def __init__(self, mem_or_size, read_only=None, write_only=None, init=None, bus= # Wishbone To CSR ---------------------------------------------------------------------------------- -class Wishbone2CSR(Module): +class Wishbone2CSR(LiteXModule): def __init__(self, bus_wishbone=None, bus_csr=None, register=True): self.csr = bus_csr if self.csr is None: @@ -535,7 +535,7 @@ def __init__(self, bus_wishbone=None, bus_csr=None, register=True): # Registered Access. if register: - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(self.csr.dat_w, self.wishbone.dat_w), If(self.wishbone.cyc & self.wishbone.stb, @@ -556,7 +556,7 @@ def __init__(self, bus_wishbone=None, bus_csr=None, register=True): ) # Un-Registered Access. else: - self.submodules.fsm = fsm = FSM(reset_state="WRITE-READ") + self.fsm = fsm = FSM(reset_state="WRITE-READ") fsm.act("WRITE-READ", self.csr.dat_w.eq(self.wishbone.dat_w), If(self.wishbone.cyc & self.wishbone.stb, @@ -573,7 +573,7 @@ def __init__(self, bus_wishbone=None, bus_csr=None, register=True): # Wishbone Cache ----------------------------------------------------------------------------------- -class Cache(Module): +class Cache(LiteXModule): """Cache This module is a write-back wishbone cache that can be used as a L2 cache. @@ -581,7 +581,7 @@ class Cache(Module): """ def __init__(self, cachesize, master, slave, reverse=True): self.master = master - self.slave = slave + self.slave = slave # # # @@ -671,7 +671,7 @@ def word_is_last(word): return 1 # Control FSM - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", If(master.cyc & master.stb, NextState("TEST_HIT") From a2820cba9633e31ae66ec452d5e6174febdb0c39 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 11:07:31 +0200 Subject: [PATCH 270/454] interconnect/packet: Switch to LiteXModule. --- litex/soc/interconnect/packet.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/litex/soc/interconnect/packet.py b/litex/soc/interconnect/packet.py index 2886164de..4d7f7b12a 100644 --- a/litex/soc/interconnect/packet.py +++ b/litex/soc/interconnect/packet.py @@ -9,8 +9,6 @@ from migen import * from migen.genlib.roundrobin import * -from migen.genlib.record import * -from migen.genlib.fsm import FSM, NextState from litex.gen import * @@ -18,7 +16,7 @@ # Status ------------------------------------------------------------------------------------------- -class Status(Module): +class Status(LiteXModule): def __init__(self, endpoint): self.first = Signal(reset=1) self.last = Signal() @@ -38,7 +36,7 @@ def __init__(self, endpoint): # Arbiter ------------------------------------------------------------------------------------------ -class Arbiter(Module): +class Arbiter(LiteXModule): def __init__(self, masters, slave): if len(masters) == 0: pass @@ -46,7 +44,7 @@ def __init__(self, masters, slave): self.grant = Signal() self.comb += masters.pop().connect(slave) else: - self.submodules.rr = RoundRobin(len(masters)) + self.rr = RoundRobin(len(masters)) self.grant = self.rr.grant cases = {} for i, master in enumerate(masters): @@ -58,7 +56,7 @@ def __init__(self, masters, slave): # Dispatcher --------------------------------------------------------------------------------------- -class Dispatcher(Module): +class Dispatcher(LiteXModule): def __init__(self, master, slaves, one_hot=False): if len(slaves) == 0: self.sel = Signal() @@ -157,7 +155,7 @@ def decode(self, signal, obj): # Packetizer --------------------------------------------------------------------------------------- -class Packetizer(Module): +class Packetizer(LiteXModule): def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) @@ -186,7 +184,7 @@ def __init__(self, sink_description, source_description, header): self.sync += If(sr_shift, sr.eq(sr[data_width:])) # FSM. - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm_from_idle = Signal() fsm.act("IDLE", sink.ready.eq(1), @@ -260,7 +258,7 @@ def __init__(self, sink_description, source_description, header): # Depacketizer ------------------------------------------------------------------------------------- -class Depacketizer(Module): +class Depacketizer(LiteXModule): def __init__(self, sink_description, source_description, header): self.sink = sink = stream.Endpoint(sink_description) self.source = source = stream.Endpoint(source_description) @@ -294,7 +292,7 @@ def __init__(self, sink_description, source_description, header): self.comb += header.decode(self.header, source) # FSM. - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.fsm = fsm = FSM(reset_state="IDLE") fsm_from_idle = Signal() fsm.act("IDLE", sink.ready.eq(1), @@ -361,7 +359,7 @@ def __init__(self, sink_description, source_description, header): # PacketFIFO --------------------------------------------------------------------------------------- -class PacketFIFO(Module): +class PacketFIFO(LiteXModule): def __init__(self, layout, payload_depth, param_depth=None, buffered=False): self.sink = sink = stream.Endpoint(layout) self.source = source = stream.Endpoint(layout) @@ -380,8 +378,8 @@ def __init__(self, layout, payload_depth, param_depth=None, buffered=False): payload_description = stream.EndpointDescription(payload_layout=payload_layout) param_description = stream.EndpointDescription(param_layout=param_layout) param_depth = param_depth + 1 # +1 to allow dequeuing current while enqueuing next. - self.submodules.payload_fifo = payload_fifo = stream.SyncFIFO(payload_description, payload_depth, buffered) - self.submodules.param_fifo = param_fifo = stream.SyncFIFO(param_description, param_depth, buffered) + self.payload_fifo = payload_fifo = stream.SyncFIFO(payload_description, payload_depth, buffered) + self.param_fifo = param_fifo = stream.SyncFIFO(param_description, param_depth, buffered) # Connect Sink to FIFOs. self.comb += [ From 48f27707d1fef4eb7d2d8266d2c1884e7981b70b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 11:16:55 +0200 Subject: [PATCH 271/454] soc/cores: Make sure all Modules are switched to LiteXModule. --- litex/soc/cores/clock/lattice_nx.py | 2 +- litex/soc/cores/cpu/cv32e41p/core.py | 8 ++++---- litex/soc/cores/cpu/gowin_emcu/core.py | 2 +- litex/soc/cores/cpu/ibex/core.py | 2 +- litex/soc/cores/cpu/microwatt/core.py | 2 +- litex/soc/cores/cpu/openc906/core.py | 2 +- litex/soc/cores/cpu/vexriscv/core.py | 2 +- litex/soc/cores/emif.py | 1 + litex/soc/cores/spi_opi.py | 1 + 9 files changed, 12 insertions(+), 10 deletions(-) diff --git a/litex/soc/cores/clock/lattice_nx.py b/litex/soc/cores/clock/lattice_nx.py index 429b49172..6702461f1 100644 --- a/litex/soc/cores/clock/lattice_nx.py +++ b/litex/soc/cores/clock/lattice_nx.py @@ -106,7 +106,7 @@ def do_finalize(self): # Lattice / NX PLL --------------------------------------------------------------------------------- -class NXPLL(Module): +class NXPLL(LiteXModule): nclkouts_max = 5 clki_div_range = ( 1, 128+1) clkfb_div_range = ( 1, 128+1) diff --git a/litex/soc/cores/cpu/cv32e41p/core.py b/litex/soc/cores/cpu/cv32e41p/core.py index 0345c9126..13bfa9cff 100644 --- a/litex/soc/cores/cpu/cv32e41p/core.py +++ b/litex/soc/cores/cpu/cv32e41p/core.py @@ -73,7 +73,7 @@ def add_manifest_sources(platform, manifest): # OBI <> Wishbone ---------------------------------------------------------------------------------- -class OBI2Wishbone(Module): +class OBI2Wishbone(LiteXModule): def __init__(self, obi, wb): addr = Signal.like(obi.addr) be = Signal.like(obi.be) @@ -123,7 +123,7 @@ def __init__(self, obi, wb): ) ) -class Wishbone2OBI(Module): +class Wishbone2OBI(LiteXModule): def __init__(self, wb, obi): self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", @@ -147,7 +147,7 @@ def __init__(self, wb, obi): # Wishbone <> APB ---------------------------------------------------------------------------------- -class Wishbone2APB(Module): +class Wishbone2APB(LiteXModule): def __init__(self, wb, apb): self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", @@ -171,7 +171,7 @@ def __init__(self, wb, apb): # Debug Module ------------------------------------------------------------------------------------- -class DebugModule(Module): +class DebugModule(LiteXModule): jtag_layout = [ ("tck", 1), ("tms", 1), diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 7af5ac90b..c8551b21c 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -13,7 +13,7 @@ # AHB Flash ---------------------------------------------------------------------------------------- -class AHBFlash(Module): +class AHBFlash(LiteXModule): def __init__(self, bus): addr = Signal(13) read = Signal() diff --git a/litex/soc/cores/cpu/ibex/core.py b/litex/soc/cores/cpu/ibex/core.py index b3e88077e..d3010e9b5 100644 --- a/litex/soc/cores/cpu/ibex/core.py +++ b/litex/soc/cores/cpu/ibex/core.py @@ -45,7 +45,7 @@ ("rdata", 32), ] -class OBI2Wishbone(Module): +class OBI2Wishbone(LiteXModule): def __init__(self, obi, wb): addr = Signal.like(obi.addr) be = Signal.like(obi.be) diff --git a/litex/soc/cores/cpu/microwatt/core.py b/litex/soc/cores/cpu/microwatt/core.py index e32648b5f..99316f89b 100644 --- a/litex/soc/cores/cpu/microwatt/core.py +++ b/litex/soc/cores/cpu/microwatt/core.py @@ -236,7 +236,7 @@ def do_finalize(self): # XICS Slave --------------------------------------------------------------------------------------- -class XICSSlave(Module, AutoCSR): +class XICSSlave(LiteXModule): def __init__(self, platform, core_irq_out=Signal(), int_level_in=Signal(16), variant="standard"): self.variant = variant diff --git a/litex/soc/cores/cpu/openc906/core.py b/litex/soc/cores/cpu/openc906/core.py index 4e6846235..06d32e998 100644 --- a/litex/soc/cores/cpu/openc906/core.py +++ b/litex/soc/cores/cpu/openc906/core.py @@ -34,7 +34,7 @@ # Wishbone <> APB ---------------------------------------------------------------------------------- -class Wishbone2APB(Module): +class Wishbone2APB(LiteXModule): def __init__(self, wb, apb): assert wb.data_width == 32 self.fsm = fsm = FSM(reset_state="IDLE") diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index 42bc67dca..3145a7e95 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -82,7 +82,7 @@ # VexRiscv Timer ----------------------------------------------------------------------------------- -class VexRiscvTimer(Module, AutoCSR): +class VexRiscvTimer(LiteXModule): def __init__(self): self._latch = CSR() self._time = CSRStatus(64) diff --git a/litex/soc/cores/emif.py b/litex/soc/cores/emif.py index 923a30e99..bde48b15e 100644 --- a/litex/soc/cores/emif.py +++ b/litex/soc/cores/emif.py @@ -11,6 +11,7 @@ from litex.soc.interconnect import wishbone +# EMIF (External Memory Interface) ----------------------------------------------------------------- class EMIF(LiteXModule): """External Memory Interface core diff --git a/litex/soc/cores/spi_opi.py b/litex/soc/cores/spi_opi.py index 0e1f68d31..5b628977f 100644 --- a/litex/soc/cores/spi_opi.py +++ b/litex/soc/cores/spi_opi.py @@ -14,6 +14,7 @@ from litex.soc.integration.doc import AutoDoc, ModuleDoc +# 7-Series SPI OPI --------------------------------------------------------------------------------- class S7SPIOPI(LiteXModule): def __init__(self, pads, From 63159aa187a8bc074ba08d88943f0629c76d9d52 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 11:29:38 +0200 Subject: [PATCH 272/454] soc/cores: Minor cosmetic changes. --- litex/soc/cores/code_8b10b.py | 3 +-- litex/soc/cores/dma.py | 8 ++------ litex/soc/cores/esc.py | 2 +- litex/soc/cores/spi/spi_mmap.py | 7 +++---- litex/soc/cores/uart.py | 7 ++----- litex/soc/cores/usb_fifo.py | 30 +++++++++++++----------------- litex/soc/cores/video.py | 10 +++++----- 7 files changed, 27 insertions(+), 40 deletions(-) diff --git a/litex/soc/cores/code_8b10b.py b/litex/soc/cores/code_8b10b.py index 5f218e016..227e39f9a 100644 --- a/litex/soc/cores/code_8b10b.py +++ b/litex/soc/cores/code_8b10b.py @@ -352,8 +352,7 @@ def __init__(self, nwords=1): # # # # Encoders - encoder = Encoder(nwords, True) - self.submodules += encoder + self.encoder = encoder = Encoder(nwords, True) # Control self.comb += encoder.ce.eq(self.pipe_ce) diff --git a/litex/soc/cores/dma.py b/litex/soc/cores/dma.py index ec9b8d4de..735d102e6 100644 --- a/litex/soc/cores/dma.py +++ b/litex/soc/cores/dma.py @@ -92,9 +92,7 @@ def add_csr(self, default_base=0, default_length=0, default_enable=0, default_lo self.comb += self._offset.status.eq(offset) - fsm = FSM(reset_state="IDLE") - fsm = ResetInserter()(fsm) - self.submodules += fsm + self.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) self.comb += fsm.reset.eq(~self._enable.storage) fsm.act("IDLE", NextValue(offset, 0), @@ -177,9 +175,7 @@ def add_csr(self, default_base=0, default_length=0, default_enable=0, default_lo self.comb += self._offset.status.eq(offset) - fsm = FSM(reset_state="IDLE") - fsm = ResetInserter()(fsm) - self.submodules += fsm + self.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) self.comb += fsm.reset.eq(~self._enable.storage) fsm.act("IDLE", self.sink.ready.eq(ready_on_idle), diff --git a/litex/soc/cores/esc.py b/litex/soc/cores/esc.py index 21901aa9f..7ac56f663 100644 --- a/litex/soc/cores/esc.py +++ b/litex/soc/cores/esc.py @@ -87,7 +87,7 @@ class ESCDShot(LiteXModule): esc_pad = Signal() # Or platform.request("X") with X = esc pin name. from litex.soc.cores.esc import ESCDShot - self.submodules.esc0 = ESCDShot(esc_pad, sys_clk_freq, protocol="DSHOT150") + self.esc0 = ESCDShot(esc_pad, sys_clk_freq, protocol="DSHOT150") # Test script: # ------------ diff --git a/litex/soc/cores/spi/spi_mmap.py b/litex/soc/cores/spi/spi_mmap.py index 39c55c487..acb9300ed 100644 --- a/litex/soc/cores/spi/spi_mmap.py +++ b/litex/soc/cores/spi/spi_mmap.py @@ -102,8 +102,7 @@ def __init__(self, pads, data_width, sys_clk_freq, clk_settle_time=20e-9): clk_settle = WaitTimer(int(sys_clk_freq*clk_settle_time)) self.submodules += clk_settle - clk_fsm = FSM(reset_state="IDLE") - self.submodules += clk_fsm + self.clk_fsm = clk_fsm = FSM(reset_state="IDLE") clk_fsm.act("IDLE", If(self.start, NextState("SETTLE") @@ -686,12 +685,12 @@ def __init__(self, pads, data_width, sys_clk_freq, # Pipelines -------------------------------------------------------------------------------- - self.submodules += stream.Pipeline( + self.tx_pipeline = stream.Pipeline( tx_mmap, tx_fifo, tx_rx_engine ) - self.submodules += stream.Pipeline( + self.rx_pipeline = stream.Pipeline( tx_rx_engine, rx_fifo, rx_mmap diff --git a/litex/soc/cores/uart.py b/litex/soc/cores/uart.py index 12ca5593f..d6ab38a30 100644 --- a/litex/soc/cores/uart.py +++ b/litex/soc/cores/uart.py @@ -65,9 +65,7 @@ def __init__(self, pads, tuning_word): count = Signal(4, reset_less=True) # Clock Phase Accumulator. - clk_phase_accum = RS232ClkPhaseAccum(tuning_word, mode="tx") - self.submodules += clk_phase_accum - + self.clk_phase_accum = clk_phase_accum = RS232ClkPhaseAccum(tuning_word, mode="tx") # FSM self.fsm = fsm = FSM(reset_state="IDLE") @@ -113,8 +111,7 @@ def __init__(self, pads, tuning_word): count = Signal(4, reset_less=True) # Clock Phase Accumulator. - clk_phase_accum = RS232ClkPhaseAccum(tuning_word, mode="rx") - self.submodules += clk_phase_accum + self.clk_phase_accum = clk_phase_accum = RS232ClkPhaseAccum(tuning_word, mode="rx") # Resynchronize pads.rx and generate delayed version. rx = Signal() diff --git a/litex/soc/cores/usb_fifo.py b/litex/soc/cores/usb_fifo.py index 2ee0de2c9..25e97f00b 100644 --- a/litex/soc/cores/usb_fifo.py +++ b/litex/soc/cores/usb_fifo.py @@ -207,19 +207,17 @@ def __init__(self, pads, clk_freq, tWR = self.ns(30) # WR# active pulse width (t10) tMultiReg = 2 - # read fifo (FTDI --> SoC) - read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) + # Read fifo (FTDI --> SoC). + self.read_fifo = read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) - # write fifo (SoC --> FTDI) - write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) + # Write fifo (SoC --> FTDI). + self.write_fifo = write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth) - self.submodules += read_fifo, write_fifo - - # sink / source interfaces + # Sink / Source interfaces. self.sink = write_fifo.sink self.source = read_fifo.source - # read / write arbitration + # Read / Write arbitration. wants_write = Signal() wants_read = Signal() @@ -239,13 +237,11 @@ def __init__(self, pads, clk_freq, read_time_en, max_read_time = anti_starvation(self, read_time) write_time_en, max_write_time = anti_starvation(self, write_time) - fsm = FSM(reset_state="READ") - self.submodules += fsm - - read_done = Signal() + read_done = Signal() write_done = Signal() - commuting = Signal() + commuting = Signal() + self.fsm = fsm = FSM(reset_state="READ") fsm.act("READ", read_time_en.eq(1), If(wants_write & read_done, @@ -284,9 +280,9 @@ def __init__(self, pads, clk_freq, # read actions pads.rd_n.reset = 1 - read_fsm = FSM(reset_state="IDLE") - self.submodules += read_fsm read_counter = Signal(8) + + self.read_fsm = read_fsm = FSM(reset_state="IDLE") read_fsm.act("IDLE", read_done.eq(1), NextValue(read_counter, 0), @@ -317,9 +313,9 @@ def __init__(self, pads, clk_freq, # write actions pads.wr_n.reset = 1 - write_fsm = FSM(reset_state="IDLE") - self.submodules += write_fsm write_counter = Signal(8) + + self.write_fsm = write_fsm = FSM(reset_state="IDLE") write_fsm.act("IDLE", write_done.eq(1), NextValue(write_counter, 0), diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 76fe6ee77..30096931b 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -835,7 +835,7 @@ def __init__(self, pads, clock_domain="sys", pn_swap=[]): for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) - setattr(self.submodules, f"{color}_encoder", encoder) + self.add_module(name=f"{color}_encoder", module=encoder) self.comb += encoder.d.eq(getattr(sink, color)) self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) @@ -848,7 +848,7 @@ def __init__(self, pads, clock_domain="sys", pn_swap=[]): data_o = data_o, clock_domain = clock_domain, ) - setattr(self.submodules, f"{color}_serializer", serializer) + self.add_module(name=f"{color}_serializer", module=serializer) # HDMI (Gowin). @@ -872,7 +872,7 @@ def __init__(self, pads, clock_domain="sys", pn_swap=[]): for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) - setattr(self.submodules, f"{color}_encoder", encoder) + self.add_module(name=f"{color}_encoder", module=encoder) self.comb += encoder.d.eq(getattr(sink, color)) self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) @@ -916,7 +916,7 @@ def __init__(self, pads, clock_domain="sys"): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) - setattr(self.submodules, f"{color}_encoder", encoder) + self.add_module(name=f"{color}_encoder", module=encoder) self.comb += encoder.d.eq(getattr(sink, color)) self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) @@ -928,7 +928,7 @@ def __init__(self, pads, clock_domain="sys"): data_o = pad_o, clock_domain = clock_domain, ) - setattr(self.submodules, f"{color}_serializer", serializer) + self.add_module(name=f"{color}_serializer", module=serializer) pad_p = getattr(pads, f"data{channel}_p") pad_n = getattr(pads, f"data{channel}_n") self.specials += Instance("OBUFDS", i_I=pad_o, o_O=pad_p, o_OB=pad_n) From fa629b782f5dbfb857e430baca715446acb14542 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 11:40:31 +0200 Subject: [PATCH 273/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 035510b3d..4d795a814 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ -------- - liteeth/arp : Fixed response on table update. - litesata/us(p)sataphy : Fixed data_width=32 case. + - clock/lattice_ecp5 : Fixed phase calculation. [> Added -------- @@ -18,6 +19,7 @@ - soc/cores : Added Ti60F100 HyperRAM support. - build/xilinx : Added initial OpenXC7 support (and improved Yosys-NextPnr). - build/efinix : Added JTAG-UART/JTAGBone support. + - interconnect/wishbone : Added byte/word addressing support. [> Changed ---------- From 856d7452b31793bf90dc2f3e24bb5922dc8b2bbc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 12:26:54 +0200 Subject: [PATCH 274/454] gen/fhdl/module: Ensure Module/Special/ClockDomains are initialized before adding them as submodules/specials/clock_domains. --- litex/gen/fhdl/module.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/litex/gen/fhdl/module.py b/litex/gen/fhdl/module.py index 8a389cbe8..88fcd5081 100644 --- a/litex/gen/fhdl/module.py +++ b/litex/gen/fhdl/module.py @@ -20,6 +20,14 @@ class LiteXModule(Module, AutoCSR, AutoDoc): AutoDoc for CSR and documentation automation, respectively. """ + @staticmethod + def _is_class_instance(_obj, _cls): + # If obj is cls, it is not an instance and not initialized. + if _obj is _cls: + return False + # Else check if object is an instance of cls. + return isinstance(_obj, _cls) + def __setattr__(m, name, value): """ Overrides the default behavior of attribute assignment in Python. This method simplifies the @@ -33,13 +41,13 @@ def __setattr__(m, name, value): # Automatic handling for adding submodules, specials, and clock domains in LiteX. # - m.module_x = .. equivalent of Migen's m.submodules.module_x = .. # Note: Do an exception for CSRs that have a specific collection mechanism. - elif (isinstance(value, Module) and ((name, value) not in m._submodules) and (not isinstance(value, _CSRBase))): + elif (m._is_class_instance(value, Module) and ((name, value) not in m._submodules) and (not isinstance(value, _CSRBase))): setattr(m.submodules, name, value) # - m.special_x = .. equivalent of Migen's m.specials.special_x = .. - elif isinstance(value, Special) and (value not in m._fragment.specials): + elif m._is_class_instance(value, Special) and (value not in m._fragment.specials): setattr(m.specials, name, value) # - m.cd_x = .. equivalent of Migen's m.clock_domains.cd_x = .. - elif isinstance(value, ClockDomain) and (value not in m._fragment.clock_domains): + elif m._is_class_instance(value, ClockDomain) and (value not in m._fragment.clock_domains): setattr(m.clock_domains, name, value) # Else use default __setattr__. else: From c44b906d9fccce956dcfce8dfa779d991130356c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 12:33:37 +0200 Subject: [PATCH 275/454] interconnect/stream: Revert Convert to Module, needs to be investigated. --- litex/soc/interconnect/stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index 797f1999f..c3759641e 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -470,7 +470,7 @@ def _get_converter_ratio(nbits_from, nbits_to): return converter_cls, ratio -class Converter(LiteXModule): +class Converter(Module): # FIXME: Switch to LiteXModule. def __init__(self, nbits_from, nbits_to, reverse = False, report_valid_token_count = False): From d021564fca8ac6d239dad2b18b5531cc9ee249c6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 15:24:57 +0200 Subject: [PATCH 276/454] interconnect/wishbone: Revert SRAM to Module, needs to be investigated. --- litex/soc/interconnect/wishbone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 5b4323ef5..084930418 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -392,7 +392,7 @@ def __init__(self, master, slave): # Wishbone SRAM ------------------------------------------------------------------------------------ -class SRAM(LiteXModule): +class SRAM(Module): # FIXME: Switch to LiteXModule. def __init__(self, mem_or_size, read_only=None, write_only=None, init=None, bus=None, name=None): if bus is None: bus = Interface(data_width=32, address_width=32, addressing="word") From 5e482d641c18bb942ce8b58eb8b60fd403a76b14 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 27 Oct 2023 16:06:07 +0200 Subject: [PATCH 277/454] core/naxriscv switch to main branch, and implement a reset controller internaly --- litex/soc/cores/cpu/naxriscv/core.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 071936e03..7b00721b0 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -165,8 +165,8 @@ def __init__(self, platform, variant): # CPU Instance. self.cpu_params = dict( # Clk/Rst. - i_clk = ClockSignal("sys"), - i_reset = ResetSignal("sys") | self.reset, + i_socClk = ClockSignal("sys"), + i_asyncReset = ResetSignal("sys") | self.reset, o_patcher_tracer_valid=self.tracer_valid, o_patcher_tracer_payload=self.tracer_payload, @@ -308,8 +308,7 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "9e44c1b6" if NaxRiscv.update_repo=="recommended" else None) - NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "74c5d7de" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "main", "b6d0712f" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From b5a9106f56ab56053558b9b6f59c7b60ee4a7d39 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Oct 2023 18:07:22 +0200 Subject: [PATCH 278/454] cores/video: Simplify VTG/DMA synchronization and re-synchronize on each end of frame. --- litex/soc/cores/video.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 30096931b..942ecba4a 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -693,20 +693,14 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 video_pipe_source = self.cdc.source # Video Synchronization/Generation. - fsm = FSM(reset_state="VTG-SYNC") + fsm = FSM(reset_state="SYNC") fsm = ClockDomainsRenamer(clock_domain)(fsm) fsm = ResetInserter()(fsm) self.submodules += fsm self.specials += MultiReg(self.dma.fsm.reset, fsm.reset, clock_domain) - fsm.act("VTG-SYNC", - vtg_sink.ready.eq(1), + fsm.act("SYNC", + vtg_sink.ready.eq(~fsm.reset), If(vtg_sink.valid & vtg_sink.last, - NextState("DMA-SYNC") - ) - ) - fsm.act("DMA-SYNC", - video_pipe_source.ready.eq(1), - If(video_pipe_source.valid & video_pipe_source.last, NextState("RUN") ) ) @@ -715,10 +709,13 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 If(vtg_sink.valid & vtg_sink.de, video_pipe_source.connect(source, keep={"valid", "ready"}), vtg_sink.ready.eq(source.valid & source.ready), - + If(video_pipe_source.valid & video_pipe_source.last, + NextState("SYNC") + ) ), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), ) + if (depth == 32): self.comb += [ source.r.eq(video_pipe_source.data[ 0: 8]), From 9374196974274aa1ad957afef25578572d2ce81b Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 30 Oct 2023 11:03:16 +0100 Subject: [PATCH 279/454] soc/cores/uart: allows 64bits in Stream2Wishbone --- litex/soc/cores/uart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/uart.py b/litex/soc/cores/uart.py index d6ab38a30..a929a0a8a 100644 --- a/litex/soc/cores/uart.py +++ b/litex/soc/cores/uart.py @@ -311,7 +311,7 @@ def __init__(self, phy=None, clk_freq=None, data_width=32, address_width=32): # # # assert data_width in [8, 16, 32] - assert address_width in [8, 16, 32] + assert address_width in [8, 16, 32, 64] cmd = Signal(8, reset_less=True) incr = Signal() From f06ef5205a8cb727b827d3c84d1e0ff8f5f81478 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 30 Oct 2023 11:13:40 +0100 Subject: [PATCH 280/454] soc/cores/uart: adding address_width (default 32bits) to UARTBone constructor --- litex/soc/cores/uart.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/uart.py b/litex/soc/cores/uart.py index a929a0a8a..f4e0fec28 100644 --- a/litex/soc/cores/uart.py +++ b/litex/soc/cores/uart.py @@ -431,17 +431,17 @@ def __init__(self, phy=None, clk_freq=None, data_width=32, address_width=32): class UARTBone(Stream2Wishbone): - def __init__(self, phy, clk_freq, cd="sys"): + def __init__(self, phy, clk_freq, cd="sys", address_width=32): if cd == "sys": self.phy = phy - Stream2Wishbone.__init__(self, self.phy, clk_freq=clk_freq) + Stream2Wishbone.__init__(self, self.phy, clk_freq=clk_freq, address_width=address_width) else: self.phy = ClockDomainsRenamer(cd)(phy) self.tx_cdc = stream.ClockDomainCrossing([("data", 8)], cd_from="sys", cd_to=cd) self.rx_cdc = stream.ClockDomainCrossing([("data", 8)], cd_from=cd, cd_to="sys") self.comb += self.phy.source.connect(self.rx_cdc.sink) self.comb += self.tx_cdc.source.connect(self.phy.sink) - Stream2Wishbone.__init__(self, clk_freq=clk_freq) + Stream2Wishbone.__init__(self, clk_freq=clk_freq, address_width=address_width) self.comb += self.rx_cdc.source.connect(self.sink) self.comb += self.source.connect(self.tx_cdc.sink) From 321254cc389bf458695e0fe934a37e55d7342a3f Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 30 Oct 2023 11:14:30 +0100 Subject: [PATCH 281/454] soc/integration/soc: pass bus.address_width to UARTBone constructor --- litex/soc/integration/soc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 3fd236338..7e5588658 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1481,7 +1481,11 @@ def add_uartbone(self, name="uartbone", uart_name="serial", clk_freq=None, baudr clk_freq = self.sys_clk_freq self.check_if_exists(name) uartbone_phy = uart.UARTPHY(self.platform.request(uart_name), clk_freq, baudrate) - uartbone = uart.UARTBone(phy=uartbone_phy, clk_freq=clk_freq, cd=cd) + uartbone = uart.UARTBone( + phy = uartbone_phy, + clk_freq = clk_freq, + cd = cd, + addr_width = self.bus.address_width) self.add_module(name=f"{name}_phy", module=uartbone_phy) self.add_module(name=name, module=uartbone) self.bus.add_master(name=name, master=uartbone.wishbone) From a2c39a7bbfc70338a5c31260230487f0b5dc591c Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 30 Oct 2023 16:20:31 +0100 Subject: [PATCH 282/454] tools: litex_server, litex_client and remote: don't hardcode bus address --- litex/tools/litex_client.py | 39 +++++++++---- litex/tools/litex_server.py | 28 +++++----- litex/tools/remote/comm_uart.py | 13 +++-- litex/tools/remote/csr_builder.py | 15 ++++- litex/tools/remote/etherbone.py | 93 ++++++++++++++++++++++--------- 5 files changed, 130 insertions(+), 58 deletions(-) diff --git a/litex/tools/litex_client.py b/litex/tools/litex_client.py index 07b741973..5a9c18b49 100644 --- a/litex/tools/litex_client.py +++ b/litex/tools/litex_client.py @@ -21,16 +21,21 @@ # Remote Client ------------------------------------------------------------------------------------ class RemoteClient(EtherboneIPC, CSRBuilder): - def __init__(self, host="localhost", port=1234, base_address=0, csr_csv=None, csr_data_width=None, debug=False): + def __init__(self, host="localhost", port=1234, base_address=0, csr_csv=None, csr_data_width=None, + csr_bus_address_width=None, debug=False): # If csr_csv set to None and local csr.csv file exists, use it. if csr_csv is None and os.path.exists("csr.csv"): csr_csv = "csr.csv" # If valid csr_csv file found, build the CSRs. if csr_csv is not None: CSRBuilder.__init__(self, self, csr_csv, csr_data_width) - # Else if csr_data_width set to None, force to csr_data_width 32-bit. - elif csr_data_width is None: - csr_data_width = 32 + else: + # Else if csr_data_width set to None, force to csr_data_width 32-bit. + if csr_data_width is None: + csr_data_width = 32 + # Else if csr_bus_address_width set to None, force to csr_bus_address_width 32-bit. + if self.csr_bus_address_width is None: + self.csr_bus_address_width = 32 self.host = host self.port = port self.debug = debug @@ -61,20 +66,27 @@ def close(self): def read(self, addr, length=None, burst="incr"): length_int = 1 if length is None else length + addr_size = self.csr_bus_address_width // 8 # Prepare packet - record = EtherboneRecord() + record = EtherboneRecord(addr_size) incr = (burst == "incr") - record.reads = EtherboneReads(addrs=[self.base_address + addr + 4*incr*j for j in range(length_int)]) + record.reads = EtherboneReads( + addr_size = addr_size, + addrs = [self.base_address + addr + 4*incr*j for j in range(length_int)] + ) record.rcount = len(record.reads) # Send packet - packet = EtherbonePacket() + packet = EtherbonePacket(self.csr_bus_address_width) packet.records = [record] packet.encode() self.send_packet(self.socket, packet) # Receive response - packet = EtherbonePacket(self.receive_packet(self.socket)) + packet = EtherbonePacket( + addr_width = self.csr_bus_address_width, + init = self.receive_packet(self.socket, addr_size) + ) packet.decode() datas = packet.records.pop().writes.get_datas() if self.debug: @@ -84,11 +96,16 @@ def read(self, addr, length=None, burst="incr"): def write(self, addr, datas): datas = datas if isinstance(datas, list) else [datas] - record = EtherboneRecord() - record.writes = EtherboneWrites(base_addr=self.base_address + addr, datas=[d for d in datas]) + addr_size = self.csr_bus_address_width // 8 + record = EtherboneRecord(addr_size) + record.writes = EtherboneWrites( + base_addr = self.base_address + addr, + addr_size = addr_size, + datas = [d for d in datas] + ) record.wcount = len(record.writes) - packet = EtherbonePacket() + packet = EtherbonePacket(self.csr_bus_address_width) packet.records = [record] packet.encode() self.send_packet(self.socket, packet) diff --git a/litex/tools/litex_server.py b/litex/tools/litex_server.py index 8a8f6339a..a3685ffcf 100755 --- a/litex/tools/litex_server.py +++ b/litex/tools/litex_server.py @@ -70,11 +70,12 @@ def _read_merger(addrs, max_length=256, bursts=["incr", "fixed"]): # Remote Server ------------------------------------------------------------------------------------ class RemoteServer(EtherboneIPC): - def __init__(self, comm, bind_ip, bind_port=1234): - self.comm = comm - self.bind_ip = bind_ip - self.bind_port = bind_port - self.lock = False + def __init__(self, comm, bind_ip, bind_port=1234, addr_width=32): + self.comm = comm + self.bind_ip = bind_ip + self.bind_port = bind_port + self.lock = False + self.addr_width = addr_width def open(self): if hasattr(self, "socket"): @@ -115,14 +116,13 @@ def _serve_thread(self): while True: # Receive packet. try: - packet = self.receive_packet(client_socket) + packet = self.receive_packet(client_socket, self.addr_width // 8) if packet == 0: break except: break - # Decode Packet. - packet = EtherbonePacket(packet) + packet = EtherbonePacket(self.addr_width, packet) packet.decode() # Get Packet's Record. @@ -152,11 +152,12 @@ def _serve_thread(self): bursts = bursts): reads += self.comm.read(addr, length, burst) - record = EtherboneRecord() - record.writes = EtherboneWrites(datas=reads) + addr_size = self.addr_width // 8 + record = EtherboneRecord(addr_size) + record.writes = EtherboneWrites(addr_size=addr_size, datas=reads) record.wcount = len(record.writes) - packet = EtherbonePacket() + packet = EtherbonePacket(self.addr_width) packet.records = [record] packet.encode() self.send_packet(client_socket, packet) @@ -181,6 +182,7 @@ def main(): # Common arguments parser.add_argument("--bind-ip", default="localhost", help="Host bind address.") parser.add_argument("--bind-port", default=1234, help="Host bind port.") + parser.add_argument("--addr-width", default=32, help="bus address width.") parser.add_argument("--debug", action="store_true", help="Enable debug.") # UART arguments @@ -220,7 +222,7 @@ def main(): uart_port = args.uart_port uart_baudrate = int(float(args.uart_baudrate)) print("[CommUART] port: {} / baudrate: {} / ".format(uart_port, uart_baudrate), end="") - comm = CommUART(uart_port, uart_baudrate, debug=args.debug) + comm = CommUART(uart_port, uart_baudrate, debug=args.debug, addr_width=int(args.addr_width)) # JTAG mode elif args.jtag: @@ -279,7 +281,7 @@ def main(): parser.print_help() exit() - server = RemoteServer(comm, args.bind_ip, int(args.bind_port)) + server = RemoteServer(comm, args.bind_ip, int(args.bind_port), addr_width=int(args.addr_width)) server.open() server.start(4) try: diff --git a/litex/tools/remote/comm_uart.py b/litex/tools/remote/comm_uart.py index bb124fb36..818d9dbeb 100644 --- a/litex/tools/remote/comm_uart.py +++ b/litex/tools/remote/comm_uart.py @@ -19,11 +19,12 @@ # CommUART ----------------------------------------------------------------------------------------- class CommUART(CSRBuilder): - def __init__(self, port, baudrate=115200, csr_csv=None, debug=False): + def __init__(self, port, baudrate=115200, csr_csv=None, debug=False, addr_width=32): CSRBuilder.__init__(self, comm=self, csr_csv=csr_csv) - self.port = serial.serial_for_url(port, baudrate) - self.baudrate = str(baudrate) - self.debug = debug + self.port = serial.serial_for_url(port, baudrate) + self.baudrate = str(baudrate) + self.debug = debug + self.addr_bytes = addr_width // 8 def open(self): if hasattr(self, "port"): @@ -63,7 +64,7 @@ def read(self, addr, length=None, burst="incr"): "fixed": CMD_READ_BURST_FIXED, }[burst] self._write([cmd, length_int]) - self._write(list((addr//4).to_bytes(4, byteorder="big"))) + self._write(list((addr//4).to_bytes(self.addr_bytes, byteorder="big"))) for i in range(length_int): value = int.from_bytes(self._read(4), "big") if self.debug: @@ -85,7 +86,7 @@ def write(self, addr, data, burst="incr"): "fixed": CMD_WRITE_BURST_FIXED, }[burst] self._write([cmd, size]) - self._write(list(((addr//4 + offset).to_bytes(4, byteorder="big")))) + self._write(list(((addr//4 + offset).to_bytes(self.addr_bytes, byteorder="big")))) for i, value in enumerate(data[offset:offset+size]): self._write(list(value.to_bytes(4, byteorder="big"))) if self.debug: diff --git a/litex/tools/remote/csr_builder.py b/litex/tools/remote/csr_builder.py index 3cffa2b96..fe2a74a6b 100644 --- a/litex/tools/remote/csr_builder.py +++ b/litex/tools/remote/csr_builder.py @@ -64,7 +64,7 @@ def __init__(self, base, size, type): # CSR Builder -------------------------------------------------------------------------------------- class CSRBuilder: - def __init__(self, comm, csr_csv, csr_data_width=None): + def __init__(self, comm, csr_csv, csr_data_width=None, csr_bus_address_width=None): if csr_csv is not None: self.items = self.get_csr_items(csr_csv) self.constants = self.build_constants() @@ -79,7 +79,18 @@ def __init__(self, comm, csr_csv, csr_data_width=None): raise KeyError("csr_data_width of {} provided but {} found in constants".format( csr_data_width, constant_csr_data_width)) - self.csr_data_width = csr_data_width + # Load csr_data_width from the constants, otherwise it must be provided + constant_csr_bus_address_width = self.constants.d.get("config_bus_address_width", None) + if csr_bus_address_width is None: + csr_bus_address_width = constant_csr_bus_address_width + if csr_bus_address_width is None: + raise KeyError("csr_bus_address_width not found in constants, please provide!") + if csr_bus_address_width != constant_csr_bus_address_width: + raise KeyError("csr_bus_address_width of {} provided but {} found in constants".format( + csr_bus_address_width, constant_csr_bus_address_width)) + + self.csr_data_width = csr_data_width + self.csr_bus_address_width = csr_bus_address_width self.bases = self.build_bases() self.regs = self.build_registers(comm.read, comm.write) self.mems = self.build_memories() diff --git a/litex/tools/remote/etherbone.py b/litex/tools/remote/etherbone.py index 9d93b2424..59d679efb 100644 --- a/litex/tools/remote/etherbone.py +++ b/litex/tools/remote/etherbone.py @@ -59,6 +59,8 @@ def get_field_data(field, datas): pack_to_uint32 = struct.Struct('>I').pack unpack_uint32_from = struct.Struct('>I').unpack +pack_to_uint64 = struct.Struct('>Q').pack +unpack_uint64_from = struct.Struct('>Q').unpack # Packet ------------------------------------------------------------------------------------------- @@ -88,13 +90,15 @@ def __repr__(self): # Etherbone Writes --------------------------------------------------------------------------------- class EtherboneWrites(Packet): - def __init__(self, init=[], base_addr=0, datas=[]): + def __init__(self, addr_size, init=[], base_addr=0, datas=[]): if isinstance(datas, list) and len(datas) > 255: raise ValueError(f"Burst size of {len(datas)} exceeds maximum of 255 allowed by Etherbone.") + assert addr_size in [1, 2, 4, 8] Packet.__init__(self, init) self.base_addr = base_addr self.writes = [] self.encoded = init != [] + self.addr_size = addr_size for data in datas: self.add(EtherboneWrite(data)) @@ -111,7 +115,10 @@ def encode(self): if self.encoded: raise ValueError ba = bytearray() - ba += pack_to_uint32(self.base_addr) + if self.addr_size == 4: + ba += pack_to_uint32(self.base_addr) + else: + ba += pack_to_uint64(self.base_addr) for write in self.writes: ba += pack_to_uint32(write.data) self.bytes = ba @@ -121,9 +128,12 @@ def decode(self): if not self.encoded: raise ValueError ba = self.bytes - self.base_addr = unpack_uint32_from(ba[:4])[0] + if self.addr_size == 4: + self.base_addr = unpack_uint32_from(ba[:self.addr_size])[0] + else: + self.base_addr = unpack_uint64_from(ba[:self.addr_size])[0] writes = [] - offset = 4 + offset = self.addr_size length = len(ba) while length > offset: writes.append(EtherboneWrite(unpack_uint32_from(ba[offset:offset+4])[0])) @@ -142,13 +152,15 @@ def __repr__(self): # Etherbone Reads ---------------------------------------------------------------------------------- class EtherboneReads(Packet): - def __init__(self, init=[], base_ret_addr=0, addrs=[]): + def __init__(self, addr_size, init=[], base_ret_addr=0, addrs=[]): if isinstance(addrs, list) and len(addrs) > 255: raise ValueError(f"Burst size of {len(addrs)} exceeds maximum of 255 allowed by Etherbone.") + assert addr_size in [1, 2, 4, 8] Packet.__init__(self, init) self.base_ret_addr = base_ret_addr - self.reads = [] - self.encoded = init != [] + self.reads = [] + self.encoded = init != [] + self.addr_size = addr_size for addr in addrs: self.add(EtherboneRead(addr)) @@ -165,9 +177,15 @@ def encode(self): if self.encoded: raise ValueError ba = bytearray() - ba += pack_to_uint32(self.base_ret_addr) + if (self.addr_size == 4): + ba += pack_to_uint32(self.base_ret_addr) + else: + ba += pack_to_uint64(self.base_ret_addr) for read in self.reads: - ba += pack_to_uint32(read.addr) + if self.addr_size == 4: + ba += pack_to_uint32(read.addr) + else: + ba += pack_to_uint64(read.addr) self.bytes = ba self.encoded = True @@ -175,13 +193,20 @@ def decode(self): if not self.encoded: raise ValueError ba = self.bytes - base_ret_addr = unpack_uint32_from(ba[:4])[0] + if self.addr_size == 4: + base_ret_addr = unpack_uint32_from(ba[:self.addr_size])[0] + else: + base_ret_addr = unpack_uint64_from(ba[:self.addr_size])[0] reads = [] - offset = 4 + offset = self.addr_size length = len(ba) while length > offset: - reads.append(EtherboneRead(unpack_uint32_from(ba[offset:offset+4])[0])) - offset += 4 + v = ba[offset:offset+self.addr_size] + if self.addr_size == 4: + reads.append(EtherboneRead(unpack_uint32_from(v)[0])) + else: + reads.append(EtherboneRead(unpack_uint64_from(v)[0])) + offset += self.addr_size self.reads = reads self.encoded = False @@ -196,7 +221,9 @@ def __repr__(self): # Etherbone Record --------------------------------------------------------------------------------- class EtherboneRecord(Packet): - def __init__(self, init=[]): + def __init__(self, addr_size, init=[]): + assert addr_size in [1, 2, 4, 8] + Packet.__init__(self, init) self.writes = None self.reads = None @@ -210,6 +237,7 @@ def __init__(self, init=[]): self.wcount = 0 self.rcount = 0 self.encoded = init != [] + self.addr_size = addr_size def decode(self): if not self.encoded: @@ -223,14 +251,20 @@ def decode(self): # Decode writes if self.wcount: - self.writes = EtherboneWrites(self.bytes[offset:offset + 4*(self.wcount+1)]) - offset += 4*(self.wcount+1) + init_length = (4 * self.wcount) + (self.addr_size) + self.writes = EtherboneWrites( + addr_size = self.addr_size, + init = self.bytes[offset:offset + init_length]) + offset += init_length self.writes.decode() # Decode reads if self.rcount: - self.reads = EtherboneReads(self.bytes[offset:offset + 4*(self.rcount+1)]) - offset += 4*(self.rcount+1) + init_length = (self.rcount + 1) * self.addr_size + self.reads = EtherboneReads( + addr_size = self.addr_size, + init = self.bytes[offset:offset + init_length]) + offset += init_length self.reads.decode() self.encoded = False @@ -283,15 +317,17 @@ def __repr__(self, n=0): # Etherbone Packet --------------------------------------------------------------------------------- class EtherbonePacket(Packet): - def __init__(self, init=[]): + def __init__(self, addr_width, init=[]): + assert addr_width in [8, 16, 32, 64] + Packet.__init__(self, init) self.encoded = init != [] self.records = [] self.magic = etherbone_magic self.version = etherbone_version - self.addr_size = 32//8 - self.port_size = 32//8 + self.addr_size = addr_width//8 + self.port_size = 4 # FIXME: use data_size self.nr = 0 self.pr = 0 self.pf = 0 @@ -311,14 +347,14 @@ def decode(self): # Decode records length = len(ba) while length > offset: - record = EtherboneRecord(ba[offset:]) + record = EtherboneRecord(addr_size=self.addr_size, init=ba[offset:]) record.decode() self.records.append(record) offset += etherbone_record_header.length if record.wcount: - offset += 4*(record.wcount + 1) + offset += (4*record.wcount) + self.addr_size if record.rcount: - offset += 4*(record.rcount + 1) + offset += (record.rcount + 1) * self.addr_size self.encoded = False @@ -362,7 +398,8 @@ class EtherboneIPC: def send_packet(self, socket, packet): socket.sendall(packet.bytes) - def receive_packet(self, socket): + def receive_packet(self, socket, addr_size): + assert addr_size in [1, 2, 4, 8] header_length = etherbone_packet_header_length + etherbone_record_header_length packet = bytes() while len(packet) < header_length: @@ -373,7 +410,11 @@ def receive_packet(self, socket): packet += chunk wcount, rcount = struct.unpack(">BB", packet[header_length-2:]) counts = wcount + rcount - packet_size = header_length + 4*(counts + 1) + packet_size = header_length + if wcount != 0: + packet_size += 4 * (wcount ) + addr_size + if rcount != 0: + packet_size += (rcount + 1 ) * addr_size while len(packet) < packet_size: chunk = socket.recv(packet_size - len(packet)) if len(chunk) == 0: From eedebd8adb6f7318f7d38b8a24d15446c1a2e6bc Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 30 Oct 2023 17:17:16 +0100 Subject: [PATCH 283/454] litex/soc/cores/cpu/__init__, litex/soc/integration/soc: modifying CPUNone to adapt data_width and io_regions according to bus data_width/address_width --- litex/soc/cores/cpu/__init__.py | 6 ++++-- litex/soc/integration/soc.py | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/cpu/__init__.py b/litex/soc/cores/cpu/__init__.py index 0ebc65923..1d816b3dd 100644 --- a/litex/soc/cores/cpu/__init__.py +++ b/litex/soc/cores/cpu/__init__.py @@ -50,11 +50,9 @@ def disable_reset_address_check(self): class CPUNone(CPU): variants = ["standard"] - data_width = 32 endianness = "little" reset_address = 0x00000000 reset_address_check = False - io_regions = {0x0000_0000: 0x1_0000_0000} # origin, length periph_buses = [] memory_buses = [] mem_map = { @@ -63,6 +61,10 @@ class CPUNone(CPU): "spiflash" : 0x1000_0000, # FIXME: Remove. } + def __init__(self, data_width=32, addr_width=32): + self.io_regions = {0: int(2**float(addr_width))} # origin, length + self.data_width = data_width + # CPUs GCC Triples --------------------------------------------------------------------------------- CPU_GCC_TRIPLE_RISCV64 = ( diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 7e5588658..ad462d429 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1082,7 +1082,10 @@ def add_cpu(self, name="vexriscv", variant="standard", reset_address=None, cfu=N colorer("\n - ".join(sorted(cpu_cls.variants))))) raise SoCError() self.check_if_exists("cpu") - self.cpu = cpu_cls(self.platform, variant) + if cpu_cls is cpu.CPUNone: + self.cpu = cpu_cls(self.bus.data_width, self.bus.address_width) + else: + self.cpu = cpu_cls(self.platform, variant) self.logger.info("CPU {} {}.".format( colorer(name, color="underline"), colorer("added", color="green"))) From 16133359d6ba9d37c88e4107e12d228c26c8717f Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 30 Oct 2023 18:13:46 +0100 Subject: [PATCH 284/454] soc/integration/soc: fix typo at UARTBone call (addr_width -> address_width) --- litex/soc/integration/soc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 7e5588658..bdcce774c 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1482,10 +1482,10 @@ def add_uartbone(self, name="uartbone", uart_name="serial", clk_freq=None, baudr self.check_if_exists(name) uartbone_phy = uart.UARTPHY(self.platform.request(uart_name), clk_freq, baudrate) uartbone = uart.UARTBone( - phy = uartbone_phy, - clk_freq = clk_freq, - cd = cd, - addr_width = self.bus.address_width) + phy = uartbone_phy, + clk_freq = clk_freq, + cd = cd, + address_width = self.bus.address_width) self.add_module(name=f"{name}_phy", module=uartbone_phy) self.add_module(name=name, module=uartbone) self.bus.add_master(name=name, master=uartbone.wishbone) From 9b8a5b6385b769e1e42a26b73e8455e81b116e6a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 30 Oct 2023 19:40:42 +0100 Subject: [PATCH 285/454] CHANGES: Update. --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 4d795a814..0e91a7adb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -20,6 +20,9 @@ - build/xilinx : Added initial OpenXC7 support (and improved Yosys-NextPnr). - build/efinix : Added JTAG-UART/JTAGBone support. - interconnect/wishbone : Added byte/word addressing support. + - cores/uart : Added 64-bit addressing support to Stream2Wishbone. + - tools : Added 64-bit addressing support to litex_server/client. + - cores/cpu : Added 64-bit support to CPUNone. [> Changed ---------- From 755808e2872cfe892770baa40439a75d48359f48 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 31 Oct 2023 11:59:49 +0100 Subject: [PATCH 286/454] soc/interconnect/wishbone: InterconnectShared,Crossbar: using master adr_width for Interface constructor --- litex/soc/interconnect/wishbone.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 084930418..64c9c5d3d 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -238,7 +238,8 @@ def __init__(self, master, slaves, register=False): class InterconnectShared(LiteXModule): def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) - shared = Interface(data_width=data_width) + adr_width = max([m.adr_width for m in masters]) + shared = Interface(data_width=data_width, adr_width=adr_width) self.arbiter = Arbiter(masters, shared) self.decoder = Decoder(shared, slaves, register) if timeout_cycles is not None: @@ -249,7 +250,8 @@ class Crossbar(LiteXModule): def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) matches, busses = zip(*slaves) - access = [[Interface(data_width=data_width) for j in slaves] for i in masters] + adr_width = max([m.adr_width for m in masters]) + access = [[Interface(data_width=data_width, adr_width=adr_width) for j in slaves] for i in masters] # decode each master into its access row for row, master in zip(access, masters): row = list(zip(matches, row)) From b60bd925339623d751fdc672ad1dce2a84b7d823 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 10:14:38 +0100 Subject: [PATCH 287/454] gen/fhdl/verilog: Rename _print_xy to _generate_xy and cleanup imports. --- litex/gen/fhdl/verilog.py | 166 +++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index bc03183ed..d6b9536bc 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -15,18 +15,18 @@ import time import datetime +import collections -from functools import partial from operator import itemgetter -import collections -from migen.fhdl.structure import * -from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment -from migen.fhdl.tools import * +from migen.fhdl.structure import * +from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment +from migen.fhdl.tools import * from migen.fhdl.conv_output import ConvOutput -from migen.fhdl.specials import Memory +from migen.fhdl.specials import Memory from litex.gen.fhdl.namer import build_namespace + from litex.build.tools import get_litex_git_revision # ------------------------------------------------------------------------------------------------ # @@ -35,7 +35,7 @@ _tab = " "*4 -def _print_banner(filename, device): +def _generate_banner(filename, device): return """\ // ----------------------------------------------------------------------------- // Auto-Generated by: __ _ __ _ __ @@ -57,7 +57,7 @@ def _print_banner(filename, device): date = datetime.datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d %H:%M:%S") ) -def _print_trailer(): +def _generate_trailer(): return """ // ----------------------------------------------------------------------------- // Auto-Generated by LiteX on {date}. @@ -66,7 +66,7 @@ def _print_trailer(): date=datetime.datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d %H:%M:%S") ) -def _print_separator(msg=""): +def _generate_separator(msg=""): r = "\n" r += "//" + "-"*78 + "\n" r += f"// {msg}\n" @@ -78,7 +78,7 @@ def _print_separator(msg=""): # TIMESCALE # # ------------------------------------------------------------------------------------------------ # -def _print_timescale(time_unit="1ns", time_precision="1ps"): +def _generate_timescale(time_unit="1ns", time_precision="1ps"): r = f"`timescale {time_unit} / {time_precision}\n" return r @@ -145,7 +145,7 @@ def _print_timescale(time_unit="1ns", time_precision="1ps"): # Print Constant ----------------------------------------------------------------------------------- -def _print_constant(node): +def _generate_constant(node): return "{sign}{bits}'d{value}".format( sign = "" if node.value >= 0 else "-", bits = str(node.nbits), @@ -154,7 +154,7 @@ def _print_constant(node): # Print Signal ------------------------------------------------------------------------------------- -def _print_signal(ns, s): +def _generate_signal(ns, s): length = 8 vector = f"[{str(len(s)-1)}:0] " vector = " "*(length-len(vector)) + vector @@ -168,7 +168,7 @@ def _print_signal(ns, s): (UNARY, BINARY, TERNARY) = (1, 2, 3) -def _print_operator(ns, node): +def _generate_operator(ns, node): operator = node.op operands = node.operands arity = len(operands) @@ -179,7 +179,7 @@ def to_signed(r): # Unary Operator. if arity == UNARY: - r1, s1 = _print_expression(ns, operands[0]) + r1, s1 = _generate_expression(ns, operands[0]) # Negation Operator. if operator == "-": # Negate and convert to signed if not already. @@ -192,8 +192,8 @@ def to_signed(r): # Binary Operator. if arity == BINARY: - r1, s1 = _print_expression(ns, operands[0]) - r2, s2 = _print_expression(ns, operands[1]) + r1, s1 = _generate_expression(ns, operands[0]) + r2, s2 = _generate_expression(ns, operands[1]) # Convert all expressions to signed when at least one is signed. if operator not in ["<<<", ">>>"]: if s2 and not s1: @@ -206,9 +206,9 @@ def to_signed(r): # Ternary Operator. if arity == TERNARY: assert operator == "m" - r1, s1 = _print_expression(ns, operands[0]) - r2, s2 = _print_expression(ns, operands[1]) - r3, s3 = _print_expression(ns, operands[2]) + r1, s1 = _generate_expression(ns, operands[0]) + r2, s2 = _generate_expression(ns, operands[1]) + r3, s3 = _generate_expression(ns, operands[2]) # Convert all expressions to signed when at least one is signed. if s2 and not s3: r3 = to_signed(r3) @@ -221,33 +221,33 @@ def to_signed(r): # Print Slice -------------------------------------------------------------------------------------- -def _print_slice(ns, node): +def _generate_slice(ns, node): assert (node.stop - node.start) >= 1 if (isinstance(node.value, Signal) and len(node.value) == 1): assert node.start == 0 sr = "" # Avoid slicing 1-bit Signals. else: sr = f"[{node.stop-1}:{node.start}]" if (node.stop - node.start) > 1 else f"[{node.start}]" - r, s = _print_expression(ns, node.value) + r, s = _generate_expression(ns, node.value) return r + sr, s # Print Cat ---------------------------------------------------------------------------------------- -def _print_cat(ns, node): - l = [_print_expression(ns, v)[0] for v in reversed(node.l)] +def _generate_cat(ns, node): + l = [_generate_expression(ns, v)[0] for v in reversed(node.l)] return "{" + ", ".join(l) + "}", False # Print Replicate ---------------------------------------------------------------------------------- -def _print_replicate(ns, node): - return "{" + str(node.n) + "{" + _print_expression(ns, node.v)[0] + "}}", False +def _generate_replicate(ns, node): + return "{" + str(node.n) + "{" + _generate_expression(ns, node.v)[0] + "}}", False # Print Expression --------------------------------------------------------------------------------- -def _print_expression(ns, node): +def _generate_expression(ns, node): # Constant. if isinstance(node, Constant): - return _print_constant(node) + return _generate_constant(node) # Signal. elif isinstance(node, Signal): @@ -255,19 +255,19 @@ def _print_expression(ns, node): # Operator. elif isinstance(node, _Operator): - return _print_operator(ns, node) + return _generate_operator(ns, node) # Slice. elif isinstance(node, _Slice): - return _print_slice(ns, node) + return _generate_slice(ns, node) # Cat. elif isinstance(node, Cat): - return _print_cat(ns, node) + return _generate_cat(ns, node) # Replicate. elif isinstance(node, Replicate): - return _print_replicate(ns, node) + return _generate_replicate(ns, node) # Unknown. else: @@ -279,7 +279,7 @@ def _print_expression(ns, node): (_AT_BLOCKING, _AT_NONBLOCKING, _AT_SIGNAL) = range(3) -def _print_node(ns, at, level, node, target_filter=None): +def _generate_node(ns, at, level, node, target_filter=None): if target_filter is not None and target_filter not in list_targets(node): return "" @@ -293,35 +293,35 @@ def _print_node(ns, at, level, node, target_filter=None): assignment = " = " else: assignment = " <= " - return _tab*level + _print_expression(ns, node.l)[0] + assignment + _print_expression(ns, node.r)[0] + ";\n" + return _tab*level + _generate_expression(ns, node.l)[0] + assignment + _generate_expression(ns, node.r)[0] + ";\n" # Iterable. elif isinstance(node, collections.abc.Iterable): - return "".join(_print_node(ns, at, level, n, target_filter) for n in node) + return "".join(_generate_node(ns, at, level, n, target_filter) for n in node) # If. elif isinstance(node, If): - r = _tab*level + "if (" + _print_expression(ns, node.cond)[0] + ") begin\n" - r += _print_node(ns, at, level + 1, node.t, target_filter) + r = _tab*level + "if (" + _generate_expression(ns, node.cond)[0] + ") begin\n" + r += _generate_node(ns, at, level + 1, node.t, target_filter) if node.f: r += _tab*level + "end else begin\n" - r += _print_node(ns, at, level + 1, node.f, target_filter) + r += _generate_node(ns, at, level + 1, node.f, target_filter) r += _tab*level + "end\n" return r # Case. elif isinstance(node, Case): if node.cases: - r = _tab*level + "case (" + _print_expression(ns, node.test)[0] + ")\n" + r = _tab*level + "case (" + _generate_expression(ns, node.test)[0] + ")\n" css = [(k, v) for k, v in node.cases.items() if isinstance(k, Constant)] css = sorted(css, key=lambda x: x[0].value) for choice, statements in css: - r += _tab*(level + 1) + _print_expression(ns, choice)[0] + ": begin\n" - r += _print_node(ns, at, level + 2, statements, target_filter) + r += _tab*(level + 1) + _generate_expression(ns, choice)[0] + ": begin\n" + r += _generate_node(ns, at, level + 2, statements, target_filter) r += _tab*(level + 1) + "end\n" if "default" in node.cases: r += _tab*(level + 1) + "default: begin\n" - r += _print_node(ns, at, level + 2, node.cases["default"], target_filter) + r += _generate_node(ns, at, level + 2, node.cases["default"], target_filter) r += _tab*(level + 1) + "end\n" r += _tab*level + "endcase\n" return r @@ -351,7 +351,7 @@ def _print_node(ns, at, level, node, target_filter=None): # ATTRIBUTES # # ------------------------------------------------------------------------------------------------ # -def _print_attribute(attr, attr_translate): +def _generate_attribute(attr, attr_translate): r = "" first = True for attr in sorted(attr, key=lambda x: ("", x) if isinstance(x, str) else x): @@ -389,7 +389,7 @@ def _list_comb_wires(f): r |= g[0] return r -def _print_module(f, ios, name, ns, attr_translate): +def _generate_module(f, ios, name, ns, attr_translate): sigs = list_signals(f) | list_special_ios(f, ins=True, outs=True, inouts=True) special_outs = list_special_ios(f, ins=False, outs=True, inouts=True) inouts = list_special_ios(f, ins=False, outs=False, inouts=True) @@ -402,7 +402,7 @@ def _print_module(f, ios, name, ns, attr_translate): if not firstp: r += ",\n" firstp = False - attr = _print_attribute(sig.attr, attr_translate) + attr = _generate_attribute(sig.attr, attr_translate) if attr: r += _tab + attr sig.type = "wire" @@ -410,22 +410,22 @@ def _print_module(f, ios, name, ns, attr_translate): sig.port = True if sig in inouts: sig.direction = "inout" - r += _tab + "inout wire " + _print_signal(ns, sig) + r += _tab + "inout wire " + _generate_signal(ns, sig) elif sig in targets: sig.direction = "output" if sig in wires: - r += _tab + "output wire " + _print_signal(ns, sig) + r += _tab + "output wire " + _generate_signal(ns, sig) else: sig.type = "reg" - r += _tab + "output reg " + _print_signal(ns, sig) + r += _tab + "output reg " + _generate_signal(ns, sig) else: sig.direction = "input" - r += _tab + "input wire " + _print_signal(ns, sig) + r += _tab + "input wire " + _generate_signal(ns, sig) r += "\n);\n\n" return r -def _print_signals(f, ios, name, ns, attr_translate, regs_init): +def _generate_signals(f, ios, name, ns, attr_translate, regs_init): sigs = list_signals(f) | list_special_ios(f, ins=True, outs=True, inouts=True) special_outs = list_special_ios(f, ins=False, outs=True, inouts=True) inouts = list_special_ios(f, ins=False, outs=False, inouts=True) @@ -434,13 +434,13 @@ def _print_signals(f, ios, name, ns, attr_translate, regs_init): r = "" for sig in sorted(sigs - ios, key=lambda x: ns.get_name(x)): - r += _print_attribute(sig.attr, attr_translate) + r += _generate_attribute(sig.attr, attr_translate) if sig in wires: - r += "wire " + _print_signal(ns, sig) + ";\n" + r += "wire " + _generate_signal(ns, sig) + ";\n" else: - r += "reg " + _print_signal(ns, sig) + r += "reg " + _generate_signal(ns, sig) if regs_init: - r += " = " + _print_expression(ns, sig.reset)[0] + r += " = " + _generate_expression(ns, sig.reset)[0] r += ";\n" return r @@ -448,12 +448,10 @@ def _print_signals(f, ios, name, ns, attr_translate, regs_init): # COMBINATORIAL LOGIC # # ------------------------------------------------------------------------------------------------ # -def _print_combinatorial_logic_sim(f, ns): +def _generate_combinatorial_logic_sim(f, ns): r = "" if f.comb: - from collections import defaultdict - - target_stmt_map = defaultdict(list) + target_stmt_map = collections.defaultdict(list) for statement in flat_iteration(f.comb): targets = list_targets(statement) @@ -465,28 +463,28 @@ def _print_combinatorial_logic_sim(f, ns): for n, (t, stmts) in enumerate(target_stmt_map.items()): assert isinstance(t, Signal) if _use_wire(stmts): - r += "assign " + _print_node(ns, _AT_BLOCKING, 0, stmts[0]) + r += "assign " + _generate_node(ns, _AT_BLOCKING, 0, stmts[0]) else: r += "always @(*) begin\n" - r += _tab + ns.get_name(t) + " <= " + _print_expression(ns, t.reset)[0] + ";\n" - r += _print_node(ns, _AT_NONBLOCKING, 1, stmts, t) + r += _tab + ns.get_name(t) + " <= " + _generate_expression(ns, t.reset)[0] + ";\n" + r += _generate_node(ns, _AT_NONBLOCKING, 1, stmts, t) r += "end\n" r += "\n" return r -def _print_combinatorial_logic_synth(f, ns): +def _generate_combinatorial_logic_synth(f, ns): r = "" if f.comb: groups = group_by_targets(f.comb) for n, g in enumerate(groups): if _use_wire(g[1]): - r += "assign " + _print_node(ns, _AT_BLOCKING, 0, g[1][0]) + r += "assign " + _generate_node(ns, _AT_BLOCKING, 0, g[1][0]) else: r += "always @(*) begin\n" for t in sorted(g[0], key=lambda x: ns.get_name(x)): - r += _tab + ns.get_name(t) + " <= " + _print_expression(ns, t.reset)[0] + ";\n" - r += _print_node(ns, _AT_NONBLOCKING, 1, g[1]) + r += _tab + ns.get_name(t) + " <= " + _generate_expression(ns, t.reset)[0] + ";\n" + r += _generate_node(ns, _AT_NONBLOCKING, 1, g[1]) r += "end\n" r += "\n" return r @@ -495,11 +493,11 @@ def _print_combinatorial_logic_synth(f, ns): # SYNCHRONOUS LOGIC # # ------------------------------------------------------------------------------------------------ # -def _print_synchronous_logic(f, ns): +def _generate_synchronous_logic(f, ns): r = "" for k, v in sorted(f.sync.items(), key=itemgetter(0)): r += "always @(posedge " + ns.get_name(f.clock_domains[k].clk) + ") begin\n" - r += _print_node(ns, _AT_SIGNAL, 1, v) + r += _generate_node(ns, _AT_SIGNAL, 1, v) r += "end\n\n" return r @@ -507,11 +505,11 @@ def _print_synchronous_logic(f, ns): # SPECIALS # # ------------------------------------------------------------------------------------------------ # -def _print_specials(name, overrides, specials, namespace, add_data_file, attr_translate): +def _generate_specials(name, overrides, specials, namespace, add_data_file, attr_translate): r = "" for special in sorted(specials, key=lambda x: x.duid): if hasattr(special, "attr"): - r += _print_attribute(special.attr, attr_translate) + r += _generate_attribute(special.attr, attr_translate) # Replace Migen Memory's emit_verilog with LiteX's implementation. if isinstance(special, Memory): from litex.gen.fhdl.memory import memory_emit_verilog @@ -600,7 +598,8 @@ def convert(f, ios=set(), name="top", platform=None, signals = ( list_signals(f) | list_special_ios(f, ins=True, outs=True, inouts=True) | - ios), + ios + ), reserved_keywords = _ieee_1800_2017_verilog_reserved_keywords ) ns.clock_domains = f.clock_domains @@ -608,40 +607,41 @@ def convert(f, ios=set(), name="top", platform=None, # Build Verilog. # -------------- verilog = "" + # Banner. - verilog += _print_banner( + verilog += _generate_banner( filename = name, device = getattr(platform, "device", "Unknown") ) # Timescale. - verilog += _print_timescale( + verilog += _generate_timescale( time_unit = time_unit, time_precision = time_precision ) # Module Definition. - verilog += _print_separator("Module") - verilog += _print_module(f, ios, name, ns, attr_translate) + verilog += _generate_separator("Module") + verilog += _generate_module(f, ios, name, ns, attr_translate) # Module Signals. - verilog += _print_separator("Signals") - verilog += _print_signals(f, ios, name, ns, attr_translate, regs_init) + verilog += _generate_separator("Signals") + verilog += _generate_signals(f, ios, name, ns, attr_translate, regs_init) # Combinatorial Logic. - verilog += _print_separator("Combinatorial Logic") + verilog += _generate_separator("Combinatorial Logic") if regular_comb: - verilog += _print_combinatorial_logic_synth(f, ns) + verilog += _generate_combinatorial_logic_synth(f, ns) else: - verilog += _print_combinatorial_logic_sim(f, ns) + verilog += _generate_combinatorial_logic_sim(f, ns) # Synchronous Logic. - verilog += _print_separator("Synchronous Logic") - verilog += _print_synchronous_logic(f, ns) + verilog += _generate_separator("Synchronous Logic") + verilog += _generate_synchronous_logic(f, ns) # Specials - verilog += _print_separator("Specialized Logic") - verilog += _print_specials( + verilog += _generate_separator("Specialized Logic") + verilog += _generate_specials( name = name, overrides = special_overrides, specials = f.specials - lowered_specials, @@ -654,7 +654,7 @@ def convert(f, ios=set(), name="top", platform=None, verilog += "endmodule\n" # Trailer. - verilog += _print_trailer() + verilog += _generate_trailer() r.set_main_source(verilog) r.ns = ns From 1f200c83f37970ecf252e6b2d682afd0fd94dd9e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:04:31 +0100 Subject: [PATCH 288/454] build: Minor cleanups on get_verilog calls. --- litex/build/altera/platform.py | 4 ++-- litex/build/anlogic/platform.py | 3 ++- litex/build/colognechip/platform.py | 3 ++- litex/build/efinix/platform.py | 7 +++++-- litex/build/gowin/platform.py | 3 ++- litex/build/lattice/platform.py | 3 ++- litex/build/microsemi/platform.py | 3 ++- litex/build/sim/verilator.py | 2 +- litex/build/xilinx/platform.py | 3 ++- 9 files changed, 20 insertions(+), 11 deletions(-) diff --git a/litex/build/altera/platform.py b/litex/build/altera/platform.py index a389a24f8..bfcbba829 100644 --- a/litex/build/altera/platform.py +++ b/litex/build/altera/platform.py @@ -38,8 +38,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): return GenericPlatform.get_verilog(self, *args, special_overrides = so, attr_translate = self.toolchain.attr_translate, - **kwargs) - + **kwargs + ) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/anlogic/platform.py b/litex/build/anlogic/platform.py index b66f002b7..e02fffbe9 100644 --- a/litex/build/anlogic/platform.py +++ b/litex/build/anlogic/platform.py @@ -31,7 +31,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): return GenericPlatform.get_verilog(self, *args, special_overrides = so, attr_translate = self.toolchain.attr_translate, - **kwargs) + **kwargs + ) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/colognechip/platform.py b/litex/build/colognechip/platform.py index 78f6ed6e8..98104fbf2 100644 --- a/litex/build/colognechip/platform.py +++ b/litex/build/colognechip/platform.py @@ -28,7 +28,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): return GenericPlatform.get_verilog(self, *args, special_overrides = so, attr_translate = self.toolchain.attr_translate, - **kwargs) + **kwargs + ) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index 2f877ac0e..1dc76fb90 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -56,8 +56,11 @@ def __init__(self, *args, iobank_info=None, toolchain="efinity", spi_mode="activ def get_verilog(self, *args, special_overrides=dict(), **kwargs): so = dict(common.efinix_special_overrides) so.update(special_overrides) - return GenericPlatform.get_verilog(self, *args, special_overrides=so, - attr_translate=self.toolchain.attr_translate, **kwargs) + return GenericPlatform.get_verilog(self, *args, + special_overrides = so, + attr_translate = self.toolchain.attr_translate, + **kwargs + ) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/gowin/platform.py b/litex/build/gowin/platform.py index b694c2cc3..2e8a75f44 100644 --- a/litex/build/gowin/platform.py +++ b/litex/build/gowin/platform.py @@ -38,7 +38,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): return GenericPlatform.get_verilog(self, *args, special_overrides = so, attr_translate = self.toolchain.attr_translate, - **kwargs) + **kwargs + ) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/lattice/platform.py b/litex/build/lattice/platform.py index 323b2e511..79fcbe1f6 100644 --- a/litex/build/lattice/platform.py +++ b/litex/build/lattice/platform.py @@ -42,7 +42,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): return GenericPlatform.get_verilog(self, *args, special_overrides = so, attr_translate = self.toolchain.attr_translate, - **kwargs) + **kwargs + ) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/microsemi/platform.py b/litex/build/microsemi/platform.py index 71c344d65..ee59dcebb 100644 --- a/litex/build/microsemi/platform.py +++ b/litex/build/microsemi/platform.py @@ -29,7 +29,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): return GenericPlatform.get_verilog(self, *args, special_overrides = so, attr_translate = self.toolchain.attr_translate, - **kwargs) + **kwargs + ) def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) diff --git a/litex/build/sim/verilator.py b/litex/build/sim/verilator.py index ca18fb125..704313a01 100644 --- a/litex/build/sim/verilator.py +++ b/litex/build/sim/verilator.py @@ -228,7 +228,7 @@ def build(self, platform, fragment, # Generate verilog v_output = platform.get_verilog(fragment, name = build_name, - regular_comb = regular_comb + regular_comb = regular_comb, ) named_sc, named_pc = platform.resolve_signals(v_output.ns) v_file = build_name + ".v" diff --git a/litex/build/xilinx/platform.py b/litex/build/xilinx/platform.py index dfde24288..6c20f0c49 100644 --- a/litex/build/xilinx/platform.py +++ b/litex/build/xilinx/platform.py @@ -88,7 +88,8 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): return GenericPlatform.get_verilog(self, *args, special_overrides = so, attr_translate = self.toolchain.attr_translate, - **kwargs) + **kwargs + ) def get_edif(self, fragment, **kwargs): return GenericPlatform.get_edif(self, fragment, "UNISIMS", "Xilinx", self.device, **kwargs) From 27c55999c61b8e886f040eaf759c1411c0574121 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:05:09 +0100 Subject: [PATCH 289/454] gen/common/colorer: Add enable parameter to allow enabling/disabling coloring. --- litex/gen/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/gen/common.py b/litex/gen/common.py index 3a963fff6..101243038 100644 --- a/litex/gen/common.py +++ b/litex/gen/common.py @@ -8,7 +8,7 @@ # Coloring Helpers --------------------------------------------------------------------------------- -def colorer(s, color="bright"): +def colorer(s, color="bright", enable=True): """Apply ANSI colors to a string.""" header = { "bright": "\x1b[1m", @@ -18,7 +18,7 @@ def colorer(s, color="bright"): "yellow": "\x1b[33m", "underline": "\x1b[4m"}[color] trailer = "\x1b[0m" - return header + str(s) + trailer + return (header + str(s) + trailer) if enable else str(s) # Bit/Bytes Reversing ------------------------------------------------------------------------------ From 4497569118324047bcf771567f2a45bbc6750ac2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:05:36 +0100 Subject: [PATCH 290/454] gen/context: Rename soc to top. --- litex/gen/context.py | 4 ++-- litex/soc/integration/soc.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/litex/gen/context.py b/litex/gen/context.py index 8846283a1..3840c0ba5 100644 --- a/litex/gen/context.py +++ b/litex/gen/context.py @@ -19,9 +19,9 @@ class LiteXContext: platform : The FPGA Platform of the project. toolchain : The FPGA Toolchain to be used for synthesis and place-and-route. device : The FPGA Device of the LiteX project. - soc : The FPGA SoC of the LiteX project. + top : The FPGA Top-Level Module of the LiteX project. """ platform = None toolchain = None device = None - soc = None + top = None diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index e9ff4ba5e..1a938a56f 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -895,8 +895,8 @@ def __init__(self, platform, sys_clk_freq, self.constants = {} self.csr_regions = {} - # Set SoC to LiteXContext. - LiteXContext.soc = self + # Set Top-Level to LiteXContext. + LiteXContext.top = self # SoC Bus Handler -------------------------------------------------------------------------- self.bus = SoCBusHandler( From 4a1486b1db77d01cc397d47f48fe10a838403fe2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:06:41 +0100 Subject: [PATCH 291/454] gen/fhdl/hierarchy: Add with_colors parameters to allow enabling/disabling colors. --- litex/gen/fhdl/hierarchy.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/litex/gen/fhdl/hierarchy.py b/litex/gen/fhdl/hierarchy.py index eb8ffde99..17ff922dc 100644 --- a/litex/gen/fhdl/hierarchy.py +++ b/litex/gen/fhdl/hierarchy.py @@ -14,11 +14,15 @@ class LiteXHierarchyExplorer: tree_ident = "│ " tree_entry = "└─── " - def __init__(self, top, depth=None): - self.top = top - self.depth = depth + def __init__(self, top, depth=None, with_colors=True): + self.top = top + self.depth = depth + self.with_colors = with_colors - def get_tree(self, module, ident=0, with_modules=True, with_instances=True): + def _colorer(self, s, color="bright"): + return colorer(s=s, color=color, enable=self.with_colors) + + def get_tree(self, module, ident=0, with_modules=True, with_instances=True, with_colors=True): r = "" names = set() names.add(None) @@ -31,7 +35,7 @@ def get_tree(self, module, ident=0, with_modules=True, with_instances=True): n += 1 names.add(name) if with_modules: - r += f"{self.tree_ident*ident}{self.tree_entry}{colorer(name, 'cyan')} ({mod.__class__.__name__})\n" + r += f"{self.tree_ident*ident}{self.tree_entry}{self._colorer(name, 'cyan')} ({mod.__class__.__name__})\n" if (self.depth is None) or (ident < self.depth): r += self.get_tree(mod, ident + 1) @@ -44,13 +48,13 @@ def get_tree(self, module, ident=0, with_modules=True, with_instances=True): if s in v._fragment.specials: show = False if show: - r += f"{self.tree_ident*ident}{self.tree_entry}{colorer(f'[{s.of}]', 'yellow')}\n" + r += f"{self.tree_ident*ident}{self.tree_entry}{self._colorer(f'[{s.of}]', 'yellow')}\n" return r def __repr__(self): r = "\n" - r += f"{colorer(self.top.__class__.__name__, 'underline')}\n" + r += f"{self._colorer(self.top.__class__.__name__, 'underline')}\n" r += self.get_tree(self.top) - r += f"{colorer('* ', 'cyan')}: Generated name.\n" - r += f"{colorer('[]', 'yellow')}: BlackBox.\n" + r += f"{self._colorer('* ', 'cyan')}: Generated name.\n" + r += f"{self._colorer('[]', 'yellow')}: BlackBox.\n" return r From e6d950bcb0b60b15316ee2dcbd66f858987ed015 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:07:57 +0100 Subject: [PATCH 292/454] gen/fhdl/verilog: Add module hierarchy generation after module definition. Will give a better overview of the generated verilog and will also ease comparing changes/track regressions. --- litex/gen/fhdl/verilog.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index d6b9536bc..20d861505 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -25,7 +25,9 @@ from migen.fhdl.conv_output import ConvOutput from migen.fhdl.specials import Memory -from litex.gen.fhdl.namer import build_namespace +from litex.gen import LiteXContext +from litex.gen.fhdl.namer import build_namespace +from litex.gen.fhdl.hierarchy import LiteXHierarchyExplorer from litex.build.tools import get_litex_git_revision @@ -82,6 +84,19 @@ def _generate_timescale(time_unit="1ns", time_precision="1ps"): r = f"`timescale {time_unit} / {time_precision}\n" return r +# ------------------------------------------------------------------------------------------------ # +# HIERARCHY # +# ------------------------------------------------------------------------------------------------ # + +def _generate_hierarchy(top): + hierarchy = LiteXHierarchyExplorer(top=top, depth=None, with_colors=False).__repr__() + r = "/*\n" + for l in hierarchy.split("\n"): + r += l + "\n" + #r += "//" + l + "\n" + r += "*/\n" + return r + # ------------------------------------------------------------------------------------------------ # # RESERVED KEYWORDS # # ------------------------------------------------------------------------------------------------ # @@ -624,6 +639,10 @@ def convert(f, ios=set(), name="top", platform=None, verilog += _generate_separator("Module") verilog += _generate_module(f, ios, name, ns, attr_translate) + # Module Hierarchy. + verilog += _generate_separator("Hierarchy") + verilog += _generate_hierarchy(top=LiteXContext.top) + # Module Signals. verilog += _generate_separator("Signals") verilog += _generate_signals(f, ios, name, ns, attr_translate, regs_init) From fe19ee464e091e3ad8a89dee73699907d2947189 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:29:48 +0100 Subject: [PATCH 293/454] gen/fhdl/memory: Rename memory_emit_verilog to _memory_generate_verilog. --- litex/gen/fhdl/memory.py | 15 ++++++++------- litex/gen/fhdl/verilog.py | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/litex/gen/fhdl/memory.py b/litex/gen/fhdl/memory.py index 545d774a4..56f2847a1 100644 --- a/litex/gen/fhdl/memory.py +++ b/litex/gen/fhdl/memory.py @@ -2,18 +2,19 @@ # This file is part of LiteX (Adapted from Migen for LiteX usage). # # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq -# This file is Copyright (c) 2021 Florent Kermarrec +# This file is Copyright (c) 2021-2023 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause -from migen.fhdl.structure import * -from migen.fhdl.module import * +from migen.fhdl.structure import * +from migen.fhdl.module import * from migen.fhdl.bitcontainer import bits_for -from migen.fhdl.tools import * -from migen.fhdl.verilog import _printexpr as verilog_printexpr -from migen.fhdl.specials import * +from migen.fhdl.tools import * +from migen.fhdl.verilog import _printexpr as verilog_printexpr +from migen.fhdl.specials import * +# LiteX Memory Verilog Generation ------------------------------------------------------------------ -def memory_emit_verilog(name, memory, namespace, add_data_file): +def _memory_generate_verilog(name, memory, namespace, add_data_file): # Helpers. # -------- diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index 20d861505..87cf629d8 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -527,8 +527,8 @@ def _generate_specials(name, overrides, specials, namespace, add_data_file, attr r += _generate_attribute(special.attr, attr_translate) # Replace Migen Memory's emit_verilog with LiteX's implementation. if isinstance(special, Memory): - from litex.gen.fhdl.memory import memory_emit_verilog - pr = memory_emit_verilog(name, special, namespace, add_data_file) + from litex.gen.fhdl.memory import _memory_generate_verilog + pr = _memory_generate_verilog(name, special, namespace, add_data_file) else: pr = call_special_classmethod(overrides, special, "emit_verilog", namespace, add_data_file) if pr is None: From dee64b346f84b4986607c13fe9c0089792f16eb3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:40:16 +0100 Subject: [PATCH 294/454] gen/fhdl: Integrate Migen's Instance verilog generation to be able to customize it to our needs. --- litex/gen/fhdl/instance.py | 55 ++++++++++++++++++++++++++++++++++++++ litex/gen/fhdl/verilog.py | 8 ++++-- 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 litex/gen/fhdl/instance.py diff --git a/litex/gen/fhdl/instance.py b/litex/gen/fhdl/instance.py new file mode 100644 index 000000000..b948d720c --- /dev/null +++ b/litex/gen/fhdl/instance.py @@ -0,0 +1,55 @@ +# +# This file is part of LiteX (Adapted from Migen for LiteX usage). +# +# This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq +# SPDX-License-Identifier: BSD-2-Clause + +from migen.fhdl.structure import * +from migen.fhdl.verilog import _printexpr as verilog_printexpr +from migen.fhdl.specials import * + +# LiteX Instance Verilog Generation ---------------------------------------------------------------- + +def _instance_generate_verilog(instance, ns, add_data_file): + r = instance.of + " " + parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), instance.items)) + if parameters: + r += "#(\n" + firstp = True + for p in parameters: + if not firstp: + r += ",\n" + firstp = False + r += "\t." + p.name + "(" + if isinstance(p.value, Constant): + r += verilog_printexpr(ns, p.value)[0] + elif isinstance(p.value, float): + r += str(p.value) + elif isinstance(p.value, Instance.PreformattedParam): + r += p.value + elif isinstance(p.value, str): + r += "\"" + p.value + "\"" + else: + raise TypeError + r += ")" + r += "\n) " + r += ns.get_name(instance) + if parameters: r += " " + r += "(\n" + firstp = True + for p in instance.items: + if isinstance(p, Instance._IO): + name_inst = p.name + name_design = verilog_printexpr(ns, p.expr)[0] + if not firstp: + r += ",\n" + firstp = False + r += "\t." + name_inst + "(" + name_design + ")" + if not firstp: + r += "\n" + if instance.synthesis_directive is not None: + synthesis_directive = "/* synthesis {} */".format(instance.synthesis_directive) + r += ")" + synthesis_directive + ";\n\n" + else: + r += ");\n\n" + return r diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index 87cf629d8..bce9ce3cb 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -2,7 +2,7 @@ # This file is part of LiteX (Adapted from Migen for LiteX usage). # # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq -# This file is Copyright (c) 2013-2021 Florent Kermarrec +# This file is Copyright (c) 2013-2023 Florent Kermarrec # This file is Copyright (c) 2013-2017 Robert Jordens # This file is Copyright (c) 2016-2018 whitequark # This file is Copyright (c) 2017 Adam Greig @@ -23,7 +23,7 @@ from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment from migen.fhdl.tools import * from migen.fhdl.conv_output import ConvOutput -from migen.fhdl.specials import Memory +from migen.fhdl.specials import Instance, Memory from litex.gen import LiteXContext from litex.gen.fhdl.namer import build_namespace @@ -529,6 +529,10 @@ def _generate_specials(name, overrides, specials, namespace, add_data_file, attr if isinstance(special, Memory): from litex.gen.fhdl.memory import _memory_generate_verilog pr = _memory_generate_verilog(name, special, namespace, add_data_file) + # Replace Migen Instance's emit_verilog with LiteX's implementation. + elif isinstance(special, Instance): + from litex.gen.fhdl.instance import _instance_generate_verilog + pr = _instance_generate_verilog(special, namespace, add_data_file) else: pr = call_special_classmethod(overrides, special, "emit_verilog", namespace, add_data_file) if pr is None: From 079a0a7b759ed3604b9d65fc057b60678ac2a5d0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:46:51 +0100 Subject: [PATCH 295/454] gen/fhdl/instance: First cleanup pass. --- litex/gen/fhdl/instance.py | 53 +++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/litex/gen/fhdl/instance.py b/litex/gen/fhdl/instance.py index b948d720c..ba08e4562 100644 --- a/litex/gen/fhdl/instance.py +++ b/litex/gen/fhdl/instance.py @@ -4,52 +4,69 @@ # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq # SPDX-License-Identifier: BSD-2-Clause -from migen.fhdl.structure import * -from migen.fhdl.verilog import _printexpr as verilog_printexpr -from migen.fhdl.specials import * +from migen.fhdl.structure import * +from migen.fhdl.verilog import _printexpr as verilog_printexpr +from migen.fhdl.specials import * # LiteX Instance Verilog Generation ---------------------------------------------------------------- def _instance_generate_verilog(instance, ns, add_data_file): r = instance.of + " " + + # Instance Parameters. + # -------------------- parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), instance.items)) if parameters: r += "#(\n" - firstp = True + first = True for p in parameters: - if not firstp: + if not first: r += ",\n" - firstp = False + first = False r += "\t." + p.name + "(" + # Constant. if isinstance(p.value, Constant): r += verilog_printexpr(ns, p.value)[0] + # Float. elif isinstance(p.value, float): r += str(p.value) + # Preformatted. elif isinstance(p.value, Instance.PreformattedParam): r += p.value + # String. elif isinstance(p.value, str): r += "\"" + p.value + "\"" else: raise TypeError r += ")" r += "\n) " + + # Instance IOs. + # ------------- r += ns.get_name(instance) - if parameters: r += " " + if parameters: + r += " " r += "(\n" - firstp = True - for p in instance.items: - if isinstance(p, Instance._IO): - name_inst = p.name - name_design = verilog_printexpr(ns, p.expr)[0] - if not firstp: + first = True + for io in instance.items: + if isinstance(io, Instance._IO): + name_inst = io.name + name_design = verilog_printexpr(ns, io.expr)[0] + if not first: r += ",\n" - firstp = False + first = False r += "\t." + name_inst + "(" + name_design + ")" - if not firstp: + if not first: r += "\n" + + # Instance Synthesis Directive. + # ----------------------------- if instance.synthesis_directive is not None: - synthesis_directive = "/* synthesis {} */".format(instance.synthesis_directive) - r += ")" + synthesis_directive + ";\n\n" + synthesis_directive = f"/* synthesis {instance.synthesis_directive} */" + r += ")" + synthesis_directive + ";\n" else: - r += ");\n\n" + r += ");\n" + + r += "\n" + return r From 18c0541e6aae0781c4897ecb55ac64ae4d86a620 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 11:53:32 +0100 Subject: [PATCH 296/454] gen/fhdl/instance: Add instance description. --- litex/gen/fhdl/instance.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/litex/gen/fhdl/instance.py b/litex/gen/fhdl/instance.py index ba08e4562..47f1913b1 100644 --- a/litex/gen/fhdl/instance.py +++ b/litex/gen/fhdl/instance.py @@ -11,7 +11,17 @@ # LiteX Instance Verilog Generation ---------------------------------------------------------------- def _instance_generate_verilog(instance, ns, add_data_file): - r = instance.of + " " + r = "" + + # Instance Description. + # --------------------- + r += "//" + "-"*78 + "\n" + r += f"// Instance {ns.get_name(instance)} of {instance.of} Module.\n" + r += "//" + "-"*78 + "\n" + + # Instance Name. + # -------------- + r += instance.of + " " # Instance Parameters. # -------------------- @@ -23,7 +33,7 @@ def _instance_generate_verilog(instance, ns, add_data_file): if not first: r += ",\n" first = False - r += "\t." + p.name + "(" + r += f"\t.{p.name}(" # Constant. if isinstance(p.value, Constant): r += verilog_printexpr(ns, p.value)[0] @@ -35,7 +45,7 @@ def _instance_generate_verilog(instance, ns, add_data_file): r += p.value # String. elif isinstance(p.value, str): - r += "\"" + p.value + "\"" + r += f"\"{p.value}\"" else: raise TypeError r += ")" From 4627e8958f4164abc9c2dc4baab6e63eba1e2c76 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 12:11:53 +0100 Subject: [PATCH 297/454] gen/fhdl/instance: Generate Parameters/Inputs/Outputs/InOuts separators and generate IOs in Input/Output/InOut order. --- litex/gen/fhdl/instance.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/litex/gen/fhdl/instance.py b/litex/gen/fhdl/instance.py index 47f1913b1..1eac1f115 100644 --- a/litex/gen/fhdl/instance.py +++ b/litex/gen/fhdl/instance.py @@ -29,6 +29,7 @@ def _instance_generate_verilog(instance, ns, add_data_file): if parameters: r += "#(\n" first = True + r += "\t// Parameters.\n" for p in parameters: if not first: r += ",\n" @@ -56,16 +57,24 @@ def _instance_generate_verilog(instance, ns, add_data_file): r += ns.get_name(instance) if parameters: r += " " - r += "(\n" + r += "(" + inputs = list(filter(lambda i: isinstance(i, Instance.Input), instance.items)) + outputs = list(filter(lambda i: isinstance(i, Instance.Output), instance.items)) + inouts = list(filter(lambda i: isinstance(i, Instance.InOut), instance.items)) first = True - for io in instance.items: - if isinstance(io, Instance._IO): - name_inst = io.name - name_design = verilog_printexpr(ns, io.expr)[0] - if not first: - r += ",\n" - first = False - r += "\t." + name_inst + "(" + name_design + ")" + for io in (inputs + outputs + inouts): + if not first: + r += ",\n" + if len(inputs) and (io is inputs[0]): + r += "\n\t// Inputs.\n" + if len(outputs) and (io is outputs[0]): + r += "\n\t// Outputs.\n" + if len(inouts) and (io is inouts[0]): + r += "\n\t// InOuts.\n" + name_inst = io.name + name_design = verilog_printexpr(ns, io.expr)[0] + first = False + r += f"\t.{name_inst}({name_design})" if not first: r += "\n" @@ -73,7 +82,7 @@ def _instance_generate_verilog(instance, ns, add_data_file): # ----------------------------- if instance.synthesis_directive is not None: synthesis_directive = f"/* synthesis {instance.synthesis_directive} */" - r += ")" + synthesis_directive + ";\n" + r += f"){synthesis_directive};\n" else: r += ");\n" From a1704a045e1edfc5ce2f5d56106476601b0bbe14 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 12:29:01 +0100 Subject: [PATCH 298/454] gen/fhdl/instance: Ident Parameters/IOs on max length of names. --- litex/gen/fhdl/instance.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/litex/gen/fhdl/instance.py b/litex/gen/fhdl/instance.py index 1eac1f115..ba5007355 100644 --- a/litex/gen/fhdl/instance.py +++ b/litex/gen/fhdl/instance.py @@ -2,12 +2,22 @@ # This file is part of LiteX (Adapted from Migen for LiteX usage). # # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq +# This file is Copyright (c) 2023 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause from migen.fhdl.structure import * from migen.fhdl.verilog import _printexpr as verilog_printexpr from migen.fhdl.specials import * +# Helpers ------------------------------------------------------------------------------------------ + +def get_max_name_length(ios): + r = 0 + for io in ios: + if len(io.name) > r: + r = len(io.name) + return r + # LiteX Instance Verilog Generation ---------------------------------------------------------------- def _instance_generate_verilog(instance, ns, add_data_file): @@ -26,6 +36,7 @@ def _instance_generate_verilog(instance, ns, add_data_file): # Instance Parameters. # -------------------- parameters = list(filter(lambda i: isinstance(i, Instance.Parameter), instance.items)) + ident = get_max_name_length(parameters) if parameters: r += "#(\n" first = True @@ -34,7 +45,7 @@ def _instance_generate_verilog(instance, ns, add_data_file): if not first: r += ",\n" first = False - r += f"\t.{p.name}(" + r += f"\t.{p.name}{' '*(ident-len(p.name))} (" # Constant. if isinstance(p.value, Constant): r += verilog_printexpr(ns, p.value)[0] @@ -61,7 +72,8 @@ def _instance_generate_verilog(instance, ns, add_data_file): inputs = list(filter(lambda i: isinstance(i, Instance.Input), instance.items)) outputs = list(filter(lambda i: isinstance(i, Instance.Output), instance.items)) inouts = list(filter(lambda i: isinstance(i, Instance.InOut), instance.items)) - first = True + first = True + ident = get_max_name_length(inputs + outputs + inouts) for io in (inputs + outputs + inouts): if not first: r += ",\n" @@ -74,7 +86,7 @@ def _instance_generate_verilog(instance, ns, add_data_file): name_inst = io.name name_design = verilog_printexpr(ns, io.expr)[0] first = False - r += f"\t.{name_inst}({name_design})" + r += f"\t.{name_inst}{' '*(ident-len(name_inst))} ({name_design})" if not first: r += "\n" From 6f431fa2b136fccd8efab32f4dd2a51f4ef9277e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 3 Nov 2023 14:24:06 +0100 Subject: [PATCH 299/454] gen/fhdl: Cleanup/Simplify hierarchy generation. --- litex/gen/fhdl/hierarchy.py | 12 ++++++++---- litex/gen/fhdl/verilog.py | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/litex/gen/fhdl/hierarchy.py b/litex/gen/fhdl/hierarchy.py index 17ff922dc..720fe0207 100644 --- a/litex/gen/fhdl/hierarchy.py +++ b/litex/gen/fhdl/hierarchy.py @@ -26,7 +26,8 @@ def get_tree(self, module, ident=0, with_modules=True, with_instances=True, with r = "" names = set() names.add(None) - # Modules / SubModules. + + # Modules / Sub-Modules. for name, mod in module._submodules: if name is None: n = 0 @@ -51,10 +52,13 @@ def get_tree(self, module, ident=0, with_modules=True, with_instances=True, with r += f"{self.tree_ident*ident}{self.tree_entry}{self._colorer(f'[{s.of}]', 'yellow')}\n" return r - def __repr__(self): - r = "\n" + def get_hierarchy(self): + r = "" r += f"{self._colorer(self.top.__class__.__name__, 'underline')}\n" r += self.get_tree(self.top) - r += f"{self._colorer('* ', 'cyan')}: Generated name.\n" + r += f"{self._colorer('* ', 'cyan')}: Generated name.\n" r += f"{self._colorer('[]', 'yellow')}: BlackBox.\n" return r + + def __repr__(self): + return f"\n{self.get_hierarchy()}" diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index bce9ce3cb..ce52fa355 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -89,11 +89,11 @@ def _generate_timescale(time_unit="1ns", time_precision="1ps"): # ------------------------------------------------------------------------------------------------ # def _generate_hierarchy(top): - hierarchy = LiteXHierarchyExplorer(top=top, depth=None, with_colors=False).__repr__() + hierarchy_explorer = LiteXHierarchyExplorer(top=top, depth=None, with_colors=False) r = "/*\n" - for l in hierarchy.split("\n"): + for l in hierarchy_explorer.get_hierarchy().split("\n"): r += l + "\n" - #r += "//" + l + "\n" + r = r[:-1] r += "*/\n" return r From f4e68d78ca8417081b5f7698b5e866a094b82bdd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 4 Nov 2023 20:55:56 +0100 Subject: [PATCH 300/454] cores/video: Fix missing h/vsync connection in SYNC state. --- litex/soc/cores/video.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 942ecba4a..832ff1795 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -702,7 +702,8 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 vtg_sink.ready.eq(~fsm.reset), If(vtg_sink.valid & vtg_sink.last, NextState("RUN") - ) + ), + vtg_sink.connect(source, keep={"hsync", "vsync"}), ) fsm.act("RUN", vtg_sink.ready.eq(1), From b0c0669ed3628fecf6898804b119b2b3a4905646 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 5 Nov 2023 08:18:43 +0100 Subject: [PATCH 301/454] cores/video/VideoFramebuffer: Skip first frame on enable to ensure proper VTG/DMA synchronization. --- litex/soc/cores/video.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index 832ff1795..b8d22f7d0 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -693,13 +693,18 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 video_pipe_source = self.cdc.source # Video Synchronization/Generation. + first = Signal() fsm = FSM(reset_state="SYNC") fsm = ClockDomainsRenamer(clock_domain)(fsm) fsm = ResetInserter()(fsm) self.submodules += fsm self.specials += MultiReg(self.dma.fsm.reset, fsm.reset, clock_domain) fsm.act("SYNC", - vtg_sink.ready.eq(~fsm.reset), + vtg_sink.ready.eq(1), + If(fsm.reset, + vtg_sink.ready.eq(0), + NextValue(first, 1) + ), If(vtg_sink.valid & vtg_sink.last, NextState("RUN") ), @@ -709,9 +714,13 @@ def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65 vtg_sink.ready.eq(1), If(vtg_sink.valid & vtg_sink.de, video_pipe_source.connect(source, keep={"valid", "ready"}), + If(first, + source.valid.eq(0) + ), vtg_sink.ready.eq(source.valid & source.ready), If(video_pipe_source.valid & video_pipe_source.last, - NextState("SYNC") + NextValue(first, 0), + NextState("SYNC"), ) ), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), From 1e805a8789114e36364e35c1470bb77ea55bb2bf Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 09:38:17 +0100 Subject: [PATCH 302/454] fhdl/namer: Remove debug and add docstring comments. --- litex/gen/fhdl/namer.py | 164 ++++++++++++++++++++++++++++++---------- 1 file changed, 123 insertions(+), 41 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 2596e17da..1a4b51fac 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -4,44 +4,37 @@ # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq # SPDX-License-Identifier: BSD-2-Clause -from collections import OrderedDict from itertools import combinations from migen.fhdl.structure import * - class _Node: + """A node in a hierarchy tree used for signal name resolution. + + Attributes: + signal_count (int): The count of signals in this node. + numbers (set): A set containing numbers associated with this node. + use_name (bool): Flag to determine if the node's name should be used in signal naming. + use_number (bool): Flag to determine if the node's number should be used in signal naming. + children (dict): A dictionary of child nodes. + """ def __init__(self): self.signal_count = 0 self.numbers = set() self.use_name = False self.use_number = False - self.children = OrderedDict() - - -def _display_tree(filename, tree): - from migen.util.treeviz import RenderNode - - def _to_render_node(name, node): - children = [_to_render_node(k, v) for k, v in node.children.items()] - if node.use_name: - if node.use_number: - color = (0.5, 0.9, 0.8) - else: - color = (0.8, 0.5, 0.9) - else: - if node.use_number: - color = (0.9, 0.8, 0.5) - else: - color = (0.8, 0.8, 0.8) - label = "{0}\n{1} signals\n{2}".format(name, node.signal_count, node.numbers) - return RenderNode(label, children, color=color) + self.children = {} - top = _to_render_node("top", tree) - top.to_svg(filename) +def _build_tree(signals, basic_tree=None): + """Builds a hierarchical tree of nodes based on the provided signals. + Parameters: + signals (iterable): An iterable of signals to be organized into a tree. + basic_tree (_Node, optional): A basic tree structure that the new tree is based upon. -def _build_tree(signals, basic_tree=None): + Returns: + _Node: The root node of the constructed hierarchical tree. + """ root = _Node() for signal in signals: current_b = basic_tree @@ -71,6 +64,15 @@ def _build_tree(signals, basic_tree=None): def _set_use_name(node, node_name=""): + """Determines whether names should be used in signal naming by examining child nodes. + + Parameters: + node (_Node): The current node in the tree. + node_name (str): The name of the node, used when the node's name needs to be included. + + Returns: + set: A set of tuples representing the names that are to be used. + """ cnames = [(k, _set_use_name(v, k)) for k, v in node.children.items()] for (c1_prefix, c1_names), (c2_prefix, c2_names) in combinations(cnames, 2): if not c1_names.isdisjoint(c2_names): @@ -92,6 +94,15 @@ def _set_use_name(node, node_name=""): def _name_signal(tree, signal): + """Generates a hierarchical name for a given signal based on the tree structure. + + Parameters: + tree (_Node): The root node of the tree used for name resolution. + signal : The signal object whose name is to be generated. + + Returns: + str: The generated hierarchical name for the signal. + """ elements = [] treepos = tree for step_name, step_n in signal.backtrace: @@ -110,10 +121,27 @@ def _name_signal(tree, signal): def _build_pnd_from_tree(tree, signals): + """Builds a dictionary mapping signals to their hierarchical names from a tree. + + Parameters: + tree (_Node): The tree that contains naming information. + signals (iterable): An iterable of signals that need to be named. + + Returns: + dict: A dictionary where keys are signals and values are their hierarchical names. + """ return dict((signal, _name_signal(tree, signal)) for signal in signals) def _invert_pnd(pnd): + """Inverts a signal-to-name dictionary to a name-to-signals dictionary. + + Parameters: + pnd (dict): A dictionary mapping signals to names. + + Returns: + dict: An inverted dictionary where keys are names and values are lists of signals. + """ inv_pnd = dict() for k, v in pnd.items(): inv_pnd[v] = inv_pnd.get(v, []) @@ -122,6 +150,14 @@ def _invert_pnd(pnd): def _list_conflicting_signals(pnd): + """Lists signals that have conflicting names in the provided mapping. + + Parameters: + pnd (dict): A dictionary mapping signals to names. + + Returns: + set: A set of signals that have name conflicts. + """ inv_pnd = _invert_pnd(pnd) r = set() for k, v in inv_pnd.items(): @@ -131,38 +167,42 @@ def _list_conflicting_signals(pnd): def _set_use_number(tree, signals): + """Sets nodes in the tree to use numbers based on signal counts to resolve name conflicts. + + Parameters: + tree (_Node): The tree that contains naming information. + signals (iterable): An iterable of signals that may have name conflicts. + + Returns: + None + """ for signal in signals: current = tree for step_name, step_n in signal.backtrace: current = current.children[step_name] current.use_number = current.signal_count > len(current.numbers) and len(current.numbers) > 1 -_debug = False +def _build_pnd_for_group(group_n, signals): + """Builds a signal-to-name dictionary for a specific group of signals. + Parameters: + group_n (int): The group number. + signals (iterable): The signals within the group. -def _build_pnd_for_group(group_n, signals): + Returns: + dict: A dictionary mapping signals to their hierarchical names. + """ basic_tree = _build_tree(signals) _set_use_name(basic_tree) - if _debug: - _display_tree("tree{0}_basic.svg".format(group_n), basic_tree) pnd = _build_pnd_from_tree(basic_tree, signals) # If there are conflicts, try splitting the tree by numbers on paths taken by conflicting signals. conflicting_signals = _list_conflicting_signals(pnd) if conflicting_signals: _set_use_number(basic_tree, conflicting_signals) - if _debug: - print("namer: using split-by-number strategy (group {0})".format(group_n)) - _display_tree("tree{0}_marked.svg".format(group_n), basic_tree) numbered_tree = _build_tree(signals, basic_tree) _set_use_name(numbered_tree) - if _debug: - _display_tree("tree{0}_numbered.svg".format(group_n), numbered_tree) pnd = _build_pnd_from_tree(numbered_tree, signals) - else: - if _debug: - print("namer: using basic strategy (group {0})".format(group_n)) - # ...then add number suffixes by DUID. inv_pnd = _invert_pnd(pnd) duid_suffixed = False @@ -171,13 +211,18 @@ def _build_pnd_for_group(group_n, signals): duid_suffixed = True for n, signal in enumerate(sorted(signals, key=lambda x: x.duid)): pnd[signal] += str(n) - if _debug and duid_suffixed: - print("namer: using DUID suffixes (group {0})".format(group_n)) - return pnd def _build_signal_groups(signals): + """Organizes signals into related groups. + + Parameters: + signals (iterable): An iterable of all signals to be organized. + + Returns: + list: A list of sets, each containing related signals. + """ r = [] for signal in signals: # Build chain of related signals. @@ -199,6 +244,15 @@ def _build_signal_groups(signals): def _build_pnd(signals): + """Builds a complete signal-to-name dictionary using a hierarchical tree. + + Parameters: + signals (iterable): An iterable of all signals to be named. + tree (_Node): The root node of the tree used for name resolution. + + Returns: + dict: A complete dictionary mapping signals to their hierarchical names. + """ groups = _build_signal_groups(signals) gpnds = [_build_pnd_for_group(n, gsignals) for n, gsignals in enumerate(groups)] pnd = dict() @@ -216,6 +270,15 @@ def _build_pnd(signals): def build_namespace(signals, reserved_keywords=set()): + """Constructs a namespace where each signal is given a unique hierarchical name. + + Parameters: + signals (iterable): An iterable of all signals to be named. + reserved_keywords (set, optional): A set of keywords that cannot be used as signal names. + + Returns: + Namespace: An object that contains the mapping of signals to unique names and provides methods to access them. + """ pnd = _build_pnd(signals) ns = Namespace(pnd, reserved_keywords) # Register Signals with name_override. @@ -226,6 +289,25 @@ def build_namespace(signals, reserved_keywords=set()): class Namespace: + """ + A Namespace object manages unique naming for signals within a hardware design. + + It ensures that each signal has a unique, conflict-free name within the design's namespace. This + includes taking into account reserved keywords and handling signals that may share the same name + by default (due to being instances of the same hardware module or component). + + Attributes: + counts (dict): A dictionary to keep track of the number of times a particular name has been used. + sigs (dict): A dictionary mapping signals to a unique identifier to avoid name conflicts. + pnd (dict): The primary name dictionary that maps signals to their base names. + clock_domains (dict): A dictionary managing the names of clock signals within various clock domains. + + Methods: + get_name(sig): Returns a unique name for the given signal. If the signal is associated with a + clock domain, it handles naming appropriately, considering resets and clock signals. For + regular signals, it uses overridden names or constructs names based on the signal's + hierarchical structure. + """ def __init__(self, pnd, reserved_keywords=set()): self.counts = {k: 1 for k in reserved_keywords} self.sigs = {} From 6214aa69af2effa8a14ddeac3ace4c19388597fb Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 10:52:44 +0100 Subject: [PATCH 303/454] gen/fhdl/namer: Simplify _build_tree and add comments. --- litex/gen/fhdl/namer.py | 63 +++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 1a4b51fac..8ba87142e 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -25,43 +25,46 @@ def __init__(self): self.use_number = False self.children = {} -def _build_tree(signals, basic_tree=None): - """Builds a hierarchical tree of nodes based on the provided signals. +def _build_tree(signals, base_tree=None): + """ + Constructs a hierarchical tree from signals, where each signal's backtrace contributes to the tree structure. Parameters: - signals (iterable): An iterable of signals to be organized into a tree. - basic_tree (_Node, optional): A basic tree structure that the new tree is based upon. + - signals (list): A list of signals to process. + - base_tree (Node, optional): A base tree to refine with number usage information. Returns: - _Node: The root node of the constructed hierarchical tree. + - Node: The root node of the constructed tree. """ root = _Node() + + # Iterate over each signal to be included in the tree. for signal in signals: - current_b = basic_tree - current = root + current = root current.signal_count += 1 + current_base = base_tree + + # Traverse or build the hierarchy of nodes based on the signal's backtrace. for name, number in signal.backtrace: - if basic_tree is None: - use_number = False - else: - current_b = current_b.children[name] - use_number = current_b.use_number - if use_number: - key = (name, number) - else: - key = name - try: - current = current.children[key] - except KeyError: - new = _Node() - current.children[key] = new - current = new + # Decide whether to use a numbered key based on the base tree. + use_number = False + if current_base: + current_base = current_base.children.get(name) + use_number = current_base.use_number if current_base else False + + # Create the appropriate key for the node. + key = (name, number) if use_number else name + # Use setdefault to either get the existing child node or create a new one. + current = current.children.setdefault(key, _Node()) + # Add the number to the set of numbers associated with this node. current.numbers.add(number) - if use_number: - current.all_numbers = sorted(current_b.numbers) + # Increment the count of signals that have traversed this node. current.signal_count += 1 - return root + # If numbering is used, sort and store all numbers associated with the base node. + if use_number: + current.all_numbers = sorted(current_base.numbers) + return root def _set_use_name(node, node_name=""): """Determines whether names should be used in signal naming by examining child nodes. @@ -192,15 +195,15 @@ def _build_pnd_for_group(group_n, signals): Returns: dict: A dictionary mapping signals to their hierarchical names. """ - basic_tree = _build_tree(signals) - _set_use_name(basic_tree) - pnd = _build_pnd_from_tree(basic_tree, signals) + base_tree = _build_tree(signals) + _set_use_name(base_tree) + pnd = _build_pnd_from_tree(base_tree, signals) # If there are conflicts, try splitting the tree by numbers on paths taken by conflicting signals. conflicting_signals = _list_conflicting_signals(pnd) if conflicting_signals: - _set_use_number(basic_tree, conflicting_signals) - numbered_tree = _build_tree(signals, basic_tree) + _set_use_number(base_tree, conflicting_signals) + numbered_tree = _build_tree(signals, base_tree) _set_use_name(numbered_tree) pnd = _build_pnd_from_tree(numbered_tree, signals) # ...then add number suffixes by DUID. From d28b7a1172fd126067b11530e83128dd09806fe9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 11:32:52 +0100 Subject: [PATCH 304/454] gen/fhdl/namer: Simplify _set_use_name/_build_pnd_from_tree and add comments. --- litex/gen/fhdl/namer.py | 109 ++++++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 8ba87142e..5bc3fede5 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -67,74 +67,73 @@ def _build_tree(signals, base_tree=None): return root def _set_use_name(node, node_name=""): - """Determines whether names should be used in signal naming by examining child nodes. - - Parameters: - node (_Node): The current node in the tree. - node_name (str): The name of the node, used when the node's name needs to be included. - - Returns: - set: A set of tuples representing the names that are to be used. """ - cnames = [(k, _set_use_name(v, k)) for k, v in node.children.items()] - for (c1_prefix, c1_names), (c2_prefix, c2_names) in combinations(cnames, 2): - if not c1_names.isdisjoint(c2_names): - node.children[c1_prefix].use_name = True - node.children[c2_prefix].use_name = True - r = set() - for c_prefix, c_names in cnames: - if node.children[c_prefix].use_name: - for c_name in c_names: - r.add((c_prefix, ) + c_name) + Recursively determines if node names should be used to ensure unique signal naming. + """ + required_names = set() # This will accumulate all names that ensure unique identification of signals. + + # Recursively collect names from children, identifying if any naming conflicts occur. + child_name_sets = { + child_name: _set_use_name(child_node, child_name) + for child_name, child_node in node.children.items() + } + + # Check for naming conflicts between all pairs of children. + for (child1_name, names1), (child2_name, names2) in combinations(child_name_sets.items(), 2): + if names1 & names2: # If there's an intersection, we have a naming conflict. + node.children[child1_name].use_name = node.children[child2_name].use_name = True + + # Collect names, prepending child's name if necessary. + for child_name, child_names in child_name_sets.items(): + if node.children[child_name].use_name: + # Prepend the child's name to ensure uniqueness. + required_names.update((child_name,) + name for name in child_names) else: - r |= c_names + required_names.update(child_names) - if node.signal_count > sum(c.signal_count for c in node.children.values()): + # If this node has its own signals, ensure its name is used. + if node.signal_count > sum(child.signal_count for child in node.children.values()): node.use_name = True - r.add((node_name, )) + required_names.add((node_name,)) # Add this node's name only if it has additional signals. - return r + return required_names +def _build_pnd_from_tree(tree, signals): + """ + Constructs a mapping of signals to their names derived from a tree structure. -def _name_signal(tree, signal): - """Generates a hierarchical name for a given signal based on the tree structure. - - Parameters: - tree (_Node): The root node of the tree used for name resolution. - signal : The signal object whose name is to be generated. - - Returns: - str: The generated hierarchical name for the signal. + This mapping is used to identify signals by their unique hierarchical path within the tree. The + tree structure has 'use_name' flags that influence the naming process. """ - elements = [] - treepos = tree - for step_name, step_n in signal.backtrace: - try: - treepos = treepos.children[(step_name, step_n)] - use_number = True - except KeyError: - treepos = treepos.children[step_name] - use_number = False - if treepos.use_name: - elname = step_name - if use_number: - elname += str(treepos.all_numbers.index(step_n)) - elements.append(elname) - return "_".join(elements) + # Initialize a dictionary to hold the signal names. + pnd = {} -def _build_pnd_from_tree(tree, signals): - """Builds a dictionary mapping signals to their hierarchical names from a tree. + # Process each signal to build its hierarchical name. + for signal in signals: + # Collect name parts for the hierarchical name. + elements = [] + # Start traversing the tree from the root. + treepos = tree - Parameters: - tree (_Node): The tree that contains naming information. - signals (iterable): An iterable of signals that need to be named. + # Walk through the signal's history to assemble its name. + for step_name, step_n in signal.backtrace: + # Navigate the tree according to the signal's path. + treepos = treepos.children.get((step_name, step_n)) or treepos.children.get(step_name) + # Check if the number is part of the name based on the tree node. + use_number = step_n in treepos.all_numbers if hasattr(treepos, 'all_numbers') else False - Returns: - dict: A dictionary where keys are signals and values are their hierarchical names. - """ - return dict((signal, _name_signal(tree, signal)) for signal in signals) + # If the tree node's name is to be used, add it to the elements. + if treepos.use_name: + # Create the name part, including the number if necessary. + element_name = step_name if not use_number else f"{step_name}{treepos.all_numbers.index(step_n)}" + elements.append(element_name) + + # Combine the name parts into the signal's full name. + pnd[signal] = "_".join(elements) + # Return the completed name dictionary. + return pnd def _invert_pnd(pnd): """Inverts a signal-to-name dictionary to a name-to-signals dictionary. From 36e47052b2acf8cd00ee1a216d51ef45b2ec19d3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 11:49:48 +0100 Subject: [PATCH 305/454] gen/fhdl/namer: Simplify _invert_pnd/_list_conflicting_signals/_set_use_number/_build_pnd_for_group and add comments. --- litex/gen/fhdl/namer.py | 101 ++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 5bc3fede5..ba3eac30d 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -136,21 +136,25 @@ def _build_pnd_from_tree(tree, signals): return pnd def _invert_pnd(pnd): - """Inverts a signal-to-name dictionary to a name-to-signals dictionary. + """ + Inverts a signal-to-name dictionary to a name-to-signals dictionary. Parameters: pnd (dict): A dictionary mapping signals to names. Returns: - dict: An inverted dictionary where keys are names and values are lists of signals. + dict: An inverted dictionary where keys are names and values are lists of signals with that name. """ - inv_pnd = dict() - for k, v in pnd.items(): - inv_pnd[v] = inv_pnd.get(v, []) - inv_pnd[v].append(k) + inv_pnd = {} + for signal, name in pnd.items(): + # Get the list of signals for the current name, or initialize it if not present. + signals_with_name = inv_pnd.get(name, []) + # Add the current signal to the list. + signals_with_name.append(signal) + # Place the updated list back in the dictionary. + inv_pnd[name] = signals_with_name return inv_pnd - def _list_conflicting_signals(pnd): """Lists signals that have conflicting names in the provided mapping. @@ -160,29 +164,43 @@ def _list_conflicting_signals(pnd): Returns: set: A set of signals that have name conflicts. """ + # Invert the signal-to-name mapping to a name-to-signals mapping. inv_pnd = _invert_pnd(pnd) - r = set() - for k, v in inv_pnd.items(): - if len(v) > 1: - r.update(v) - return r + # Prepare a set to hold signals with conflicting names. + conflicts = set() + + # Iterate through the inverted dictionary. + for name, signals in inv_pnd.items(): + # If there is more than one signal for this name, it means there is a conflict. + if len(signals) > 1: + # Add all conflicting signals to our set. + conflicts.update(signals) + + # Return the set of all signals that have name conflicts. + return conflicts def _set_use_number(tree, signals): - """Sets nodes in the tree to use numbers based on signal counts to resolve name conflicts. + """ + Updates nodes to use number suffixes to resolve naming conflicts when necessary. Parameters: - tree (_Node): The tree that contains naming information. - signals (iterable): An iterable of signals that may have name conflicts. + tree (_Node): The root node of the naming tree. + signals (iterable): Signals potentially causing naming conflicts. Returns: - None + None: Tree is modified in place. """ for signal in signals: - current = tree - for step_name, step_n in signal.backtrace: - current = current.children[step_name] - current.use_number = current.signal_count > len(current.numbers) and len(current.numbers) > 1 + node = tree # Start traversal from the root node. + + # Traverse the signal's path and decide if numbering is needed. + for step_name, _ in signal.backtrace: + node = node.children[step_name] # Proceed to the next node. + # Set use_number if signal count exceeds unique identifiers. + if not node.use_number: + node.use_number = node.signal_count > len(node.numbers) > 1 + # Once use_number is True, it stays True. def _build_pnd_for_group(group_n, signals): """Builds a signal-to-name dictionary for a specific group of signals. @@ -194,26 +212,29 @@ def _build_pnd_for_group(group_n, signals): Returns: dict: A dictionary mapping signals to their hierarchical names. """ - base_tree = _build_tree(signals) - _set_use_name(base_tree) - pnd = _build_pnd_from_tree(base_tree, signals) - - # If there are conflicts, try splitting the tree by numbers on paths taken by conflicting signals. - conflicting_signals = _list_conflicting_signals(pnd) - if conflicting_signals: - _set_use_number(base_tree, conflicting_signals) - numbered_tree = _build_tree(signals, base_tree) - _set_use_name(numbered_tree) - pnd = _build_pnd_from_tree(numbered_tree, signals) - # ...then add number suffixes by DUID. - inv_pnd = _invert_pnd(pnd) - duid_suffixed = False - for name, signals in inv_pnd.items(): - if len(signals) > 1: - duid_suffixed = True - for n, signal in enumerate(sorted(signals, key=lambda x: x.duid)): - pnd[signal] += str(n) - return pnd + + # Construct initial naming tree and name dictionary. + tree = _build_tree(signals) + _set_use_name(tree) + name_dict = _build_pnd_from_tree(tree, signals) + + # Address naming conflicts by introducing numbers. + conflicts = _list_conflicting_signals(name_dict) + if conflicts: + _set_use_number(tree, conflicts) + # Rebuild tree and name dictionary if there were conflicts. + tree = _build_tree(signals, tree) + _set_use_name(tree) + name_dict = _build_pnd_from_tree(tree, signals) + + # Disambiguate remaining conflicts using signal's unique identifier (DUID). + inv_name_dict = _invert_pnd(name_dict) + for names, sigs in inv_name_dict.items(): + if len(sigs) > 1: + for idx, sig in enumerate(sorted(sigs, key=lambda s: s.duid)): + name_dict[sig] += f"{idx}" + + return name_dict def _build_signal_groups(signals): From a65d471ed2ffb25cd0e86c7e24db0d411fdf8358 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 11:58:29 +0100 Subject: [PATCH 306/454] gen/fhdl/namer: Simplify _invert_pnd_build_signal_groups/_build_pnd and add comments. --- litex/gen/fhdl/namer.py | 75 +++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index ba3eac30d..6eda0e225 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -246,24 +246,29 @@ def _build_signal_groups(signals): Returns: list: A list of sets, each containing related signals. """ - r = [] + grouped_signals = [] + + # Create groups of related signals. for signal in signals: - # Build chain of related signals. - related_list = [] - cur_signal = signal - while cur_signal is not None: - related_list.insert(0, cur_signal) - cur_signal = cur_signal.related - # Add to groups. - for _ in range(len(related_list) - len(r)): - r.append(set()) - for target_set, source_signal in zip(r, related_list): - target_set.add(source_signal) - # With the algorithm above and a list of all signals, a signal appears in all groups of a lower - # number than its. Make signals appear only in their group of highest number. - for s1, s2 in zip(r, r[1:]): - s1 -= s2 - return r + chain = [] + # Trace back the chain of related signals. + while signal is not None: + chain.insert(0, signal) + signal = signal.related + + # Ensure there's a set for each level of relation. + while len(grouped_signals) < len(chain): + grouped_signals.append(set()) + + # Assign signals to their respective group. + for group, sig in zip(grouped_signals, chain): + group.add(sig) + + # Ensure signals only appear in their most specific group. + for i in range(len(grouped_signals) - 1): + grouped_signals[i] -= grouped_signals[i + 1] + + return grouped_signals def _build_pnd(signals): @@ -276,19 +281,31 @@ def _build_pnd(signals): Returns: dict: A complete dictionary mapping signals to their hierarchical names. """ + # Group the signals based on their relationships. groups = _build_signal_groups(signals) - gpnds = [_build_pnd_for_group(n, gsignals) for n, gsignals in enumerate(groups)] - pnd = dict() - for gn, gpnd in enumerate(gpnds): - for signal, name in gpnd.items(): - result = name - cur_gn = gn - cur_signal = signal - while cur_signal.related is not None: - cur_signal = cur_signal.related - cur_gn -= 1 - result = gpnds[cur_gn][cur_signal] + "_" + result - pnd[signal] = result + + # Generate a name mapping for each group. + group_pnd_mappings = [_build_pnd_for_group(group_number, group_signals) + for group_number, group_signals in enumerate(groups)] + + # Create the final signal-to-name mapping. + pnd = {} + for group_number, group_pnd in enumerate(group_pnd_mappings): + for signal, name in group_pnd.items(): + # Build the full hierarchical name for each signal. + hierarchical_name = name + current_group_number = group_number + current_signal = signal + + # Traverse up the signal's group relationships to prepend parent names. + while current_signal.related is not None: + current_signal = current_signal.related + current_group_number -= 1 + hierarchical_name = f"{group_pnd_mappings[current_group_number][current_signal]}_{hierarchical_name}" + + # Map the signal to its full hierarchical name. + pnd[signal] = hierarchical_name + return pnd From 9548259a5c0c193b9e4ca86b2cfc4bc6d3f8ccf4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 12:03:17 +0100 Subject: [PATCH 307/454] gen/fhdl/namer: Simplify build_namespace and add comments. --- litex/gen/fhdl/namer.py | 46 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 6eda0e225..d58504f74 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -8,6 +8,8 @@ from migen.fhdl.structure import * +# Private Classes/Helpers -------------------------------------------------------------------------- + class _Node: """A node in a hierarchy tree used for signal name resolution. @@ -308,25 +310,7 @@ def _build_pnd(signals): return pnd - -def build_namespace(signals, reserved_keywords=set()): - """Constructs a namespace where each signal is given a unique hierarchical name. - - Parameters: - signals (iterable): An iterable of all signals to be named. - reserved_keywords (set, optional): A set of keywords that cannot be used as signal names. - - Returns: - Namespace: An object that contains the mapping of signals to unique names and provides methods to access them. - """ - pnd = _build_pnd(signals) - ns = Namespace(pnd, reserved_keywords) - # Register Signals with name_override. - swno = {signal for signal in signals if signal.name_override is not None} - for signal in sorted(swno, key=lambda x: x.duid): - ns.get_name(signal) - return ns - +# Public Classes/Helpers --------------------------------------------------------------------------- class Namespace: """ @@ -392,3 +376,27 @@ def get_name(self, sig): # Return Name. return sig_name + suffix + +def build_namespace(signals, reserved_keywords=set()): + """Constructs a namespace where each signal is given a unique hierarchical name. + + Parameters: + signals (iterable): An iterable of all signals to be named. + reserved_keywords (set, optional): A set of keywords that cannot be used as signal names. + + Returns: + Namespace: An object that contains the mapping of signals to unique names and provides methods to access them. + """ + + # Create the primary signal-to-name dictionary. + pnd = _build_pnd(signals) + + # Initialize the namespace with reserved keywords and the primary mapping. + namespace = Namespace(pnd, reserved_keywords) + + # Handle signals with overridden names, ensuring they are processed in a consistent order. + signals_with_name_override = filter(lambda s: s.name_override is not None, signals) + for signal in sorted(signals_with_name_override, key=lambda s: s.duid): + namespace.get_name(signal) + + return namespace \ No newline at end of file From 19a3ab2614395d8ffebb85ddcbedc530eda09f2e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 12:51:28 +0100 Subject: [PATCH 308/454] gen/fhdl/namer: Improve class/variable names. --- litex/gen/fhdl/namer.py | 140 ++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index d58504f74..4b3c8f688 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -10,7 +10,7 @@ # Private Classes/Helpers -------------------------------------------------------------------------- -class _Node: +class HierarchyNode: """A node in a hierarchy tree used for signal name resolution. Attributes: @@ -27,18 +27,18 @@ def __init__(self): self.use_number = False self.children = {} -def _build_tree(signals, base_tree=None): +def build_hierarchy_tree(signals, base_tree=None): """ Constructs a hierarchical tree from signals, where each signal's backtrace contributes to the tree structure. Parameters: - - signals (list): A list of signals to process. - - base_tree (Node, optional): A base tree to refine with number usage information. + - signals (list): A list of signals to process. + - base_tree (HierarchyNode, optional): A base tree to refine with number usage information. Returns: - - Node: The root node of the constructed tree. + - HierarchyNode: The root node of the constructed tree. """ - root = _Node() + root = HierarchyNode() # Iterate over each signal to be included in the tree. for signal in signals: @@ -57,7 +57,7 @@ def _build_tree(signals, base_tree=None): # Create the appropriate key for the node. key = (name, number) if use_number else name # Use setdefault to either get the existing child node or create a new one. - current = current.children.setdefault(key, _Node()) + current = current.children.setdefault(key, HierarchyNode()) # Add the number to the set of numbers associated with this node. current.numbers.add(number) # Increment the count of signals that have traversed this node. @@ -68,7 +68,7 @@ def _build_tree(signals, base_tree=None): return root -def _set_use_name(node, node_name=""): +def determine_name_usage(node, node_name=""): """ Recursively determines if node names should be used to ensure unique signal naming. """ @@ -76,7 +76,7 @@ def _set_use_name(node, node_name=""): # Recursively collect names from children, identifying if any naming conflicts occur. child_name_sets = { - child_name: _set_use_name(child_node, child_name) + child_name: determine_name_usage(child_node, child_name) for child_name, child_node in node.children.items() } @@ -100,7 +100,7 @@ def _set_use_name(node, node_name=""): return required_names -def _build_pnd_from_tree(tree, signals): +def build_signal_name_dict_from_tree(tree, signals): """ Constructs a mapping of signals to their names derived from a tree structure. @@ -109,7 +109,7 @@ def _build_pnd_from_tree(tree, signals): """ # Initialize a dictionary to hold the signal names. - pnd = {} + name_dict = {} # Process each signal to build its hierarchical name. for signal in signals: @@ -132,48 +132,48 @@ def _build_pnd_from_tree(tree, signals): elements.append(element_name) # Combine the name parts into the signal's full name. - pnd[signal] = "_".join(elements) + name_dict[signal] = "_".join(elements) # Return the completed name dictionary. - return pnd + return name_dict -def _invert_pnd(pnd): +def invert_signal_name_dict(name_dict): """ Inverts a signal-to-name dictionary to a name-to-signals dictionary. Parameters: - pnd (dict): A dictionary mapping signals to names. + name_dict (dict): A dictionary mapping signals to names. Returns: dict: An inverted dictionary where keys are names and values are lists of signals with that name. """ - inv_pnd = {} - for signal, name in pnd.items(): + inverted_dict = {} + for signal, name in name_dict.items(): # Get the list of signals for the current name, or initialize it if not present. - signals_with_name = inv_pnd.get(name, []) + signals_with_name = inverted_dict.get(name, []) # Add the current signal to the list. signals_with_name.append(signal) # Place the updated list back in the dictionary. - inv_pnd[name] = signals_with_name - return inv_pnd + inverted_dict[name] = signals_with_name + return inverted_dict -def _list_conflicting_signals(pnd): +def list_conflicting_signals(name_dict): """Lists signals that have conflicting names in the provided mapping. Parameters: - pnd (dict): A dictionary mapping signals to names. + name_dict (dict): A dictionary mapping signals to names. Returns: set: A set of signals that have name conflicts. """ # Invert the signal-to-name mapping to a name-to-signals mapping. - inv_pnd = _invert_pnd(pnd) + inverted_dict = invert_signal_name_dict(name_dict) # Prepare a set to hold signals with conflicting names. conflicts = set() # Iterate through the inverted dictionary. - for name, signals in inv_pnd.items(): + for name, signals in inverted_dict.items(): # If there is more than one signal for this name, it means there is a conflict. if len(signals) > 1: # Add all conflicting signals to our set. @@ -182,13 +182,13 @@ def _list_conflicting_signals(pnd): # Return the set of all signals that have name conflicts. return conflicts -def _set_use_number(tree, signals): +def set_number_usage(tree, signals): """ Updates nodes to use number suffixes to resolve naming conflicts when necessary. Parameters: - tree (_Node): The root node of the naming tree. - signals (iterable): Signals potentially causing naming conflicts. + tree (HierarchyNode): The root node of the naming tree. + signals (iterable): Signals potentially causing naming conflicts. Returns: None: Tree is modified in place. @@ -204,11 +204,11 @@ def _set_use_number(tree, signals): node.use_number = node.signal_count > len(node.numbers) > 1 # Once use_number is True, it stays True. -def _build_pnd_for_group(group_n, signals): +def build_signal_name_dict_for_group(group_number, signals): """Builds a signal-to-name dictionary for a specific group of signals. Parameters: - group_n (int): The group number. + group_number (int): The group number. signals (iterable): The signals within the group. Returns: @@ -216,21 +216,21 @@ def _build_pnd_for_group(group_n, signals): """ # Construct initial naming tree and name dictionary. - tree = _build_tree(signals) - _set_use_name(tree) - name_dict = _build_pnd_from_tree(tree, signals) + tree = build_hierarchy_tree(signals) + determine_name_usage(tree) + name_dict = build_signal_name_dict_from_tree(tree, signals) # Address naming conflicts by introducing numbers. - conflicts = _list_conflicting_signals(name_dict) + conflicts = list_conflicting_signals(name_dict) if conflicts: - _set_use_number(tree, conflicts) + set_number_usage(tree, conflicts) # Rebuild tree and name dictionary if there were conflicts. - tree = _build_tree(signals, tree) - _set_use_name(tree) - name_dict = _build_pnd_from_tree(tree, signals) + tree = build_hierarchy_tree(signals, tree) + determine_name_usage(tree) + name_dict = build_signal_name_dict_from_tree(tree, signals) # Disambiguate remaining conflicts using signal's unique identifier (DUID). - inv_name_dict = _invert_pnd(name_dict) + inv_name_dict = invert_signal_name_dict(name_dict) for names, sigs in inv_name_dict.items(): if len(sigs) > 1: for idx, sig in enumerate(sorted(sigs, key=lambda s: s.duid)): @@ -239,7 +239,7 @@ def _build_pnd_for_group(group_n, signals): return name_dict -def _build_signal_groups(signals): +def build_signal_groups(signals): """Organizes signals into related groups. Parameters: @@ -272,49 +272,48 @@ def _build_signal_groups(signals): return grouped_signals - -def _build_pnd(signals): +def build_signal_name_dict(signals): """Builds a complete signal-to-name dictionary using a hierarchical tree. Parameters: - signals (iterable): An iterable of all signals to be named. - tree (_Node): The root node of the tree used for name resolution. + signals (iterable): An iterable of all signals to be named. + tree (HierarchyNode): The root node of the tree used for name resolution. Returns: dict: A complete dictionary mapping signals to their hierarchical names. """ # Group the signals based on their relationships. - groups = _build_signal_groups(signals) + groups = build_signal_groups(signals) # Generate a name mapping for each group. - group_pnd_mappings = [_build_pnd_for_group(group_number, group_signals) - for group_number, group_signals in enumerate(groups)] + group_name_dict_mappings = [build_signal_name_dict_for_group(group_number, group_signals) + for group_number, group_signals in enumerate(groups)] # Create the final signal-to-name mapping. - pnd = {} - for group_number, group_pnd in enumerate(group_pnd_mappings): - for signal, name in group_pnd.items(): + name_dict = {} + for group_number, group_name_dict in enumerate(group_name_dict_mappings): + for signal, name in group_name_dict.items(): # Build the full hierarchical name for each signal. - hierarchical_name = name + hierarchical_name = name current_group_number = group_number - current_signal = signal + current_signal = signal # Traverse up the signal's group relationships to prepend parent names. while current_signal.related is not None: - current_signal = current_signal.related + current_signal = current_signal.related current_group_number -= 1 - hierarchical_name = f"{group_pnd_mappings[current_group_number][current_signal]}_{hierarchical_name}" + hierarchical_name = f"{group_name_dict_mappings[current_group_number][current_signal]}_{hierarchical_name}" # Map the signal to its full hierarchical name. - pnd[signal] = hierarchical_name + name_dict[signal] = hierarchical_name - return pnd + return name_dict # Public Classes/Helpers --------------------------------------------------------------------------- -class Namespace: +class SignalNamespace: """ - A Namespace object manages unique naming for signals within a hardware design. + A SignalNamespace object manages unique naming for signals within a hardware design. It ensures that each signal has a unique, conflict-free name within the design's namespace. This includes taking into account reserved keywords and handling signals that may share the same name @@ -323,7 +322,7 @@ class Namespace: Attributes: counts (dict): A dictionary to keep track of the number of times a particular name has been used. sigs (dict): A dictionary mapping signals to a unique identifier to avoid name conflicts. - pnd (dict): The primary name dictionary that maps signals to their base names. + name_dict (dict): The primary name dictionary that maps signals to their base names. clock_domains (dict): A dictionary managing the names of clock signals within various clock domains. Methods: @@ -332,10 +331,10 @@ class Namespace: regular signals, it uses overridden names or constructs names based on the signal's hierarchical structure. """ - def __init__(self, pnd, reserved_keywords=set()): - self.counts = {k: 1 for k in reserved_keywords} - self.sigs = {} - self.pnd = pnd + def __init__(self, name_dict, reserved_keywords=set()): + self.counts = {k: 1 for k in reserved_keywords} + self.sigs = {} + self.name_dict = name_dict self.clock_domains = dict() def get_name(self, sig): @@ -357,9 +356,9 @@ def get_name(self, sig): # Use Name's override when set... if sig.name_override is not None: sig_name = sig.name_override - # ... else get Name from pnd. + # ... else get Name from name_dict. else: - sig_name = self.pnd[sig] + sig_name = self.name_dict[sig] # Check/Add numbering suffix when required. # ----------------------------------------- @@ -370,16 +369,15 @@ def get_name(self, sig): n = self.counts[sig_name] except KeyError: n = 0 - self.sigs[sig] = n + self.sigs[sig] = n self.counts[sig_name] = n + 1 suffix = "" if n == 0 else f"_{n}" # Return Name. return sig_name + suffix -def build_namespace(signals, reserved_keywords=set()): +def build_signal_namespace(signals, reserved_keywords=set()): """Constructs a namespace where each signal is given a unique hierarchical name. - Parameters: signals (iterable): An iterable of all signals to be named. reserved_keywords (set, optional): A set of keywords that cannot be used as signal names. @@ -389,14 +387,16 @@ def build_namespace(signals, reserved_keywords=set()): """ # Create the primary signal-to-name dictionary. - pnd = _build_pnd(signals) + pnd = build_signal_name_dict(signals) # Initialize the namespace with reserved keywords and the primary mapping. - namespace = Namespace(pnd, reserved_keywords) + namespace = SignalNamespace(pnd, reserved_keywords) # Handle signals with overridden names, ensuring they are processed in a consistent order. signals_with_name_override = filter(lambda s: s.name_override is not None, signals) for signal in sorted(signals_with_name_override, key=lambda s: s.duid): namespace.get_name(signal) - return namespace \ No newline at end of file + return namespace + +build_namespace = build_signal_namespace \ No newline at end of file From 16804acaa8fb997da981dfef751d858761d4759f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 13:19:19 +0100 Subject: [PATCH 309/454] gen/fhdl/namer: Add update_hierarchy_node function to reduce build_hierarchy_tree complexity. --- litex/gen/fhdl/namer.py | 45 +++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 4b3c8f688..e5c82756a 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -27,6 +27,34 @@ def __init__(self): self.use_number = False self.children = {} +def update_hierarchy_node(current, name, number, use_number, current_base): + """ + Updates or creates a hierarchy node based on the current position, name, and number. + If numbering is used, sorts and stores all numbers associated with the base node. + + Parameters: + curren t (HierarchyNode): The current node in the hierarchy. + name (str): The name of the current hierarchy level. + number (int): The number associated with the current hierarchy level. + use_number (bool): Flag indicating whether to use the number in the hierarchy. + current_base (HierarchyNode): The base node for number usage information. + + Returns: + HierarchyNode: The updated or created node. + """ + # Create the appropriate key for the node. + key = (name, number) if use_number else name + # Use setdefault to either get the existing child node or create a new one. + current = current.children.setdefault(key, HierarchyNode()) + # Add the number to the set of numbers associated with this node. + current.numbers.add(number) + # Increment the count of signals that have traversed this node. + current.signal_count += 1 + # If numbering is used, sort and store all numbers associated with the base node. + if use_number and current_base: + current.all_numbers = sorted(current_base.numbers) + return current + def build_hierarchy_tree(signals, base_tree=None): """ Constructs a hierarchical tree from signals, where each signal's backtrace contributes to the tree structure. @@ -52,19 +80,10 @@ def build_hierarchy_tree(signals, base_tree=None): use_number = False if current_base: current_base = current_base.children.get(name) - use_number = current_base.use_number if current_base else False - - # Create the appropriate key for the node. - key = (name, number) if use_number else name - # Use setdefault to either get the existing child node or create a new one. - current = current.children.setdefault(key, HierarchyNode()) - # Add the number to the set of numbers associated with this node. - current.numbers.add(number) - # Increment the count of signals that have traversed this node. - current.signal_count += 1 - # If numbering is used, sort and store all numbers associated with the base node. - if use_number: - current.all_numbers = sorted(current_base.numbers) + use_number = current_base.use_number if current_base else False + + # Update the current node in the hierarchy. + current = update_hierarchy_node(current, name, number, use_number, current_base) return root From 0efccae8b41bd4e6d586a418c1e9da20f8616a68 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 13:34:23 +0100 Subject: [PATCH 310/454] gen/fhdl/namer: Simplify/Remove some redundancies. --- litex/gen/fhdl/namer.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index e5c82756a..2b720e5c7 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -70,8 +70,7 @@ def build_hierarchy_tree(signals, base_tree=None): # Iterate over each signal to be included in the tree. for signal in signals: - current = root - current.signal_count += 1 + current = root current_base = base_tree # Traverse or build the hierarchy of nodes based on the signal's backtrace. @@ -285,10 +284,6 @@ def build_signal_groups(signals): for group, sig in zip(grouped_signals, chain): group.add(sig) - # Ensure signals only appear in their most specific group. - for i in range(len(grouped_signals) - 1): - grouped_signals[i] -= grouped_signals[i + 1] - return grouped_signals def build_signal_name_dict(signals): @@ -390,10 +385,11 @@ def get_name(self, sig): n = 0 self.sigs[sig] = n self.counts[sig_name] = n + 1 - suffix = "" if n == 0 else f"_{n}" + if n > 0: + sig_name += f"_{n}" # Return Name. - return sig_name + suffix + return sig_name def build_signal_namespace(signals, reserved_keywords=set()): """Constructs a namespace where each signal is given a unique hierarchical name. @@ -413,8 +409,6 @@ def build_signal_namespace(signals, reserved_keywords=set()): # Handle signals with overridden names, ensuring they are processed in a consistent order. signals_with_name_override = filter(lambda s: s.name_override is not None, signals) - for signal in sorted(signals_with_name_override, key=lambda s: s.duid): - namespace.get_name(signal) return namespace From c0057672d6e88c16f92410bfe5073847deb9dd83 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 13:43:14 +0100 Subject: [PATCH 311/454] gen/fhdl/namer: Split build_signal_name_dict with build_hierarchical_name and update_name_dict_with_group. --- litex/gen/fhdl/namer.py | 64 ++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 2b720e5c7..b2a09c48b 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -286,6 +286,49 @@ def build_signal_groups(signals): return grouped_signals +def build_hierarchical_name(signal, group_number, group_name_dict_mappings): + """Builds the hierarchical name for a signal. + + Parameters: + signal (Signal): The signal to build the name for. + group_number (int): The group number of the signal. + group_name_dict_mappings (list): The list of all group name dictionaries. + + Returns: + str: The hierarchical name for the signal. + """ + hierarchical_name = group_name_dict_mappings[group_number][signal] + current_group_number = group_number + current_signal = signal + + # Traverse up the signal's group relationships to prepend parent names. + while current_signal.related is not None: + current_signal = current_signal.related + current_group_number -= 1 + parent_name = group_name_dict_mappings[current_group_number][current_signal] + hierarchical_name = f"{parent_name}_{hierarchical_name}" + + return hierarchical_name + +def update_name_dict_with_group(name_dict, group_number, group_name_dict, group_name_dict_mappings): + """Updates the name dictionary with hierarchical names for a specific group. + + Parameters: + name_dict (dict): The dictionary to update. + group_number (int): The current group number. + group_name_dict (dict): The name dictionary for the current group. + group_name_dict_mappings (list): The list of all group name dictionaries. + + Returns: + None: The name_dict is updated in place. + """ + for signal, name in group_name_dict.items(): + hierarchical_name = build_hierarchical_name( + signal, group_number, group_name_dict_mappings + ) + name_dict[signal] = hierarchical_name + + def build_signal_name_dict(signals): """Builds a complete signal-to-name dictionary using a hierarchical tree. @@ -300,26 +343,15 @@ def build_signal_name_dict(signals): groups = build_signal_groups(signals) # Generate a name mapping for each group. - group_name_dict_mappings = [build_signal_name_dict_for_group(group_number, group_signals) - for group_number, group_signals in enumerate(groups)] + group_name_dict_mappings = [ + build_signal_name_dict_for_group(group_number, group_signals) + for group_number, group_signals in enumerate(groups) + ] # Create the final signal-to-name mapping. name_dict = {} for group_number, group_name_dict in enumerate(group_name_dict_mappings): - for signal, name in group_name_dict.items(): - # Build the full hierarchical name for each signal. - hierarchical_name = name - current_group_number = group_number - current_signal = signal - - # Traverse up the signal's group relationships to prepend parent names. - while current_signal.related is not None: - current_signal = current_signal.related - current_group_number -= 1 - hierarchical_name = f"{group_name_dict_mappings[current_group_number][current_signal]}_{hierarchical_name}" - - # Map the signal to its full hierarchical name. - name_dict[signal] = hierarchical_name + update_name_dict_with_group(name_dict, group_number, group_name_dict, group_name_dict_mappings) return name_dict From c8a96b8d7918e6b5f88775c47c7e7a3e571b4625 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 13:52:02 +0100 Subject: [PATCH 312/454] gen/fhdl/namer: Add update method to HierarchyNode to replace update_hierarchy_node. --- litex/gen/fhdl/namer.py | 55 ++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index b2a09c48b..415c0be4e 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -27,33 +27,32 @@ def __init__(self): self.use_number = False self.children = {} -def update_hierarchy_node(current, name, number, use_number, current_base): - """ - Updates or creates a hierarchy node based on the current position, name, and number. - If numbering is used, sorts and stores all numbers associated with the base node. - - Parameters: - curren t (HierarchyNode): The current node in the hierarchy. - name (str): The name of the current hierarchy level. - number (int): The number associated with the current hierarchy level. - use_number (bool): Flag indicating whether to use the number in the hierarchy. - current_base (HierarchyNode): The base node for number usage information. - - Returns: - HierarchyNode: The updated or created node. - """ - # Create the appropriate key for the node. - key = (name, number) if use_number else name - # Use setdefault to either get the existing child node or create a new one. - current = current.children.setdefault(key, HierarchyNode()) - # Add the number to the set of numbers associated with this node. - current.numbers.add(number) - # Increment the count of signals that have traversed this node. - current.signal_count += 1 - # If numbering is used, sort and store all numbers associated with the base node. - if use_number and current_base: - current.all_numbers = sorted(current_base.numbers) - return current + def update(self, name, number, use_number, current_base=None): + """ + Updates or creates a hierarchy node based on the current position, name, and number. + If numbering is used, sorts and stores all numbers associated with the base node. + + Parameters: + name (str): The name of the current hierarchy level. + number (int): The number associated with the current hierarchy level. + use_number (bool): Flag indicating whether to use the number in the hierarchy. + current_base (HierarchyNode, optional): The base node for number usage information. + + Returns: + HierarchyNode: The updated or created child node. + """ + # Create the appropriate key for the node. + key = (name, number) if use_number else name + # Use setdefault to either get the existing child node or create a new one. + child = self.children.setdefault(key, HierarchyNode()) + # Add the number to the set of numbers associated with this node. + child.numbers.add(number) + # Increment the count of signals that have traversed this node. + child.signal_count += 1 + # If numbering is used, sort and store all numbers associated with the base node. + if use_number and current_base: + child.all_numbers = sorted(current_base.numbers) + return child def build_hierarchy_tree(signals, base_tree=None): """ @@ -82,7 +81,7 @@ def build_hierarchy_tree(signals, base_tree=None): use_number = current_base.use_number if current_base else False # Update the current node in the hierarchy. - current = update_hierarchy_node(current, name, number, use_number, current_base) + current = current.update(name, number, use_number, current_base) return root From 3df23a27f5d3e3215aadd73144d5f977c1997f08 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 13:56:25 +0100 Subject: [PATCH 313/454] gen/fhdl/namer: Avoid deep level of nesting on build_signal_name_dict_for_group. --- litex/gen/fhdl/namer.py | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 415c0be4e..0df49bc37 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -232,30 +232,37 @@ def build_signal_name_dict_for_group(group_number, signals): dict: A dictionary mapping signals to their hierarchical names. """ + def resolve_conflicts_and_rebuild_tree(): + conflicts = list_conflicting_signals(name_dict) + if conflicts: + set_number_usage(tree, conflicts) + return build_hierarchy_tree(signals, tree) + return tree + + def disambiguate_signals_with_duid(): + inv_name_dict = invert_signal_name_dict(name_dict) + for names, sigs in inv_name_dict.items(): + if len(sigs) > 1: + for idx, sig in enumerate(sorted(sigs, key=lambda s: s.duid)): + name_dict[sig] += f"{idx}" + # Construct initial naming tree and name dictionary. tree = build_hierarchy_tree(signals) determine_name_usage(tree) name_dict = build_signal_name_dict_from_tree(tree, signals) # Address naming conflicts by introducing numbers. - conflicts = list_conflicting_signals(name_dict) - if conflicts: - set_number_usage(tree, conflicts) - # Rebuild tree and name dictionary if there were conflicts. - tree = build_hierarchy_tree(signals, tree) - determine_name_usage(tree) - name_dict = build_signal_name_dict_from_tree(tree, signals) + tree = resolve_conflicts_and_rebuild_tree() + + # Re-determine name usage and rebuild the name dictionary. + determine_name_usage(tree) + name_dict = build_signal_name_dict_from_tree(tree, signals) # Disambiguate remaining conflicts using signal's unique identifier (DUID). - inv_name_dict = invert_signal_name_dict(name_dict) - for names, sigs in inv_name_dict.items(): - if len(sigs) > 1: - for idx, sig in enumerate(sorted(sigs, key=lambda s: s.duid)): - name_dict[sig] += f"{idx}" + disambiguate_signals_with_duid() return name_dict - def build_signal_groups(signals): """Organizes signals into related groups. From 9ce29224a1fb392437ad2476d88956c1a925f20c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 15:36:08 +0100 Subject: [PATCH 314/454] gen/fhdl/namer: Add all_numbers to HierarchyNode to avoid hasattr use. --- litex/gen/fhdl/namer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 0df49bc37..26ba3eb87 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -26,6 +26,7 @@ def __init__(self): self.use_name = False self.use_number = False self.children = {} + self.all_numbers = [] def update(self, name, number, use_number, current_base=None): """ @@ -140,7 +141,7 @@ def build_signal_name_dict_from_tree(tree, signals): # Navigate the tree according to the signal's path. treepos = treepos.children.get((step_name, step_n)) or treepos.children.get(step_name) # Check if the number is part of the name based on the tree node. - use_number = step_n in treepos.all_numbers if hasattr(treepos, 'all_numbers') else False + use_number = step_n in treepos.all_numbers # If the tree node's name is to be used, add it to the elements. if treepos.use_name: From af508fddc51a00658ad8b3b433a30ace71ea8143 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 15:54:19 +0100 Subject: [PATCH 315/454] gen/fhdl/namer: Improve/Simplify SignalNamespace.get_name method. --- litex/gen/fhdl/namer.py | 46 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 26ba3eb87..d063facfc 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -391,18 +391,18 @@ def __init__(self, name_dict, reserved_keywords=set()): self.clock_domains = dict() def get_name(self, sig): - # Get name of a Clock Signal. - # --------------------------- - if isinstance(sig, ClockSignal): - sig = self.clock_domains[sig.cd].clk - - # Get name of a Reset Signal. - # --------------------------- - if isinstance(sig, ResetSignal): - sig = self.clock_domains[sig.cd].rst + # Handle Clock and Reset Signals. + # ------------------------------- + if isinstance(sig, (ClockSignal, ResetSignal)): + # Retrieve the clock domain from the dictionary. + domain = self.clock_domains.get(sig.cd) + if domain is None: + raise ValueError(f"Clock Domain '{sig.cd}' not found.") + # Assign the appropriate signal from the clock domain. + sig = domain.clk if isinstance(sig, ClockSignal) else domain.rst + # If the signal is None, the clock domain is missing a clock or reset. if sig is None: - msg = f"Clock Domain {sig.cd} is reset-less, can't obtain name" - raise ValueError(msg) + raise ValueError(f"Clock Domain '{sig.cd}' is reset-less, can't obtain name.") # Get name of a Regular Signal. # ----------------------------- @@ -411,19 +411,21 @@ def get_name(self, sig): sig_name = sig.name_override # ... else get Name from name_dict. else: - sig_name = self.name_dict[sig] - - # Check/Add numbering suffix when required. - # ----------------------------------------- - try: - n = self.sigs[sig] - except KeyError: - try: - n = self.counts[sig_name] - except KeyError: - n = 0 + sig_name = self.name_dict.get(sig) + # If the signal is not in the name_dict, raise an error. + if sig_name is None: + raise ValueError(f"Signal '{sig}' not found in name dictionary.") + + + # Check/Add numbering when required. + # ---------------------------------- + # Retrieve the current count for the signal name, defaulting to 0. + n = self.sigs.get(sig) + if n is None: + n = self.counts.get(sig_name, 0) self.sigs[sig] = n self.counts[sig_name] = n + 1 + # If the count is greater than 0, append it to the signal name. if n > 0: sig_name += f"_{n}" From ef4235a5d9261c99830df78020846cc748610820 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 16:21:33 +0100 Subject: [PATCH 316/454] gen/fhdl/namer: Use _ for private functions and remove build_namespace. --- litex/gen/fhdl/namer.py | 119 ++++++++++++++++++++++---------------- litex/gen/fhdl/verilog.py | 8 +-- litex/gen/sim/vcd.py | 4 +- 3 files changed, 76 insertions(+), 55 deletions(-) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index d063facfc..678cd65b7 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -8,9 +8,9 @@ from migen.fhdl.structure import * -# Private Classes/Helpers -------------------------------------------------------------------------- +# Hierarchy Node Class ----------------------------------------------------------------------------- -class HierarchyNode: +class _HierarchyNode: """A node in a hierarchy tree used for signal name resolution. Attributes: @@ -34,18 +34,18 @@ def update(self, name, number, use_number, current_base=None): If numbering is used, sorts and stores all numbers associated with the base node. Parameters: - name (str): The name of the current hierarchy level. - number (int): The number associated with the current hierarchy level. - use_number (bool): Flag indicating whether to use the number in the hierarchy. - current_base (HierarchyNode, optional): The base node for number usage information. + name (str): The name of the current hierarchy level. + number (int): The number associated with the current hierarchy level. + use_number (bool): Flag indicating whether to use the number in the hierarchy. + current_base (_HierarchyNode, optional): The base node for number usage information. Returns: - HierarchyNode: The updated or created child node. + _HierarchyNode: The updated or created child node. """ # Create the appropriate key for the node. key = (name, number) if use_number else name # Use setdefault to either get the existing child node or create a new one. - child = self.children.setdefault(key, HierarchyNode()) + child = self.children.setdefault(key, _HierarchyNode()) # Add the number to the set of numbers associated with this node. child.numbers.add(number) # Increment the count of signals that have traversed this node. @@ -55,18 +55,20 @@ def update(self, name, number, use_number, current_base=None): child.all_numbers = sorted(current_base.numbers) return child -def build_hierarchy_tree(signals, base_tree=None): +# Build Hierarchy Tree Function -------------------------------------------------------------------- + +def _build_hierarchy_tree(signals, base_tree=None): """ Constructs a hierarchical tree from signals, where each signal's backtrace contributes to the tree structure. Parameters: - - signals (list): A list of signals to process. - - base_tree (HierarchyNode, optional): A base tree to refine with number usage information. + - signals (list): A list of signals to process. + - base_tree (_HierarchyNode, optional): A base tree to refine with number usage information. Returns: - - HierarchyNode: The root node of the constructed tree. + - _HierarchyNode: The root node of the constructed tree. """ - root = HierarchyNode() + root = _HierarchyNode() # Iterate over each signal to be included in the tree. for signal in signals: @@ -86,7 +88,9 @@ def build_hierarchy_tree(signals, base_tree=None): return root -def determine_name_usage(node, node_name=""): +# Determine Name Usage Function -------------------------------------------------------------------- + +def _determine_name_usage(node, node_name=""): """ Recursively determines if node names should be used to ensure unique signal naming. """ @@ -94,7 +98,7 @@ def determine_name_usage(node, node_name=""): # Recursively collect names from children, identifying if any naming conflicts occur. child_name_sets = { - child_name: determine_name_usage(child_node, child_name) + child_name: _determine_name_usage(child_node, child_name) for child_name, child_node in node.children.items() } @@ -118,7 +122,9 @@ def determine_name_usage(node, node_name=""): return required_names -def build_signal_name_dict_from_tree(tree, signals): +# Build Signal Name Dict From Tree Function -------------------------------------------------------- + +def _build_signal_name_dict_from_tree(tree, signals): """ Constructs a mapping of signals to their names derived from a tree structure. @@ -155,7 +161,9 @@ def build_signal_name_dict_from_tree(tree, signals): # Return the completed name dictionary. return name_dict -def invert_signal_name_dict(name_dict): +# Invert Signal Name Dict Function ----------------------------------------------------------------- + +def _invert_signal_name_dict(name_dict): """ Inverts a signal-to-name dictionary to a name-to-signals dictionary. @@ -175,7 +183,9 @@ def invert_signal_name_dict(name_dict): inverted_dict[name] = signals_with_name return inverted_dict -def list_conflicting_signals(name_dict): +# List Conflicting Signals Function ---------------------------------------------------------------- + +def _list_conflicting_signals(name_dict): """Lists signals that have conflicting names in the provided mapping. Parameters: @@ -185,7 +195,7 @@ def list_conflicting_signals(name_dict): set: A set of signals that have name conflicts. """ # Invert the signal-to-name mapping to a name-to-signals mapping. - inverted_dict = invert_signal_name_dict(name_dict) + inverted_dict = _invert_signal_name_dict(name_dict) # Prepare a set to hold signals with conflicting names. conflicts = set() @@ -200,13 +210,15 @@ def list_conflicting_signals(name_dict): # Return the set of all signals that have name conflicts. return conflicts -def set_number_usage(tree, signals): +# Set Number Usage Function ------------------------------------------------------------------------ + +def _set_number_usage(tree, signals): """ Updates nodes to use number suffixes to resolve naming conflicts when necessary. Parameters: - tree (HierarchyNode): The root node of the naming tree. - signals (iterable): Signals potentially causing naming conflicts. + tree (_HierarchyNode): The root node of the naming tree. + signals (iterable): Signals potentially causing naming conflicts. Returns: None: Tree is modified in place. @@ -222,7 +234,9 @@ def set_number_usage(tree, signals): node.use_number = node.signal_count > len(node.numbers) > 1 # Once use_number is True, it stays True. -def build_signal_name_dict_for_group(group_number, signals): +# Build Signal Name Dict For Group Function -------------------------------------------------------- + +def _build_signal_name_dict_for_group(group_number, signals): """Builds a signal-to-name dictionary for a specific group of signals. Parameters: @@ -234,37 +248,39 @@ def build_signal_name_dict_for_group(group_number, signals): """ def resolve_conflicts_and_rebuild_tree(): - conflicts = list_conflicting_signals(name_dict) + conflicts = _list_conflicting_signals(name_dict) if conflicts: - set_number_usage(tree, conflicts) - return build_hierarchy_tree(signals, tree) + _set_number_usage(tree, conflicts) + return _build_hierarchy_tree(signals, tree) return tree def disambiguate_signals_with_duid(): - inv_name_dict = invert_signal_name_dict(name_dict) + inv_name_dict = _invert_signal_name_dict(name_dict) for names, sigs in inv_name_dict.items(): if len(sigs) > 1: for idx, sig in enumerate(sorted(sigs, key=lambda s: s.duid)): name_dict[sig] += f"{idx}" # Construct initial naming tree and name dictionary. - tree = build_hierarchy_tree(signals) - determine_name_usage(tree) - name_dict = build_signal_name_dict_from_tree(tree, signals) + tree = _build_hierarchy_tree(signals) + _determine_name_usage(tree) + name_dict = _build_signal_name_dict_from_tree(tree, signals) # Address naming conflicts by introducing numbers. tree = resolve_conflicts_and_rebuild_tree() # Re-determine name usage and rebuild the name dictionary. - determine_name_usage(tree) - name_dict = build_signal_name_dict_from_tree(tree, signals) + _determine_name_usage(tree) + name_dict = _build_signal_name_dict_from_tree(tree, signals) # Disambiguate remaining conflicts using signal's unique identifier (DUID). disambiguate_signals_with_duid() return name_dict -def build_signal_groups(signals): +# Build Signal Groups Function --------------------------------------------------------------------- + +def _build_signal_groups(signals): """Organizes signals into related groups. Parameters: @@ -293,7 +309,9 @@ def build_signal_groups(signals): return grouped_signals -def build_hierarchical_name(signal, group_number, group_name_dict_mappings): +# Build Hierarchical Name Function ----------------------------------------------------------------- + +def _build_hierarchical_name(signal, group_number, group_name_dict_mappings): """Builds the hierarchical name for a signal. Parameters: @@ -317,7 +335,9 @@ def build_hierarchical_name(signal, group_number, group_name_dict_mappings): return hierarchical_name -def update_name_dict_with_group(name_dict, group_number, group_name_dict, group_name_dict_mappings): +# Update Name Dict With Group Function ------------------------------------------------------------- + +def _update_name_dict_with_group(name_dict, group_number, group_name_dict, group_name_dict_mappings): """Updates the name dictionary with hierarchical names for a specific group. Parameters: @@ -330,43 +350,44 @@ def update_name_dict_with_group(name_dict, group_number, group_name_dict, group_ None: The name_dict is updated in place. """ for signal, name in group_name_dict.items(): - hierarchical_name = build_hierarchical_name( + hierarchical_name = _build_hierarchical_name( signal, group_number, group_name_dict_mappings ) name_dict[signal] = hierarchical_name +# Build Signal Name Dict Function ------------------------------------------------------------------ -def build_signal_name_dict(signals): +def _build_signal_name_dict(signals): """Builds a complete signal-to-name dictionary using a hierarchical tree. Parameters: - signals (iterable): An iterable of all signals to be named. - tree (HierarchyNode): The root node of the tree used for name resolution. + signals (iterable): An iterable of all signals to be named. + tree (_HierarchyNode): The root node of the tree used for name resolution. Returns: dict: A complete dictionary mapping signals to their hierarchical names. """ # Group the signals based on their relationships. - groups = build_signal_groups(signals) + groups = _build_signal_groups(signals) # Generate a name mapping for each group. group_name_dict_mappings = [ - build_signal_name_dict_for_group(group_number, group_signals) + _build_signal_name_dict_for_group(group_number, group_signals) for group_number, group_signals in enumerate(groups) ] # Create the final signal-to-name mapping. name_dict = {} for group_number, group_name_dict in enumerate(group_name_dict_mappings): - update_name_dict_with_group(name_dict, group_number, group_name_dict, group_name_dict_mappings) + _update_name_dict_with_group(name_dict, group_number, group_name_dict, group_name_dict_mappings) return name_dict -# Public Classes/Helpers --------------------------------------------------------------------------- +# Signal Namespace Class --------------------------------------------------------------------------- -class SignalNamespace: +class _SignalNamespace: """ - A SignalNamespace object manages unique naming for signals within a hardware design. + A _SignalNamespace object manages unique naming for signals within a hardware design. It ensures that each signal has a unique, conflict-free name within the design's namespace. This includes taking into account reserved keywords and handling signals that may share the same name @@ -432,6 +453,8 @@ def get_name(self, sig): # Return Name. return sig_name +# Build Signal Namespace function ------------------------------------------------------------------ + def build_signal_namespace(signals, reserved_keywords=set()): """Constructs a namespace where each signal is given a unique hierarchical name. Parameters: @@ -443,14 +466,12 @@ def build_signal_namespace(signals, reserved_keywords=set()): """ # Create the primary signal-to-name dictionary. - pnd = build_signal_name_dict(signals) + pnd = _build_signal_name_dict(signals) # Initialize the namespace with reserved keywords and the primary mapping. - namespace = SignalNamespace(pnd, reserved_keywords) + namespace = _SignalNamespace(pnd, reserved_keywords) # Handle signals with overridden names, ensuring they are processed in a consistent order. signals_with_name_override = filter(lambda s: s.name_override is not None, signals) return namespace - -build_namespace = build_signal_namespace \ No newline at end of file diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index ce52fa355..7fe572100 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -26,7 +26,7 @@ from migen.fhdl.specials import Instance, Memory from litex.gen import LiteXContext -from litex.gen.fhdl.namer import build_namespace +from litex.gen.fhdl.namer import build_signal_namespace from litex.gen.fhdl.hierarchy import LiteXHierarchyExplorer from litex.build.tools import get_litex_git_revision @@ -611,9 +611,9 @@ def convert(f, ios=set(), name="top", platform=None, if io_name: io.name_override = io_name - # Build NameSpace. - # ---------------- - ns = build_namespace( + # Build Signal Namespace. + # ---------------------- + ns = build_signal_namespace( signals = ( list_signals(f) | list_special_ios(f, ins=True, outs=True, inouts=True) | diff --git a/litex/gen/sim/vcd.py b/litex/gen/sim/vcd.py index 60aa33d49..1c3f27ad8 100644 --- a/litex/gen/sim/vcd.py +++ b/litex/gen/sim/vcd.py @@ -12,7 +12,7 @@ from collections import OrderedDict import shutil -from litex.gen.fhdl.namer import build_namespace +from litex.gen.fhdl.namer import build_signal_namespace def vcd_codes(): codechars = [chr(i) for i in range(33, 127)] @@ -71,7 +71,7 @@ def init(self, signals): # write vcd header header = "" - ns = build_namespace(self.codes.keys()) + ns = build_signal_namespace(self.codes.keys()) for signal, code in self.codes.items(): name = ns.get_name(signal) header += "$var wire {len} {code} {name} $end\n".format(name=name, code=code, len=len(signal)) From 33fd7742c9be837e012a6a416b5e2d0cf36d2b53 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 16:49:54 +0100 Subject: [PATCH 317/454] interconnect/stream/ClockDomainCrossing: Use DUID for clock_domain id to allow deterministic builds. --- litex/soc/interconnect/stream.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/stream.py b/litex/soc/interconnect/stream.py index c3759641e..c7d521221 100644 --- a/litex/soc/interconnect/stream.py +++ b/litex/soc/interconnect/stream.py @@ -244,8 +244,9 @@ def __init__(self, layout, depth=None, buffered=False): # ClockDomainCrossing ------------------------------------------------------------------------------ -class ClockDomainCrossing(LiteXModule): +class ClockDomainCrossing(LiteXModule, DUID): def __init__(self, layout, cd_from="sys", cd_to="sys", depth=None, buffered=False, with_common_rst=False): + DUID.__init__(self) self.sink = Endpoint(layout) self.source = Endpoint(layout) @@ -259,7 +260,7 @@ def __init__(self, layout, cd_from="sys", cd_to="sys", depth=None, buffered=Fals else: if with_common_rst: # Create intermediate Clk Domains and generate a common Rst. - _cd_id = id(self) # FIXME: Improve, used to allow build with anonymous modules. + _cd_id = self.duid # Use duid for a deterministic unique ID. _cd_rst = Signal() _cd_from = ClockDomain(f"from{_cd_id}") _cd_to = ClockDomain(f"to{_cd_id}") From 5b989bcb0e5498d16b13d4397ee284b3d5d1a98f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 17:24:03 +0100 Subject: [PATCH 318/454] gen/fhdl/verilog: Switch Assign/Operator types to IntEnum. --- litex/gen/fhdl/verilog.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index 7fe572100..12d8953f8 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -17,6 +17,7 @@ import datetime import collections +from enum import IntEnum from operator import itemgetter from migen.fhdl.structure import * @@ -181,19 +182,22 @@ def _generate_signal(ns, s): # Print Operator ----------------------------------------------------------------------------------- -(UNARY, BINARY, TERNARY) = (1, 2, 3) +class OperatorType(IntEnum): + UNARY = 1 + BINARY = 2 + TERNARY = 3 def _generate_operator(ns, node): operator = node.op operands = node.operands arity = len(operands) - assert arity in [UNARY, BINARY, TERNARY] + assert arity in [item.value for item in OperatorType] def to_signed(r): return f"$signed({{1'd0, {r}}})" # Unary Operator. - if arity == UNARY: + if arity == OperatorType.UNARY: r1, s1 = _generate_expression(ns, operands[0]) # Negation Operator. if operator == "-": @@ -206,7 +210,7 @@ def to_signed(r): s = s1 # Binary Operator. - if arity == BINARY: + if arity == OperatorType.BINARY: r1, s1 = _generate_expression(ns, operands[0]) r2, s2 = _generate_expression(ns, operands[1]) # Convert all expressions to signed when at least one is signed. @@ -219,7 +223,7 @@ def to_signed(r): s = s1 or s2 # Ternary Operator. - if arity == TERNARY: + if arity == OperatorType.TERNARY: assert operator == "m" r1, s1 = _generate_expression(ns, operands[0]) r2, s2 = _generate_expression(ns, operands[1]) @@ -292,17 +296,21 @@ def _generate_expression(ns, node): # NODES # # ------------------------------------------------------------------------------------------------ # -(_AT_BLOCKING, _AT_NONBLOCKING, _AT_SIGNAL) = range(3) +class AssignType(IntEnum): + BLOCKING = 0 + NON_BLOCKING = 1 + SIGNAL = 2 def _generate_node(ns, at, level, node, target_filter=None): + assert at in [item.value for item in AssignType] if target_filter is not None and target_filter not in list_targets(node): return "" # Assignment. elif isinstance(node, _Assign): - if at == _AT_BLOCKING: + if at == AssignType.BLOCKING: assignment = " = " - elif at == _AT_NONBLOCKING: + elif at == AssignType.NON_BLOCKING: assignment = " <= " elif is_variable(node.l): assignment = " = " @@ -478,11 +486,11 @@ def _generate_combinatorial_logic_sim(f, ns): for n, (t, stmts) in enumerate(target_stmt_map.items()): assert isinstance(t, Signal) if _use_wire(stmts): - r += "assign " + _generate_node(ns, _AT_BLOCKING, 0, stmts[0]) + r += "assign " + _generate_node(ns, AssignType.BLOCKING, 0, stmts[0]) else: r += "always @(*) begin\n" r += _tab + ns.get_name(t) + " <= " + _generate_expression(ns, t.reset)[0] + ";\n" - r += _generate_node(ns, _AT_NONBLOCKING, 1, stmts, t) + r += _generate_node(ns, AssignType.NON_BLOCKING, 1, stmts, t) r += "end\n" r += "\n" return r @@ -494,12 +502,12 @@ def _generate_combinatorial_logic_synth(f, ns): for n, g in enumerate(groups): if _use_wire(g[1]): - r += "assign " + _generate_node(ns, _AT_BLOCKING, 0, g[1][0]) + r += "assign " + _generate_node(ns, AssignType.BLOCKING, 0, g[1][0]) else: r += "always @(*) begin\n" for t in sorted(g[0], key=lambda x: ns.get_name(x)): r += _tab + ns.get_name(t) + " <= " + _generate_expression(ns, t.reset)[0] + ";\n" - r += _generate_node(ns, _AT_NONBLOCKING, 1, g[1]) + r += _generate_node(ns, AssignType.NON_BLOCKING, 1, g[1]) r += "end\n" r += "\n" return r @@ -512,7 +520,7 @@ def _generate_synchronous_logic(f, ns): r = "" for k, v in sorted(f.sync.items(), key=itemgetter(0)): r += "always @(posedge " + ns.get_name(f.clock_domains[k].clk) + ") begin\n" - r += _generate_node(ns, _AT_SIGNAL, 1, v) + r += _generate_node(ns, AssignType.SIGNAL, 1, v) r += "end\n\n" return r From 657252c5732ff82054cb3b396b65d0e753a85d5e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 6 Nov 2023 17:55:54 +0100 Subject: [PATCH 319/454] gen/fhdl/namer: Update copyrights. --- litex/gen/fhdl/namer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 678cd65b7..9b31d03d2 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -2,6 +2,7 @@ # This file is part of LiteX (Adapted from Migen for LiteX usage). # # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq +# This file is Copyright (c) 2023 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause from itertools import combinations From c1e4b3a850ce84c039f09e360ed039a1d47ad936 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 7 Nov 2023 13:21:16 +0100 Subject: [PATCH 320/454] xilinx/clock: Add reset_buf parameter to allow using a buffer to route reset signal. --- litex/build/xilinx/common.py | 7 +++++-- litex/soc/cores/clock/xilinx_common.py | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/litex/build/xilinx/common.py b/litex/build/xilinx/common.py index fb40cd3df..6d7e1e435 100644 --- a/litex/build/xilinx/common.py +++ b/litex/build/xilinx/common.py @@ -71,6 +71,7 @@ def __init__(self, cd, async_reset): if not hasattr(async_reset, "attr"): i, async_reset = async_reset, Signal() self.comb += async_reset.eq(i) + rst_buf = Signal() rst_meta = Signal() self.specials += [ Instance("FDPE", @@ -89,10 +90,12 @@ def __init__(self, cd, async_reset): i_CE = 1, i_C = cd.clk, i_D = rst_meta, - o_Q = cd.rst + o_Q = cd.rst if getattr(cd, "rst_buf", None) is None else rst_buf ) ] - + # Add optional BUFG. + if getattr(cd, "rst_buf", None) is not None: + self.specials += Instance("BUFG", i_I=rst_buf,o_O= cd.rst) class XilinxAsyncResetSynchronizer: @staticmethod diff --git a/litex/soc/cores/clock/xilinx_common.py b/litex/soc/cores/clock/xilinx_common.py index 4de2cb596..341fd3f14 100644 --- a/litex/soc/cores/clock/xilinx_common.py +++ b/litex/soc/cores/clock/xilinx_common.py @@ -44,11 +44,13 @@ def register_clkin(self, clkin, freq): self.clkin_freq = freq register_clkin_log(self.logger, clkin, freq) - def create_clkout(self, cd, freq, phase=0, buf="bufg", margin=1e-2, with_reset=True, ce=None): + def create_clkout(self, cd, freq, phase=0, buf="bufg", margin=1e-2, with_reset=True, reset_buf=None, ce=None): assert self.nclkouts < self.nclkouts_max clkout = Signal() self.clkouts[self.nclkouts] = (clkout, freq, phase, margin) if with_reset: + assert reset_buf in [None, "bufg"] + cd.rst_buf = reset_buf # FIXME: Improve. self.specials += AsyncResetSynchronizer(cd, ~self.locked) if buf is None: self.comb += cd.clk.eq(clkout) From a0cb436467043cb487e8f0e1ddd4e962c3c0ccca Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 7 Nov 2023 20:15:07 +0100 Subject: [PATCH 321/454] build/gowin/common: adding Tristate support --- litex/build/gowin/common.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/litex/build/gowin/common.py b/litex/build/gowin/common.py index 395d8c66a..4510a1dc6 100644 --- a/litex/build/gowin/common.py +++ b/litex/build/gowin/common.py @@ -96,6 +96,25 @@ class GowinDifferentialOutput: def lower(dr): return GowinDifferentialOutputImpl(dr.i, dr.o_p, dr.o_n) +# Gowin Tristate ----------------------------------------------------------------------------------- + +class GowinTristateImpl(Module): + def __init__(self, io, o, oe, i): + nbits, _ = value_bits_sign(io) + for bit in range(nbits): + self.specials += Instance("IOBUF", + io_IO = io[bit] if nbits > 1 else io, + o_O = i[bit] if nbits > 1 else i, + i_I = o[bit] if nbits > 1 else o, + i_OEN = ~oe, + ) + +class GowinTristate: + @staticmethod + def lower(dr): + print(dr) + return GowinTristateImpl(dr.target, dr.o, dr.oe, dr.i) + # Gowin Special Overrides -------------------------------------------------------------------------- gowin_special_overrides = { @@ -104,4 +123,5 @@ def lower(dr): DDROutput: GowinDDROutput, DifferentialInput: GowinDifferentialInput, DifferentialOutput: GowinDifferentialOutput, + Tristate: GowinTristate, } From 93ce42f7819428d6fdc28bfe74a1aed019a17e7e Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 7 Nov 2023 20:20:33 +0100 Subject: [PATCH 322/454] build/gowin/gowin: rework constraints: IOStandard & Misc in one line, merge _p/_n and only write _p --- litex/build/gowin/gowin.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/litex/build/gowin/gowin.py b/litex/build/gowin/gowin.py index a0e693e14..8ee97cecf 100644 --- a/litex/build/gowin/gowin.py +++ b/litex/build/gowin/gowin.py @@ -69,15 +69,41 @@ def build_io_constraints(self): else: flat_sc.append((name, pins[0], other)) + def _search_pin_entry(pin_lst, pin_name): + for name, pin, other in pin_lst: + if pin_name == name: + return (name, pin, other) + return (None, None, None) + for name, pin, other in flat_sc: if pin != "X": + t_name = name.split('[') # avoid index pins + tmp_name = t_name[0] + if tmp_name[-2:] == "_p": + pn = tmp_name[:-2] + "_n" + if len(t_name) > 1: + pn += '[' + t_name[1] + (_, n_pin, _) = _search_pin_entry(flat_sc, pn) + if n_pin is not None: + pin = f"{pin},{n_pin}" + elif tmp_name[-2:] == "_n": + pp = tmp_name[:-2] + "_p" + if len(t_name) > 1: + pp += '[' + t_name[1] + (p_name, _, _) = _search_pin_entry(flat_sc, pp) + if p_name is not None: + continue cst.append(f"IO_LOC \"{name}\" {pin};") + other_cst = [] for c in other: if isinstance(c, IOStandard): - cst.append(f"IO_PORT \"{name}\" IO_TYPE={c.name};") + other_cst.append(f"IO_TYPE={c.name}") elif isinstance(c, Misc): - cst.append(f"IO_PORT \"{name}\" {c.misc};") + other_cst.append(f"{c.misc}") + if len(other_cst): + t = " ".join(other_cst) + cst.append(f"IO_PORT \"{name}\" {t};") if self.named_pc: cst.extend(self.named_pc) From 6598fe9c12c8fa6634a6aa32641d92f7a3110d9c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 8 Nov 2023 11:14:28 +0100 Subject: [PATCH 323/454] cores/cpu: Add KianV CPU (RV32IMA) initial support. litex_sim --cpu-type=kianv: __ _ __ _ __ / / (_) /____ | |/_/ / /__/ / __/ -_)> < /____/_/\__/\__/_/|_| Build your hardware, easily! (c) Copyright 2012-2023 Enjoy-Digital (c) Copyright 2007-2015 M-Labs BIOS built on Nov 8 2023 11:14:03 BIOS CRC passed (6984e675) LiteX git sha1: c1e4b3a8 --=============== SoC ==================-- CPU: KianV-STANDARD @ 1MHz BUS: WISHBONE 32-bit @ 4GiB CSR: 32-bit data ROM: 128.0KiB SRAM: 8.0KiB --============== Boot ==================-- Booting from serial... Press Q or ESC to abort boot completely. sL5DdSMmkekro Timeout No boot medium found --============= Console ================-- litex> ident Ident: LiteX Simulation 2023-11-08 11:14:00 litex> --- CHANGES.md | 1 + litex/soc/cores/cpu/kianv/__init__.py | 1 + litex/soc/cores/cpu/kianv/boot-helper.S | 4 + litex/soc/cores/cpu/kianv/core.py | 135 ++++++++++++++++++++++++ litex/soc/cores/cpu/kianv/crt0.S | 75 +++++++++++++ litex/soc/cores/cpu/kianv/irq.h | 4 + litex/soc/cores/cpu/kianv/system.h | 19 ++++ 7 files changed, 239 insertions(+) create mode 100644 litex/soc/cores/cpu/kianv/__init__.py create mode 100644 litex/soc/cores/cpu/kianv/boot-helper.S create mode 100644 litex/soc/cores/cpu/kianv/core.py create mode 100644 litex/soc/cores/cpu/kianv/crt0.S create mode 100644 litex/soc/cores/cpu/kianv/irq.h create mode 100644 litex/soc/cores/cpu/kianv/system.h diff --git a/CHANGES.md b/CHANGES.md index 0e91a7adb..f5dea39ab 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,6 +23,7 @@ - cores/uart : Added 64-bit addressing support to Stream2Wishbone. - tools : Added 64-bit addressing support to litex_server/client. - cores/cpu : Added 64-bit support to CPUNone. + - cores/cpu : Added KianV (RV32IMA) initial support. [> Changed ---------- diff --git a/litex/soc/cores/cpu/kianv/__init__.py b/litex/soc/cores/cpu/kianv/__init__.py new file mode 100644 index 000000000..d488e5a2c --- /dev/null +++ b/litex/soc/cores/cpu/kianv/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.kianv.core import KianV diff --git a/litex/soc/cores/cpu/kianv/boot-helper.S b/litex/soc/cores/cpu/kianv/boot-helper.S new file mode 100644 index 000000000..336a4d4f3 --- /dev/null +++ b/litex/soc/cores/cpu/kianv/boot-helper.S @@ -0,0 +1,4 @@ + .section .text, "ax", @progbits + .global boot_helper +boot_helper: + jr x13 diff --git a/litex/soc/cores/cpu/kianv/core.py b/litex/soc/cores/cpu/kianv/core.py new file mode 100644 index 000000000..449d41bc4 --- /dev/null +++ b/litex/soc/cores/cpu/kianv/core.py @@ -0,0 +1,135 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from migen import * + +from litex.gen import * + +from litex.soc.interconnect import wishbone +from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 + +# Variants ----------------------------------------------------------------------------------------- + +CPU_VARIANTS = { + "standard": "kianv", +} + +# GCC Flags ---------------------------------------------------------------------------------------- + +GCC_FLAGS = { + # /------------ Base ISA + # | /------- Hardware Multiply + Divide + # | |/----- Atomics + # | ||/---- Compressed ISA + # | |||/--- Single-Precision Floating-Point + # | ||||/-- Double-Precision Floating-Point + # i macfd + "standard": "-march=rv32i2p0_ma -mabi=ilp32", +} + +# KianV ------------------------------------------------------------------------------------------ + +class KianV(CPU): + category = "softcore" + family = "riscv" + name = "kianv" + human_name = "kianv" + variants = CPU_VARIANTS + data_width = 32 + endianness = "little" + gcc_triple = CPU_GCC_TRIPLE_RISCV32 + linker_output_format = "elf32-littleriscv" + nop = "nop" + io_regions = {0x8000_0000: 0x8000_0000} # Origin, Length. + + # GCC Flags. + @property + def gcc_flags(self): + flags = GCC_FLAGS[self.variant] + flags += " -D__kianv__ " + return flags + + def __init__(self, platform, variant="standard"): + self.platform = platform + self.variant = variant + self.human_name = f"KianV-{variant.upper()}" + self.reset = Signal() + self.idbus = idbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.periph_buses = [idbus] # Peripheral buses (Connected to main SoC's bus). + self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). + + # KianV Mem Bus. + # ---------------- + mbus = Record([ + ("valid", 1), + ("ready", 1), + ("wstrb", 4), + ("addr", 32), + ("wdata", 32), + ("rdata", 32), + ]) + + # KianV Instance. + # ----------------- + self.cpu_params = dict( + # Clk / Rst. + i_clk = ClockSignal("sys"), + i_resetn = ~(ResetSignal("sys") | self.reset), + + # Parameters. + p_RESET_ADDR = 0, + p_STACKADDR = 0, + p_RV32E = 0, + + # Control/Status. + o_PC = Open(), + i_access_fault = 0, + i_IRQ3 = 0, + i_IRQ7 = 0, + + # I/D Bus. + o_mem_valid = mbus.valid, + i_mem_ready = mbus.ready, + o_mem_wstrb = mbus.wstrb, + o_mem_addr = mbus.addr, + o_mem_wdata = mbus.wdata, + i_mem_rdata = mbus.rdata, + ) + + # Adapt KianV Mem Bus to Wishbone. + # -------------------------------- + self.comb += [ + idbus.stb.eq(mbus.valid), + idbus.cyc.eq(mbus.valid), + mbus.ready.eq(idbus.ack), + idbus.we.eq(mbus.wstrb != 0), + idbus.adr.eq(mbus.addr), + idbus.sel.eq(mbus.wstrb), + idbus.dat_w.eq(mbus.wdata), + mbus.rdata.eq(idbus.dat_r), + ] + + # Add Verilog sources. + # -------------------- + self.add_sources(platform, variant) + + def set_reset_address(self, reset_address): + self.reset_address = reset_address + self.cpu_params.update(p_RESET_ADDR=Constant(reset_address, 32)) + + @staticmethod + def add_sources(platform, variant): + if not os.path.exists("KianRiscv"): + os.system(f"git clone https://github.com/splinedrive/kianRiscV") + vdir = "kianRiscV/linux_socs/kianv_harris_mcycle_edition/kianv_harris_edition" + platform.add_verilog_include_path(vdir) + platform.add_source_dir(vdir) + + def do_finalize(self): + assert hasattr(self, "reset_address") + self.specials += Instance("kianv_harris_mc_edition", **self.cpu_params) diff --git a/litex/soc/cores/cpu/kianv/crt0.S b/litex/soc/cores/cpu/kianv/crt0.S new file mode 100644 index 000000000..683f6ad78 --- /dev/null +++ b/litex/soc/cores/cpu/kianv/crt0.S @@ -0,0 +1,75 @@ +#define MIE_MEIE 0x800 + + .global _start +_start: + j reset_vector + +reset_vector: + la sp, _fstack + la t0, trap_vector + csrw mtvec, t0 + + // initialize .data + la t0, _fdata + la t1, _edata + la t2, _fdata_rom +1: beq t0, t1, 2f + lw t3, 0(t2) + sw t3, 0(t0) + addi t0, t0, 4 + addi t2, t2, 4 + j 1b +2: + + // initialize .bss + la t0, _fbss + la t1, _ebss +1: beq t0, t1, 3f + sw zero, 0(t0) + addi t0, t0, 4 + j 1b +3: + // enable external interrupts + li t0, MIE_MEIE + csrs mie, t0 + + call main +1: j 1b + +trap_vector: + addi sp, sp, -16*4 + sw ra, 0*4(sp) + sw t0, 1*4(sp) + sw t1, 2*4(sp) + sw t2, 3*4(sp) + sw a0, 4*4(sp) + sw a1, 5*4(sp) + sw a2, 6*4(sp) + sw a3, 7*4(sp) + sw a4, 8*4(sp) + sw a5, 9*4(sp) + sw a6, 10*4(sp) + sw a7, 11*4(sp) + sw t3, 12*4(sp) + sw t4, 13*4(sp) + sw t5, 14*4(sp) + sw t6, 15*4(sp) + call isr + lw ra, 0*4(sp) + lw t0, 1*4(sp) + lw t1, 2*4(sp) + lw t2, 3*4(sp) + lw a0, 4*4(sp) + lw a1, 5*4(sp) + lw a2, 6*4(sp) + lw a3, 7*4(sp) + lw a4, 8*4(sp) + lw a5, 9*4(sp) + lw a6, 10*4(sp) + lw a7, 11*4(sp) + lw t3, 12*4(sp) + lw t4, 13*4(sp) + lw t5, 14*4(sp) + lw t6, 15*4(sp) + addi sp, sp, 16*4 + mret diff --git a/litex/soc/cores/cpu/kianv/irq.h b/litex/soc/cores/cpu/kianv/irq.h new file mode 100644 index 000000000..1aa55bc8e --- /dev/null +++ b/litex/soc/cores/cpu/kianv/irq.h @@ -0,0 +1,4 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/kianv/system.h b/litex/soc/cores/cpu/kianv/system.h new file mode 100644 index 000000000..828c87bc1 --- /dev/null +++ b/litex/soc/cores/cpu/kianv/system.h @@ -0,0 +1,19 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((unused)) static void flush_cpu_icache(void){}; /* No instruction cache */ +__attribute__((unused)) static void flush_cpu_dcache(void){}; /* No instruction cache */ +void flush_l2_cache(void); + +void busy_wait(unsigned int ms); +void busy_wait_us(unsigned int us); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_H */ From 46107137975850b895e8d7cd56040898d1ec060b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 8 Nov 2023 16:57:21 +0100 Subject: [PATCH 324/454] gen/fhdl/verilog: Ensure top is not None to build hierarchy. --- litex/gen/fhdl/verilog.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index 12d8953f8..d8b0dad61 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -90,13 +90,16 @@ def _generate_timescale(time_unit="1ns", time_precision="1ps"): # ------------------------------------------------------------------------------------------------ # def _generate_hierarchy(top): - hierarchy_explorer = LiteXHierarchyExplorer(top=top, depth=None, with_colors=False) - r = "/*\n" - for l in hierarchy_explorer.get_hierarchy().split("\n"): - r += l + "\n" - r = r[:-1] - r += "*/\n" - return r + if top is None: + return "" + else: + hierarchy_explorer = LiteXHierarchyExplorer(top=top, depth=None, with_colors=False) + r = "/*\n" + for l in hierarchy_explorer.get_hierarchy().split("\n"): + r += l + "\n" + r = r[:-1] + r += "*/\n" + return r # ------------------------------------------------------------------------------------------------ # # RESERVED KEYWORDS # From 1ab85631b8bf89a5ccf329e8e935a01ccfff270e Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 9 Nov 2023 07:07:48 +0100 Subject: [PATCH 325/454] tools/litex_server, tools/remote/comm_udp: fix Etherbonexx constructors by passing addr_width/add_size --- litex/tools/litex_server.py | 2 +- litex/tools/remote/comm_udp.py | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/litex/tools/litex_server.py b/litex/tools/litex_server.py index a3685ffcf..9599a164b 100755 --- a/litex/tools/litex_server.py +++ b/litex/tools/litex_server.py @@ -243,7 +243,7 @@ def main(): assert len(udp_ip) == 4 udp_ip[3] = "x" udp_ip = ".".join(udp_ip) - comm = CommUDP(udp_ip, udp_port, debug=args.debug) + comm = CommUDP(udp_ip, udp_port, debug=args.debug, addr_width=int(args.addr_width)) comm.open(probe=False) comm.scan(udp_ip) comm.close() diff --git a/litex/tools/remote/comm_udp.py b/litex/tools/remote/comm_udp.py index e282a6607..d00adb19d 100644 --- a/litex/tools/remote/comm_udp.py +++ b/litex/tools/remote/comm_udp.py @@ -16,13 +16,14 @@ # CommUDP ------------------------------------------------------------------------------------------ class CommUDP(CSRBuilder): - def __init__(self, server="192.168.1.50", port=1234, csr_csv=None, debug=False, timeout=1.0): + def __init__(self, server="192.168.1.50", port=1234, csr_csv=None, debug=False, timeout=1.0, addr_width=32): CSRBuilder.__init__(self, comm=self, csr_csv=csr_csv) self.server = server self.port = port self.debug = debug self.timeout= timeout self.read_counter = 0 + self.addr_width = addr_width def open(self, probe=True): if hasattr(self, "socket"): @@ -41,7 +42,7 @@ def close(self): def probe(self, ip, port, loose=False): - packet = EtherbonePacket() + packet = EtherbonePacket(self.addr_width) packet.pf = 1 packet.encode() packet.bytes += bytes([0x00, 0x00, 0x00, 0x00]) # Add Padding as payload. @@ -66,7 +67,7 @@ def probe(self, ip, port, loose=False): raise Exception(f"Unable to probe Etherbone server at {self.server}.") if datas is not None: - packet = EtherbonePacket(datas) + packet = EtherbonePacket(self.addr_width, datas) packet.decode() assert packet.pr == 1 return 1 @@ -89,12 +90,12 @@ def read(self, addr, length=None, burst="incr"): for r in range(retries): self.read_counter += 1 - record = EtherboneRecord() - record.reads = EtherboneReads(addrs=[addr+4*j for j in range(length_int)]) + record = EtherboneRecord(addr_size=self.addr_width//8) + record.reads = EtherboneReads(addr_size=self.addr_width//8, addrs=[addr+4*j for j in range(length_int)]) record.rcount = len(record.reads) record.reads.base_ret_addr = self.read_counter - packet = EtherbonePacket() + packet = EtherbonePacket(addr_width=self.addr_width) packet.records = [record] packet.encode() @@ -110,7 +111,7 @@ def read(self, addr, length=None, burst="incr"): timed_out = True break - packet = EtherbonePacket(datas) + packet = EtherbonePacket(self.addr_width, datas) packet.decode() record = packet.records.pop() datas = record.writes.get_datas() @@ -135,11 +136,11 @@ def read(self, addr, length=None, burst="incr"): def write(self, addr, datas): datas = datas if isinstance(datas, list) else [datas] length = len(datas) - record = EtherboneRecord() - record.writes = EtherboneWrites(base_addr=addr, datas=iter(datas)) + record = EtherboneRecord(addr_size=self.addr_width//8) + record.writes = EtherboneWrites(addr_size=self.addr_width//8, base_addr=addr, datas=iter(datas)) record.wcount = len(record.writes) - packet = EtherbonePacket() + packet = EtherbonePacket(self.addr_width) packet.records = [record] packet.encode() From 53e458f63a87ef547f0f35a97f9d8906fe5f191e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 09:21:53 +0100 Subject: [PATCH 326/454] integration/soc: Fix addressing order and remove limitations, we are now just limited to Wishbone. --- litex/soc/integration/soc.py | 54 ++++++++++++++++-------------- litex/soc/interconnect/wishbone.py | 10 +++--- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 1a938a56f..f71411afd 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -335,7 +335,7 @@ def data_width_convert(interface, direction): adapted_interface = interface_cls( data_width = self.data_width, address_width = self.address_width, - addressing = self.addressing, + addressing = interface.addressing, ) if direction == "m2s": master, slave = interface, adapted_interface @@ -345,6 +345,32 @@ def data_width_convert(interface, direction): self.submodules += converter return adapted_interface + # Addressing conversion helper. + def addressing_convert(interface, direction): + # Same Addressing, return un-modified interface. + if interface.addressing == self.addressing: + return interface + # Different Addressing: Return adapted interface. + else: + interface_cls = type(interface) + assert interface_cls == wishbone.Interface # FIXME: Remove limitation. + adapted_interface = interface_cls( + data_width = self.data_width, + address_width = self.address_width, + addressing = self.addressing, + ) + address_shift = log2_int(interface.data_width//8) + print(adapted_interface) + print(adapted_interface.addressing) + print(address_shift) + if direction == "m2s": + self.comb += interface.connect(adapted_interface, omit={"adr"}) + self.comb += adapted_interface.adr.eq(interface.adr[address_shift:]) + elif direction == "s2m": + self.comb += adapted_interface.connect(interface, omit={"adr"}) + self.comb += interface.adr.eq(adapted_interface.adr[address_shift:]) + return adapted_interface + # Bus-Standard conversion helper. def bus_standard_convert(interface, direction): main_bus_cls = { @@ -379,35 +405,11 @@ def bus_standard_convert(interface, direction): self.submodules += bridge return adapted_interface - # Addressing conversion helper. - def addressing_convert(interface, direction): - # Same Addressing, return un-modified interface. - if interface.addressing == self.addressing: - return interface - # Different Addressing: Return adapted interface. - else: - assert interface.addressing == "byte" # FIXME: Remove limitation. - assert self.addressing == "word" # FIXME: Remove limitation. - interface_cls = type(interface) - adapted_interface = interface_cls( - data_width = self.data_width, - address_width = self.address_width, - addressing = self.addressing, - ) - address_shift = log2_int(interface.data_width//8) - if direction == "m2s": - self.comb += interface.connect(adapted_interface) - self.comb += adapted_interface.adr.eq(interface.adr[address_shift:]) - elif direction == "s2m": - self.comb += adapted_interface.connect(interface) - self.comb += interface.adr.eq(adapted_interface.adr[address_shift:]) - return adapted_interface - # Interface conversion. adapted_interface = interface adapted_interface = data_width_convert(adapted_interface, direction) - adapted_interface = bus_standard_convert(adapted_interface, direction) adapted_interface = addressing_convert(adapted_interface, direction) + adapted_interface = bus_standard_convert(adapted_interface, direction) if type(interface) != type(adapted_interface) or interface.data_width != adapted_interface.data_width: fmt = "{name} Bus {adapted} from {from_bus} {from_bits}-bit to {to_bus} {to_bits}-bit." diff --git a/litex/soc/interconnect/wishbone.py b/litex/soc/interconnect/wishbone.py index 64c9c5d3d..5f3bc1417 100644 --- a/litex/soc/interconnect/wishbone.py +++ b/litex/soc/interconnect/wishbone.py @@ -50,15 +50,15 @@ def __init__(self, data_width=32, adr_width=30, bursting=False, addressing="word if kwargs.get("address_width", False): # FIXME: Improve or switch Wishbone to byte addressing instead of word addressing. adr_width = kwargs["address_width"] - int(log2(data_width//8)) - self.adr_width = adr_width - self.address_width = adr_width + int(log2(data_width//8)) + self.adr_width = adr_width + (int(log2(data_width//8)) if (addressing == "byte") else 0) + self.address_width = adr_width + (0 if (addressing == "byte") else int(log2(data_width//8))) self.bursting = bursting assert addressing in ["word", "byte"] self.addressing = addressing Record.__init__(self, set_layout_parameters(_layout, - adr_width = adr_width + (int(log2(data_width//8)) if (addressing == "byte") else 0), - data_width = data_width, - sel_width = data_width//8, + adr_width = self.adr_width, + data_width = self.data_width, + sel_width = self.data_width//8, )) self.adr.reset_less = True self.dat_w.reset_less = True From 03a0739d1315d0cd4a772f0e959280c93ea63363 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 10:08:46 +0100 Subject: [PATCH 327/454] integration/soc/add_adapter: Use bus_ prefix for all converter functions for consistency. --- litex/soc/integration/soc.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index f71411afd..a2ac71835 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -319,8 +319,8 @@ def check_region_is_io(self, region): def add_adapter(self, name, interface, direction="m2s"): assert direction in ["m2s", "s2m"] - # Data-Width conversion helper. - def data_width_convert(interface, direction): + # Bus-Data-Width conversion helper. + def bus_data_width_convert(interface, direction): # Same Data-Width, return un-modified interface. if interface.data_width == self.data_width: return interface @@ -345,8 +345,8 @@ def data_width_convert(interface, direction): self.submodules += converter return adapted_interface - # Addressing conversion helper. - def addressing_convert(interface, direction): + # Bus-Addressing conversion helper. + def bus_addressing_convert(interface, direction): # Same Addressing, return un-modified interface. if interface.addressing == self.addressing: return interface @@ -407,9 +407,9 @@ def bus_standard_convert(interface, direction): # Interface conversion. adapted_interface = interface - adapted_interface = data_width_convert(adapted_interface, direction) - adapted_interface = addressing_convert(adapted_interface, direction) - adapted_interface = bus_standard_convert(adapted_interface, direction) + adapted_interface = bus_data_width_convert(adapted_interface, direction) + adapted_interface = bus_addressing_convert(adapted_interface, direction) + adapted_interface = bus_standard_convert(adapted_interface, direction) if type(interface) != type(adapted_interface) or interface.data_width != adapted_interface.data_width: fmt = "{name} Bus {adapted} from {from_bus} {from_bits}-bit to {to_bus} {to_bits}-bit." From 4b9c866d76200fbdaace5d247c4ed7df1cbf6880 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 10:22:22 +0100 Subject: [PATCH 328/454] integration/soc/bus_addresing_convert: Simplify and skip on AXI/AXI-Lite interface since already handled in bridges. --- litex/soc/integration/soc.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index a2ac71835..39e1f984d 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -350,24 +350,22 @@ def bus_addressing_convert(interface, direction): # Same Addressing, return un-modified interface. if interface.addressing == self.addressing: return interface + # AXI/AXI-Lite interface, Bus-Addressing conversion already handled in Bus-Standard conversion. + elif isinstance(interface, (axi.AXIInterface, axi.AXILiteInterface)): + return interface # Different Addressing: Return adapted interface. else: interface_cls = type(interface) - assert interface_cls == wishbone.Interface # FIXME: Remove limitation. adapted_interface = interface_cls( data_width = self.data_width, address_width = self.address_width, addressing = self.addressing, ) address_shift = log2_int(interface.data_width//8) - print(adapted_interface) - print(adapted_interface.addressing) - print(address_shift) + self.comb += adapted_interface.connect(interface, omit={"adr"}) if direction == "m2s": - self.comb += interface.connect(adapted_interface, omit={"adr"}) self.comb += adapted_interface.adr.eq(interface.adr[address_shift:]) - elif direction == "s2m": - self.comb += adapted_interface.connect(interface, omit={"adr"}) + if direction == "s2m": self.comb += interface.adr.eq(adapted_interface.adr[address_shift:]) return adapted_interface From 4ba3ad5409edc18c0d0aaadf4ec0c232c4059f65 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 10:29:43 +0100 Subject: [PATCH 329/454] sim/gtkwave: Update/fix SignalNamespace import (And make it public in fhdl/namer). --- litex/build/sim/gtkwave.py | 6 +++--- litex/gen/fhdl/namer.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/litex/build/sim/gtkwave.py b/litex/build/sim/gtkwave.py index 897657635..83e299c9e 100644 --- a/litex/build/sim/gtkwave.py +++ b/litex/build/sim/gtkwave.py @@ -11,7 +11,7 @@ from migen import * -from litex.gen.fhdl.namer import Namespace +from litex.gen.fhdl.namer import SignalNamespace from litex.soc.interconnect import stream @@ -52,7 +52,7 @@ class GTKWSave: """ def __init__(self, - vns: Namespace, + vns: SignalNamespace, savefile: str, dumpfile: str, filtersdir: str = None, @@ -62,7 +62,7 @@ def __init__(self, `prefix` is prepended to all signal names and defaults to the one used by Litex simulator. """ - self.vns = vns # Namespace output of Builder.build, required to resolve signal names + self.vns = vns # SignalNamespace output of Builder.build, required to resolve signal names self.prefix = prefix self.savefile = savefile self.dumpfile = dumpfile diff --git a/litex/gen/fhdl/namer.py b/litex/gen/fhdl/namer.py index 9b31d03d2..3db8606a2 100644 --- a/litex/gen/fhdl/namer.py +++ b/litex/gen/fhdl/namer.py @@ -386,7 +386,7 @@ def _build_signal_name_dict(signals): # Signal Namespace Class --------------------------------------------------------------------------- -class _SignalNamespace: +class SignalNamespace: """ A _SignalNamespace object manages unique naming for signals within a hardware design. @@ -463,14 +463,14 @@ def build_signal_namespace(signals, reserved_keywords=set()): reserved_keywords (set, optional): A set of keywords that cannot be used as signal names. Returns: - Namespace: An object that contains the mapping of signals to unique names and provides methods to access them. + SignalNamespace: An object that contains the mapping of signals to unique names and provides methods to access them. """ # Create the primary signal-to-name dictionary. pnd = _build_signal_name_dict(signals) # Initialize the namespace with reserved keywords and the primary mapping. - namespace = _SignalNamespace(pnd, reserved_keywords) + namespace = SignalNamespace(pnd, reserved_keywords) # Handle signals with overridden names, ensuring they are processed in a consistent order. signals_with_name_override = filter(lambda s: s.name_override is not None, signals) From 1282708a08fef099e8beffab8a8e7971f3fe7266 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 11:40:16 +0100 Subject: [PATCH 330/454] cpu/naxriscv/core: Cosmetic cleanups. --- litex/soc/cores/cpu/naxriscv/core.py | 119 +++++++++++++++------------ 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 7b00721b0..c9f010ccc 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -105,18 +105,18 @@ def reserved_interrupts(self): @staticmethod def args_fill(parser): cpu_group = parser.add_argument_group(title="CPU options") - cpu_group.add_argument("--scala-file", action="append", help="Specify the scala files used to configure NaxRiscv.") - cpu_group.add_argument("--scala-args", action="append", help="Add arguements for the scala run time. Ex : --scala-args 'rvc=true,mmu=false'") - cpu_group.add_argument("--xlen", default=32, help="Specify the RISC-V data width.") - cpu_group.add_argument("--cpu-count", default=1, help="How many NaxRiscv CPU") - cpu_group.add_argument("--with-coherent-dma", action="store_true", help="Enable coherent DMA accesses") - cpu_group.add_argument("--with-jtag-tap", action="store_true", help="Add a embedded JTAG tap for debugging") - cpu_group.add_argument("--with-jtag-instruction", action="store_true", help="Add a JTAG instruction port which implement tunneling for debugging (TAP not included)") - cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") - cpu_group.add_argument("--no-netlist-cache", action="store_true", help="Always (re-)build the netlist") - cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU") - cpu_group.add_argument("--l2-bytes", default=128*1024, help="NaxRiscv L2 bytes, default 128 KB") - cpu_group.add_argument("--l2-ways", default=8, help="NaxRiscv L2 ways, default 8") + cpu_group.add_argument("--scala-file", action="append", help="Specify the scala files used to configure NaxRiscv.") + cpu_group.add_argument("--scala-args", action="append", help="Add arguements for the scala run time. Ex : --scala-args 'rvc=true,mmu=false'") + cpu_group.add_argument("--xlen", default=32, help="Specify the RISC-V data width.") + cpu_group.add_argument("--cpu-count", default=1, help="How many NaxRiscv CPU.") + cpu_group.add_argument("--with-coherent-dma", action="store_true", help="Enable coherent DMA accesses.") + cpu_group.add_argument("--with-jtag-tap", action="store_true", help="Add a embedded JTAG tap for debugging.") + cpu_group.add_argument("--with-jtag-instruction", action="store_true", help="Add a JTAG instruction port which implement tunneling for debugging (TAP not included).") + cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") + cpu_group.add_argument("--no-netlist-cache", action="store_true", help="Always (re-)build the netlist.") + cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU.") + cpu_group.add_argument("--l2-bytes", default=128*1024, help="NaxRiscv L2 bytes, default 128 KB.") + cpu_group.add_argument("--l2-ways", default=8, help="NaxRiscv L2 ways, default 8.") @staticmethod def args_read(args): @@ -200,47 +200,54 @@ def __init__(self, platform, variant): self.dma_bus = dma_bus = axi.AXIInterface(data_width=64, address_width=32, id_width=4) self.cpu_params.update( - o_dma_bus_awready=dma_bus.aw.ready, - i_dma_bus_awvalid=dma_bus.aw.valid, - i_dma_bus_awid=dma_bus.aw.id, - i_dma_bus_awaddr=dma_bus.aw.addr, - i_dma_bus_awlen=dma_bus.aw.len, - i_dma_bus_awsize=dma_bus.aw.size, - i_dma_bus_awburst=dma_bus.aw.burst, - i_dma_bus_awlock=dma_bus.aw.lock, - i_dma_bus_awcache=dma_bus.aw.cache, - i_dma_bus_awprot=dma_bus.aw.prot, - i_dma_bus_awqos=dma_bus.aw.qos, - - o_dma_bus_wready=dma_bus.w.ready, - i_dma_bus_wvalid=dma_bus.w.valid, - i_dma_bus_wdata=dma_bus.w.data, - i_dma_bus_wstrb=dma_bus.w.strb, - i_dma_bus_wlast=dma_bus.w.last, - - i_dma_bus_bready=dma_bus.b.ready, - o_dma_bus_bvalid=dma_bus.b.valid, - o_dma_bus_bid=dma_bus.b.id, - o_dma_bus_bresp=dma_bus.b.resp, - - o_dma_bus_arready=dma_bus.ar.ready, - i_dma_bus_arvalid=dma_bus.ar.valid, - i_dma_bus_arid=dma_bus.ar.id, - i_dma_bus_araddr=dma_bus.ar.addr, - i_dma_bus_arlen=dma_bus.ar.len, - i_dma_bus_arsize=dma_bus.ar.size, - i_dma_bus_arburst=dma_bus.ar.burst, - i_dma_bus_arlock=dma_bus.ar.lock, - i_dma_bus_arcache=dma_bus.ar.cache, - i_dma_bus_arprot=dma_bus.ar.prot, - i_dma_bus_arqos=dma_bus.ar.qos, - - i_dma_bus_rready=dma_bus.r.ready, - o_dma_bus_rvalid=dma_bus.r.valid, - o_dma_bus_rid=dma_bus.r.id, - o_dma_bus_rdata=dma_bus.r.data, - o_dma_bus_rresp=dma_bus.r.resp, - o_dma_bus_rlast=dma_bus.r.last + # DMA Bus. + # -------- + # AW Channel. + o_dma_bus_awready = dma_bus.aw.ready, + i_dma_bus_awvalid = dma_bus.aw.valid, + i_dma_bus_awid = dma_bus.aw.id, + i_dma_bus_awaddr = dma_bus.aw.addr, + i_dma_bus_awlen = dma_bus.aw.len, + i_dma_bus_awsize = dma_bus.aw.size, + i_dma_bus_awburst = dma_bus.aw.burst, + i_dma_bus_awlock = dma_bus.aw.lock, + i_dma_bus_awcache = dma_bus.aw.cache, + i_dma_bus_awprot = dma_bus.aw.prot, + i_dma_bus_awqos = dma_bus.aw.qos, + + # W Channel. + o_dma_bus_wready = dma_bus.w.ready, + i_dma_bus_wvalid = dma_bus.w.valid, + i_dma_bus_wdata = dma_bus.w.data, + i_dma_bus_wstrb = dma_bus.w.strb, + i_dma_bus_wlast = dma_bus.w.last, + + # B Channel. + i_dma_bus_bready = dma_bus.b.ready, + o_dma_bus_bvalid = dma_bus.b.valid, + o_dma_bus_bid = dma_bus.b.id, + o_dma_bus_bresp = dma_bus.b.resp, + + # AR Channel. + o_dma_bus_arready = dma_bus.ar.ready, + i_dma_bus_arvalid = dma_bus.ar.valid, + i_dma_bus_arid = dma_bus.ar.id, + i_dma_bus_araddr = dma_bus.ar.addr, + i_dma_bus_arlen = dma_bus.ar.len, + i_dma_bus_arsize = dma_bus.ar.size, + i_dma_bus_arburst = dma_bus.ar.burst, + i_dma_bus_arlock = dma_bus.ar.lock, + i_dma_bus_arcache = dma_bus.ar.cache, + i_dma_bus_arprot = dma_bus.ar.prot, + i_dma_bus_arqos = dma_bus.ar.qos, + + # R Channel. + i_dma_bus_rready = dma_bus.r.ready, + o_dma_bus_rvalid = dma_bus.r.valid, + o_dma_bus_rid = dma_bus.r.id, + o_dma_bus_rdata = dma_bus.r.data, + o_dma_bus_rresp = dma_bus.r.resp, + o_dma_bus_rlast = dma_bus.r.last ) def set_reset_address(self, reset_address): @@ -456,6 +463,8 @@ def add_memory_buses(self, address_width, data_width): self.cpu_params.update( # Memory Bus (Master). + # -------------------- + # AW Channel. o_mBus_awvalid = mbus.aw.valid, i_mBus_awready = mbus.aw.ready, o_mBus_awaddr = mbus.aw.addr, @@ -464,15 +473,18 @@ def add_memory_buses(self, address_width, data_width): o_mBus_awsize = mbus.aw.size, o_mBus_awburst = mbus.aw.burst, o_mBus_awallStrb = Open(), + # W Channel. o_mBus_wvalid = mbus.w.valid, i_mBus_wready = mbus.w.ready, o_mBus_wdata = mbus.w.data, o_mBus_wstrb = mbus.w.strb, o_mBus_wlast = mbus.w.last, + # B Channel. i_mBus_bvalid = mbus.b.valid, o_mBus_bready = mbus.b.ready, i_mBus_bid = mbus.b.id, i_mBus_bresp = mbus.b.resp, + # AR Channel. o_mBus_arvalid = mbus.ar.valid, i_mBus_arready = mbus.ar.ready, o_mBus_araddr = mbus.ar.addr, @@ -480,6 +492,7 @@ def add_memory_buses(self, address_width, data_width): o_mBus_arlen = mbus.ar.len, o_mBus_arsize = mbus.ar.size, o_mBus_arburst = mbus.ar.burst, + # R Channel. i_mBus_rvalid = mbus.r.valid, o_mBus_rready = mbus.r.ready, i_mBus_rdata = mbus.r.data, From f9dc8e85645e22a0a7b7656a1ef21f42e1c041ac Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 11:41:41 +0100 Subject: [PATCH 331/454] integration/soc/bus_addressing_converter: Handle missing cases. - m2s: byte to word/word to byte. - s2m: byte to word/word to byte. --- litex/soc/integration/soc.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 39e1f984d..a3c7dcd4a 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -364,9 +364,15 @@ def bus_addressing_convert(interface, direction): address_shift = log2_int(interface.data_width//8) self.comb += adapted_interface.connect(interface, omit={"adr"}) if direction == "m2s": - self.comb += adapted_interface.adr.eq(interface.adr[address_shift:]) + if (interface.addressing == "word") and (self.addressing == "byte"): + self.comb += adapted_interface.adr[address_shift:].eq(interface.adr) + if (interface.addressing == "byte") and (self.addressing == "word"): + self.comb += adapted_interface.adr.eq(interface.adr[address_shift:]) if direction == "s2m": - self.comb += interface.adr.eq(adapted_interface.adr[address_shift:]) + if (interface.addressing == "word") and (self.addressing == "byte"): + self.comb += interface.adr[address_shift:].eq(adapted_interface.adr) + if (interface.addressing == "byte") and (self.addressing == "word"): + self.comb += interface.adr.eq(adapted_interface.adr[address_shift:]) return adapted_interface # Bus-Standard conversion helper. From 55bb9b9c560e8643b778b57df0c262aa83ff847e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 13:06:43 +0100 Subject: [PATCH 332/454] integration/soc/bus_addressing_convert: Fix interface<->adapted_interface connection. --- litex/soc/integration/soc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index a3c7dcd4a..11f8142e9 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -362,13 +362,14 @@ def bus_addressing_convert(interface, direction): addressing = self.addressing, ) address_shift = log2_int(interface.data_width//8) - self.comb += adapted_interface.connect(interface, omit={"adr"}) if direction == "m2s": + self.comb += interface.connect(adapted_interface, omit={"adr"}) if (interface.addressing == "word") and (self.addressing == "byte"): self.comb += adapted_interface.adr[address_shift:].eq(interface.adr) if (interface.addressing == "byte") and (self.addressing == "word"): self.comb += adapted_interface.adr.eq(interface.adr[address_shift:]) if direction == "s2m": + self.comb += adapted_interface.connect(interface, omit={"adr"}) if (interface.addressing == "word") and (self.addressing == "byte"): self.comb += interface.adr[address_shift:].eq(adapted_interface.adr) if (interface.addressing == "byte") and (self.addressing == "word"): From 48a1b2634c8379b90353208cde7d1191839001ae Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 13:45:27 +0100 Subject: [PATCH 333/454] cores/video/VideoHDMIPHY: Fix when multiple drive_pols. --- litex/soc/cores/video.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/video.py b/litex/soc/cores/video.py index b8d22f7d0..257a9b212 100644 --- a/litex/soc/cores/video.py +++ b/litex/soc/cores/video.py @@ -842,7 +842,7 @@ def __init__(self, pads, clock_domain="sys", pn_swap=[]): for color, channel in _dvi_c2d.items(): # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) - self.add_module(name=f"{color}_encoder", module=encoder) + self.add_module(name=f"{color}_encoder_{pol}", module=encoder) self.comb += encoder.d.eq(getattr(sink, color)) self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if channel == 0 else 0) self.comb += encoder.de.eq(sink.de) @@ -855,7 +855,7 @@ def __init__(self, pads, clock_domain="sys", pn_swap=[]): data_o = data_o, clock_domain = clock_domain, ) - self.add_module(name=f"{color}_serializer", module=serializer) + self.add_module(name=f"{color}_serializer_{pol}", module=serializer) # HDMI (Gowin). From 9b4df14ab1c014d8782809e6f33012b54a0f895f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 14:55:46 +0100 Subject: [PATCH 334/454] build/gowin/common/GowinTristate: Remove print. --- litex/build/gowin/common.py | 1 - 1 file changed, 1 deletion(-) diff --git a/litex/build/gowin/common.py b/litex/build/gowin/common.py index 4510a1dc6..c947c155a 100644 --- a/litex/build/gowin/common.py +++ b/litex/build/gowin/common.py @@ -112,7 +112,6 @@ def __init__(self, io, o, oe, i): class GowinTristate: @staticmethod def lower(dr): - print(dr) return GowinTristateImpl(dr.target, dr.o, dr.oe, dr.i) # Gowin Special Overrides -------------------------------------------------------------------------- From c419706856fc31cc8ac6952354040d1f08208681 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 9 Nov 2023 15:24:40 +0100 Subject: [PATCH 335/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index f5dea39ab..a61d726b2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,6 +24,8 @@ - tools : Added 64-bit addressing support to litex_server/client. - cores/cpu : Added 64-bit support to CPUNone. - cores/cpu : Added KianV (RV32IMA) initial support. + - litedram : Added initial GW5DDRPHY (compiles but not yet working). + - build/gowin : Added GowinTristate implementation. [> Changed ---------- From 639c899838bfa8823cb99cc8048b65a68d0ada33 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 10 Nov 2023 10:27:37 +0100 Subject: [PATCH 336/454] CHANGES.md: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index a61d726b2..b4b748dc6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,7 @@ - cores/cpu : Added KianV (RV32IMA) initial support. - litedram : Added initial GW5DDRPHY (compiles but not yet working). - build/gowin : Added GowinTristate implementation. + - litepcie : Simplify/Cleanup Ultrascale(+) integration and allow .xci generation from .tcl. [> Changed ---------- From 5672a9dd2a482f8b4ec6021e1e7f105997f34628 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 10 Nov 2023 10:35:49 +0100 Subject: [PATCH 337/454] CONTRIBUTORS: Update. --- CONTRIBUTORS | 68 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 20f510e48..3fd8380d4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -10,17 +10,23 @@ and we'll fix it! Contributors: Copyright (c) 2021 Acathla-fr +Copyright (c) 2023 Adam Henault +Copyright (c) 2023 AEW2015 Copyright (c) 2011-2015 Alain Péteut +Copyright (c) 2022 Alan Green +Copyright (c) 2023 Alexey Morozov <31707428+alexey-morozov@users.noreply.github.com> Copyright (c) 2019 Ambroz Bizjak Copyright (c) 2021 Andreas Galauner -Copyright (c) 2021-2022 Andrew Dennison -Copyright (c) 2021 Andwer E Wilson +Copyright (c) 2021-2023 Andrew Dennison +Copyright (c) 2021-2022 Andrew E Wilson Copyright (c) 2021 Andy Kitchen -Copyright (c) 2018-2022 Antmicro +Copyright (c) 2018-2023 Antmicro Copyright (c) 2019 Antony Pavlov Copyright (c) 2019 Antti Lukats Copyright (c) 2019-2020 Arnaud Durand +Copyright (c) 2022-2023 Arne Jansen Copyright (c) 2019 atommann +Copyright (c) 2023 awyxx Copyright (c) 2022 Bastian Löher Copyright (c) 2022 Ben Stobbs Copyright (c) 2021 Benjamin Henrion @@ -28,7 +34,7 @@ Copyright (c) 2019-2020 Benjamin Herrenschmidt Copyright (c) 2021 Blake Smith Copyright (c) 2012-2013 Brandon Hamilton Copyright (c) 2022 Brian Swetland -Copyright (c) 2017-2021 bunnie +Copyright (c) 2017-2023 bunnie Copyright (c) 2019 Caleb Jamison Copyright (c) 2021 Camilo Andres Vera Ruiz Copyright (c) 2021-2022 Charles-Henri Mousset @@ -38,6 +44,7 @@ Copyright (c) 2021 Chris Osterwood Copyright (c) 2020-2022 Christian Klarhorst Copyright (c) 2022 curliph Copyright (c) 2019 Daniel Kucera +Copyright (c) 2023 dasdgw Copyright (c) 2020 Dave Marples Copyright (c) 2013 David Carne Copyright (c) 2020-2021 David Jablonski @@ -48,7 +55,8 @@ Copyright (c) 2018-2020 David Shah Copyright (c) 2020 davidcorrigan714 Copyright (c) 2018 Deano Calver Copyright (c) 2021-2022 developandplay <34752929+developandplay@users.noreply.github.com> -Copyright (c) 2018-2022 Dolu1990 +Copyright (c) 2018-2023 Dolu1990 +Copyright (c) 2023 Eli Schwartz Copyright (c) 2022 Eric Matthews Copyright (c) 2021 Evan Lojewski Copyright (c) 2018 Ewen McNeill @@ -57,34 +65,41 @@ Copyright (c) 2019 fb@frank-buss.de Copyright (c) 2020 Feliks Copyright (c) 2017-2018 Felix Held Copyright (c) 2020 Filipe Laíns -Copyright (c) 2012-2022 Florent Kermarrec +Copyright (c) 2012-2023 Florent Kermarrec Copyright (c) 2019 Francis Lam Copyright (c) 2020-2022 Franck Jullien -Copyright (c) 2019-2022 Gabriel L. Somlo +Copyright (c) 2019-2023 Gabriel L. Somlo Copyright (c) 2021 Gary Wong -Copyright (c) 2018-2022 gatecat +Copyright (c) 2018-2023 gatecat Copyright (c) 2020-2021 Geert Uytterhoeven Copyright (c) 2021 George Hilliard Copyright (c) 2019 Giammarco Zacheo -Copyright (c) 2021-2022 Google +Copyright (c) 2023 Giulio Girardi +Copyright (c) 2021 Google Copyright (c) 2017 Greg Darke Copyright (c) 2020-2022 Greg Davill Copyright (c) 2021 Guillaume REMBERT Copyright (c) 2014-2015 Guy Hutchison -Copyright (c) 2020-2022 Gwenhael Goavec-Merou -Copyright (c) 2021 Hans Baier -Copyright (c) 2022 Icenowy Zheng +Copyright (c) 2020-2023 Gwenhael Goavec-Merou +Copyright (c) 2021-2023 Hans Baier +Copyright (c) 2022-2023 Icenowy Zheng Copyright (c) 2019-2022 Ilia Sergachev Copyright (c) 2020 Ilya Epifanov Copyright (c) 2021 Jakub Piecuch Copyright (c) 2021 Jan Luebbe Copyright (c) 2014 Jannis Harder Copyright (c) 2018 Jean-François Nguyen +Copyright (c) 2023 Jeremy Herbert Copyright (c) 2022 Jevin Sweval +Copyright (c) 2023 Jiajie Chen Copyright (c) 2015 Joe Britton Copyright (c) 2017 Joel Addison -Copyright (c) 2020-2022 Joel Stanley +Copyright (c) 2020-2023 Joel Stanley +Copyright (c) 2023 Johan Carlsson Copyright (c) 2022 Johannes Rudolph +Copyright (c) 2023 Jonathan Bisson +Copyright (c) 2023 Joris Lee +Copyright (c) 2023 Josuah Demangeon Copyright (c) 2020 Jędrzej Boczar Copyright (c) 2019 Kees Jongenburger Copyright (c) 2013 Kenneth Ryerson @@ -94,20 +109,26 @@ Copyright (c) 2021 Konstantin Copyright (c) 2019 Kurt Kiefer Copyright (c) 2019 Larry Doolittle Copyright (c) 2012-2013 Lars-Peter Clausen +Copyright (c) 2023 Lasse Dalegaard Copyright (c) 2020-2022 Leon Schuermann -Copyright (c) 2022 Marcus Comstedt +Copyright (c) 2023 Lukas F. Hartmann +Copyright (c) 2022-2023 Marcus Comstedt Copyright (c) 2021 Marek Czerski Copyright (c) 2021 Marek Materzok Copyright (c) 2019 Martin Cornil Copyright (c) 2022 Massimiliano Giacometti Copyright (c) 2021 Matt Johnston Copyright (c) 2017 Matt Kelly +Copyright (c) 2023 Matteo Marzaro Copyright (c) 2019-2022 Michael Betz Copyright (c) 2012 Michael Walle Copyright (c) 2022 Mikolaj Sowinski Copyright (c) 2021-2022 Mikołaj Sowiński Copyright (c) 2019-2021 Miodrag Milanovic +Copyright (c) 2022 mkuhn99 +Copyright (c) 2022 mohamedElbouazzati Copyright (c) 2019 msloniewski +Copyright (c) 2023 Nate Slager Copyright (c) 2021 Nathaniel R. Lewis Copyright (c) 2021 Navaneeth Copyright (c) 2021 Navaneeth Bhardwaj @@ -127,10 +148,14 @@ Copyright (c) 2020 Piense Copyright (c) 2017 Pierre-Olivier Vauboin Copyright (c) 2020 Piotr Esden-Tempski Copyright (c) 2015 psmears +Copyright (c) 2023 Radek Pesina Copyright (c) 2020 Rangel Ivanov Copyright (c) 2021-2022 RapidSilicon Copyright (c) 2020-2021 Raptor Engineering Development Team +Copyright (c) 2023 Rasmus Pedersen Copyright (c) 2021 Ray Molenkamp +Copyright (c) 2022-2023 Richard Tucker +Copyright (c) 2023 riktw Copyright (c) 2020 rob-ng15 <58272847+rob-ng15@users.noreply.github.com> Copyright (c) 2013-2016 Robert Jordens Copyright (c) 2013 Robert Jördens @@ -138,11 +163,12 @@ Copyright (c) 2021 Robert Wilbrandt Copyright (c) 2015 Rohit Kumar Singh Copyright (c) 2021 Romain Dolbeau Copyright (c) 2022 Rouven Broszeit +Copyright (c) 2023 rowanG077 Copyright (c) 2020 rprinz08 Copyright (c) 2015 Ryan Verner -Copyright (c) 2019-2020 Sadullah Canakci +Copyright (c) 2019-2021 Sadullah Canakci Copyright (c) 2020 Samuel Lindemer -Copyright (c) 2018-2020 Sean Cross +Copyright (c) 2018-2022 Sean Cross Copyright (c) 2011-2016 Sebastien Bourdeauducq Copyright (c) 2021 Sergiu Mosanu Copyright (c) 2017-2018 Sergiusz Bazanski @@ -153,19 +179,21 @@ Copyright (c) 2021 Simon Thornington Copyright (c) 2018-2022 Stafford Horne Copyright (c) 2020 Stephane Gourichon Copyright (c) 2022 stnolting +Copyright (c) 2022-2023 stone3311 Copyright (c) 2020 Stéphane Gourichon Copyright (c) 2022 Sylvain Lefebvre Copyright (c) 2021-2022 Sylvain Munaut -Copyright (c) 2022 Thomas Watson +Copyright (c) 2022-2023 Thomas Watson Copyright (c) 2017-2021 Tim 'mithro' Ansell +Copyright (c) 2023 Tim Paine <3105306+timkpaine@users.noreply.github.com> Copyright (c) 2019 Tom Keddie Copyright (c) 2021-2022 tongchen126 Copyright (c) 2020 Vadim Kaushan Copyright (c) 2021-2022 Vadzim Dambrouski Copyright (c) 2019 Vamsi K Vytla -Copyright (c) 2020-2021 Vamsi Vytla -Copyright (c) 2020-2021 Vegard Storheil Eriksen -Copyright (c) 2022 Victor Suarez Rovere +Copyright (c) 2020-2022 Vamsi Vytla +Copyright (c) 2020-2023 Vegard Storheil Eriksen +Copyright (c) 2022-2023 Victor Suarez Rovere Copyright (c) 2019 vytautasb Copyright (c) 2013 Werner Almesberger Copyright (c) 2015-2021 whitequark From 52adf240f9b18088e4d3648773e60e197f11d8e9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 10 Nov 2023 13:17:00 +0100 Subject: [PATCH 338/454] remote/etherbone/EtherbonePacket: Set default addr_width of 32 (To avoid breaking old code using EtherbonePacket()). --- litex/tools/remote/etherbone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/tools/remote/etherbone.py b/litex/tools/remote/etherbone.py index 59d679efb..3aeac5eb1 100644 --- a/litex/tools/remote/etherbone.py +++ b/litex/tools/remote/etherbone.py @@ -317,7 +317,7 @@ def __repr__(self, n=0): # Etherbone Packet --------------------------------------------------------------------------------- class EtherbonePacket(Packet): - def __init__(self, addr_width, init=[]): + def __init__(self, addr_width=32, init=[]): assert addr_width in [8, 16, 32, 64] Packet.__init__(self, init) From 9f88137ab66322dcb5287b438183507f65fbf733 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 10 Nov 2023 16:13:32 +0100 Subject: [PATCH 339/454] remote/etherbone: Set default addr_size of 32 (To avoid breaking old code). --- litex/tools/remote/etherbone.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/tools/remote/etherbone.py b/litex/tools/remote/etherbone.py index 3aeac5eb1..760cda532 100644 --- a/litex/tools/remote/etherbone.py +++ b/litex/tools/remote/etherbone.py @@ -90,7 +90,7 @@ def __repr__(self): # Etherbone Writes --------------------------------------------------------------------------------- class EtherboneWrites(Packet): - def __init__(self, addr_size, init=[], base_addr=0, datas=[]): + def __init__(self, addr_size=4, init=[], base_addr=0, datas=[]): if isinstance(datas, list) and len(datas) > 255: raise ValueError(f"Burst size of {len(datas)} exceeds maximum of 255 allowed by Etherbone.") assert addr_size in [1, 2, 4, 8] @@ -152,7 +152,7 @@ def __repr__(self): # Etherbone Reads ---------------------------------------------------------------------------------- class EtherboneReads(Packet): - def __init__(self, addr_size, init=[], base_ret_addr=0, addrs=[]): + def __init__(self, addr_size=4, init=[], base_ret_addr=0, addrs=[]): if isinstance(addrs, list) and len(addrs) > 255: raise ValueError(f"Burst size of {len(addrs)} exceeds maximum of 255 allowed by Etherbone.") assert addr_size in [1, 2, 4, 8] @@ -221,7 +221,7 @@ def __repr__(self): # Etherbone Record --------------------------------------------------------------------------------- class EtherboneRecord(Packet): - def __init__(self, addr_size, init=[]): + def __init__(self, addr_size=4, init=[]): assert addr_size in [1, 2, 4, 8] Packet.__init__(self, init) From 57782309a269aab5972f7d33599e055ef447eac0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 10 Nov 2023 18:59:28 +0100 Subject: [PATCH 340/454] integration/soc/add_etherbone: Exclude MAC from CSRs when in hybrid board since added externally. --- litex/soc/integration/soc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 11f8142e9..fee8de48c 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1804,6 +1804,8 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, interface = interface, endianness = endianness, ) + if interface == "hybrid": + ethcore.autocsr_exclude = {"mac"} # Exclude MAC here since added externally. if not with_sys_datapath: # Use PHY's eth_tx/eth_rx clock domains. ethcore = ClockDomainsRenamer({ From 77ca872b3bfed5853378c77aea99c61c37a949c6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 10 Nov 2023 19:13:35 +0100 Subject: [PATCH 341/454] tools/litex_sim: Update Etherbone/Ethernet hybrid mode integration. --- litex/tools/litex_sim.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index fabc0468d..81699f32c 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -235,27 +235,25 @@ def __init__(self, # Ethernet and Etherbone ------------------------------------------------------------------- if with_ethernet and with_etherbone: - etherbone_ip_address = convert_ip(etherbone_ip_address) - # Ethernet MAC - self.ethmac = LiteEthMAC(phy=self.ethphy, dw=8, - interface = "hybrid", - endianness = self.cpu.endianness, - hw_mac = etherbone_mac_address) + # Etherbone. + self.add_etherbone( + phy = self.ethphy, + ip_address = etherbone_ip_address, + mac_address = etherbone_mac_address, + data_width = 8, + interface = "hybrid", + endianness = self.cpu.endianness + ) - # SoftCPU - ethmac_region_size = (self.ethmac.rx_slots.constant + self.ethmac.tx_slots.constant)*self.ethmac.slot_size.constant + # Software Interface. + self.ethmac = ethmac = self.get_module("ethcore_etherbone").mac + ethmac_region_size = (ethmac.rx_slots.constant + ethmac.tx_slots.constant)*ethmac.slot_size.constant ethmac_region = SoCRegion(origin=self.mem_map.get("ethmac", None), size=ethmac_region_size, cached=False) - self.bus.add_slave(name="ethmac", slave=self.ethmac.bus, region=ethmac_region) + self.bus.add_slave(name="ethmac", slave=ethmac.bus, region=ethmac_region) + + # Add IRQs (if enabled). if self.irq.enabled: self.irq.add("ethmac", use_loc_if_exists=True) - # HW ethernet - self.arp = LiteEthARP(self.ethmac, etherbone_mac_address, etherbone_ip_address, sys_clk_freq, dw=8) - self.ip = LiteEthIP(self.ethmac, etherbone_mac_address, etherbone_ip_address, self.arp.table, dw=8) - self.icmp = LiteEthICMP(self.ip, etherbone_ip_address, dw=8) - self.udp = LiteEthUDP(self.ip, etherbone_ip_address, dw=8) - # Etherbone - self.etherbone = LiteEthEtherbone(self.udp, 1234, mode="master") - self.bus.add_master(name="etherbone", master=self.etherbone.wishbone.bus) # Ethernet --------------------------------------------------------------------------------- elif with_ethernet: @@ -264,11 +262,13 @@ def __init__(self, phy = self.ethphy, dw = 64 if ethernet_phy_model == "xgmii" else 32, interface = "wishbone", - endianness = self.cpu.endianness) - # Compute Regions size and add it to the SoC. + endianness = self.cpu.endianness + ) ethmac_region_size = (ethmac.rx_slots.constant + ethmac.tx_slots.constant)*ethmac.slot_size.constant ethmac_region = SoCRegion(origin=self.mem_map.get("ethmac", None), size=ethmac_region_size, cached=False) self.bus.add_slave(name="ethmac", slave=ethmac.bus, region=ethmac_region) + + # Add IRQs (if enabled). if self.irq.enabled: self.irq.add("ethmac", use_loc_if_exists=True) From fb5512f6d57c11c89f95ad156968a25db83ccc09 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 13 Nov 2023 11:03:45 +1100 Subject: [PATCH 342/454] soc/integration/soc: simplify hybrid etherbone --- litex/soc/integration/soc.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index fee8de48c..67a950a42 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1781,8 +1781,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, buffer_depth = 16, with_ip_broadcast = True, with_timing_constraints = True, - interface = "crossbar", - endianness = "big"): + ethernet = False): # Imports from liteeth.core import LiteEthUDPIPCore from liteeth.frontend.etherbone import LiteEthEtherbone @@ -1801,10 +1800,10 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, dw = data_width, with_ip_broadcast = with_ip_broadcast, with_sys_datapath = with_sys_datapath, - interface = interface, - endianness = endianness, + interface = "hybrid" if ethernet else "crossbar", + endianness = self.cpu.endianness if ethernet else "big", ) - if interface == "hybrid": + if ethernet: ethcore.autocsr_exclude = {"mac"} # Exclude MAC here since added externally. if not with_sys_datapath: # Use PHY's eth_tx/eth_rx clock domains. @@ -1840,6 +1839,18 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, else: self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk) + if ethernet: + # Software Interface. + self.ethmac = ethmac = ethcore.mac + ethmac_region_size = (ethmac.rx_slots.constant + ethmac.tx_slots.constant)*ethmac.slot_size.constant + ethmac_region = SoCRegion(origin=self.mem_map.get("ethmac", None), size=ethmac_region_size, cached=False) + self.bus.add_slave(name="ethmac", slave=ethmac.bus, region=ethmac_region) + # Add IRQs (if enabled). + if self.irq.enabled: + self.irq.add("ethmac", use_loc_if_exists=True) + + self.add_constant("ETH_PHY_NO_RESET") # Disable reset from BIOS to avoid disabling Hardware Interface. + # Add SPI Flash -------------------------------------------------------------------------------- def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, phy=None, rate="1:1", software_debug=False, **kwargs): # Imports. From 885d5b9cb139a842a45a7341f59f7e3bae3237c7 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 13 Nov 2023 11:13:19 +1100 Subject: [PATCH 343/454] tools/litex_sim: update hybrid etherbone integration --- litex/tools/litex_sim.py | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 81699f32c..c51595bca 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -233,29 +233,16 @@ def __init__(self, else: raise ValueError("Unknown Ethernet PHY model:", ethernet_phy_model) - # Ethernet and Etherbone ------------------------------------------------------------------- - if with_ethernet and with_etherbone: - # Etherbone. + # Etherbone with optional Ethernet --------------------------------------------------------- + if with_etherbone: self.add_etherbone( phy = self.ethphy, ip_address = etherbone_ip_address, mac_address = etherbone_mac_address, data_width = 8, - interface = "hybrid", - endianness = self.cpu.endianness + ethernet = with_ethernet, ) - - # Software Interface. - self.ethmac = ethmac = self.get_module("ethcore_etherbone").mac - ethmac_region_size = (ethmac.rx_slots.constant + ethmac.tx_slots.constant)*ethmac.slot_size.constant - ethmac_region = SoCRegion(origin=self.mem_map.get("ethmac", None), size=ethmac_region_size, cached=False) - self.bus.add_slave(name="ethmac", slave=ethmac.bus, region=ethmac_region) - - # Add IRQs (if enabled). - if self.irq.enabled: - self.irq.add("ethmac", use_loc_if_exists=True) - - # Ethernet --------------------------------------------------------------------------------- + # Ethernet only ---------------------------------------------------------------------------- elif with_ethernet: # Ethernet MAC self.ethmac = ethmac = LiteEthMAC( @@ -272,14 +259,6 @@ def __init__(self, if self.irq.enabled: self.irq.add("ethmac", use_loc_if_exists=True) - # Etherbone -------------------------------------------------------------------------------- - elif with_etherbone: - self.add_etherbone( - phy = self.ethphy, - ip_address = etherbone_ip_address, - mac_address = etherbone_mac_address - ) - # I2C -------------------------------------------------------------------------------------- if with_i2c: pads = platform.request("i2c", 0) From 737ced8fa6ab0cfd0e139e0fd9d3a09cb404f4ab Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 13 Nov 2023 12:07:35 +1100 Subject: [PATCH 344/454] soc/software: add irq_attach() / irq_detach() cleaner mechanism for other software to use interrupts --- litex/soc/integration/soc.py | 1 + litex/soc/software/include/irq.h | 15 +++++++++++ litex/soc/software/libbase/isr.c | 45 ++++++++++++++++++++++++------- litex/soc/software/libbase/uart.c | 2 ++ 4 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 litex/soc/software/include/irq.h diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index fee8de48c..d12c27c23 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1320,6 +1320,7 @@ def finalize(self): # SoC IRQ Interconnect --------------------------------------------------------------------- if hasattr(self, "cpu") and hasattr(self.cpu, "interrupt"): + self.add_constant("NR_IRQ", max(self.irq.locs.values()) + 1) for name, loc in sorted(self.irq.locs.items()): if name in self.cpu.interrupts.keys(): continue diff --git a/litex/soc/software/include/irq.h b/litex/soc/software/include/irq.h new file mode 100644 index 000000000..fa7a1411b --- /dev/null +++ b/litex/soc/software/include/irq.h @@ -0,0 +1,15 @@ +#pragma once +#include_next + +typedef void (*isr_t)(void); + +#ifdef __cplusplus +extern "C" { +#endif + +extern int irq_attach(unsigned int irq, isr_t isr) __attribute__((weak)); +extern int irq_detach(unsigned int irq) __attribute__((weak)); + +#ifdef __cplusplus +} +#endif diff --git a/litex/soc/software/libbase/isr.c b/litex/soc/software/libbase/isr.c index ac7a7920c..6c052b2d7 100644 --- a/litex/soc/software/libbase/isr.c +++ b/litex/soc/software/libbase/isr.c @@ -191,18 +191,45 @@ void isr(void) } #else -void isr(void) +struct irq_table { - __attribute__((unused)) unsigned int irqs; + isr_t isr; +} irq_table[NR_IRQ]; - irqs = irq_pending() & irq_getmask(); +int irq_attach(unsigned int irq, isr_t isr) +{ + if (irq >= NR_IRQ) { + printf("Inv irq %d\n", irq); + return -1; + } -#ifdef CSR_UART_BASE -#ifndef UART_POLLING - if(irqs & (1 << UART_INTERRUPT)) - uart_isr(); -#endif -#endif + unsigned int ie = irq_getie(); + irq_setie(0); + irq_table[irq].isr = isr; + irq_setie(ie); + return irq; +} + +int irq_detach(unsigned int irq) +{ + return irq_attach(irq, NULL); +} + +void isr(void) +{ + unsigned int irqs = irq_pending() & irq_getmask(); + + while (irqs) + { + const unsigned int irq = __builtin_ctz(irqs); + if (irq < NR_IRQ && irq_table[irq].isr) + irq_table[irq].isr(); + else { + irq_setmask(irq_getmask() & ~(1< Date: Mon, 13 Nov 2023 06:34:59 +0100 Subject: [PATCH 345/454] build/gowin/common: disable Tristate (uncorrect code with tangNano9k hypperram #1833) --- litex/build/gowin/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/gowin/common.py b/litex/build/gowin/common.py index c947c155a..fd554e946 100644 --- a/litex/build/gowin/common.py +++ b/litex/build/gowin/common.py @@ -122,5 +122,5 @@ def lower(dr): DDROutput: GowinDDROutput, DifferentialInput: GowinDifferentialInput, DifferentialOutput: GowinDifferentialOutput, - Tristate: GowinTristate, + #Tristate: GowinTristate, # FIXME: issue with tangNano9k hyperram } From d7253ffd0e461c9e4dae684de025bab1627e0360 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 13 Nov 2023 08:57:22 +0100 Subject: [PATCH 346/454] integration/soc/add_etherbone: Rename ethernet parameter to with_ethmac and minor cosmetic cleanups. --- litex/soc/integration/soc.py | 13 +++++++------ litex/tools/litex_sim.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 5dd9a94ff..613c81402 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1782,7 +1782,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, buffer_depth = 16, with_ip_broadcast = True, with_timing_constraints = True, - ethernet = False): + with_ethmac = False): # Imports from liteeth.core import LiteEthUDPIPCore from liteeth.frontend.etherbone import LiteEthEtherbone @@ -1801,11 +1801,9 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, dw = data_width, with_ip_broadcast = with_ip_broadcast, with_sys_datapath = with_sys_datapath, - interface = "hybrid" if ethernet else "crossbar", - endianness = self.cpu.endianness if ethernet else "big", + interface = {True : "hybrid", False: "crossbar"}[with_ethmac], + endianness = {True : self.cpu.endianness, False: "big"}[with_ethmac], ) - if ethernet: - ethcore.autocsr_exclude = {"mac"} # Exclude MAC here since added externally. if not with_sys_datapath: # Use PHY's eth_tx/eth_rx clock domains. ethcore = ClockDomainsRenamer({ @@ -1840,7 +1838,10 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, else: self.platform.add_false_path_constraints(self.crg.cd_sys.clk, eth_rx_clk) - if ethernet: + # Ethernet MAC (CPU). + if with_ethmac: + self.check_if_exists("ethmac") + ethcore.autocsr_exclude = {"mac"} # Software Interface. self.ethmac = ethmac = ethcore.mac ethmac_region_size = (ethmac.rx_slots.constant + ethmac.tx_slots.constant)*ethmac.slot_size.constant diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index c51595bca..63dc738b7 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -240,7 +240,7 @@ def __init__(self, ip_address = etherbone_ip_address, mac_address = etherbone_mac_address, data_width = 8, - ethernet = with_ethernet, + with_ethmac = with_ethernet, ) # Ethernet only ---------------------------------------------------------------------------- elif with_ethernet: From edc6871aceefcdeef16a76e7d70afb52f7229115 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 13 Nov 2023 09:14:57 +0100 Subject: [PATCH 347/454] soc/software: Rename NR_IRQ to CONFIG_CPU_INTERRUPTS. --- litex/soc/integration/soc.py | 2 +- litex/soc/software/libbase/isr.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 613c81402..96d7f2abb 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1320,7 +1320,7 @@ def finalize(self): # SoC IRQ Interconnect --------------------------------------------------------------------- if hasattr(self, "cpu") and hasattr(self.cpu, "interrupt"): - self.add_constant("NR_IRQ", max(self.irq.locs.values()) + 1) + self.add_config("CPU_INTERRUPTS", max(self.irq.locs.values()) + 1) for name, loc in sorted(self.irq.locs.items()): if name in self.cpu.interrupts.keys(): continue diff --git a/litex/soc/software/libbase/isr.c b/litex/soc/software/libbase/isr.c index 6c052b2d7..268605d72 100644 --- a/litex/soc/software/libbase/isr.c +++ b/litex/soc/software/libbase/isr.c @@ -194,11 +194,11 @@ void isr(void) struct irq_table { isr_t isr; -} irq_table[NR_IRQ]; +} irq_table[CONFIG_CPU_INTERRUPTS]; int irq_attach(unsigned int irq, isr_t isr) { - if (irq >= NR_IRQ) { + if (irq >= CONFIG_CPU_INTERRUPTS) { printf("Inv irq %d\n", irq); return -1; } @@ -222,7 +222,7 @@ void isr(void) while (irqs) { const unsigned int irq = __builtin_ctz(irqs); - if (irq < NR_IRQ && irq_table[irq].isr) + if ((irq < CONFIG_CPU_INTERRUPTS) && irq_table[irq].isr) irq_table[irq].isr(); else { irq_setmask(irq_getmask() & ~(1< Date: Tue, 14 Nov 2023 10:45:16 +0100 Subject: [PATCH 348/454] build/efinix/ifacewriter: generate_lvds: adding LVDS serdes support (Titanium only) --- litex/build/efinix/ifacewriter.py | 87 ++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 26 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 1326c96c3..2e94493b9 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -379,16 +379,30 @@ def generate_lvds(self, block, verbose=True): location = block["location"] size = block["size"] sig = block["sig"] + serdes = block.get("serdes", 1 if size > 1 else 0) + rst_pin = block.get("rst", "") + delay = block.get("delay", 0) cmd = [] + fast_clk = "" + if size > 2: + fast_clk = block.get("fast_clk", "") + slow_clk = block.get("slow_clk", "") + half_rate= block.get("half_rate", "0") if mode == "OUTPUT": block_type = "LVDS_TX" tx_mode = block["tx_mode"] + oe_pin = block.get("oe", "") + if isinstance(oe_pin, Signal): + oe_pin = oe_pin.name + if isinstance(rst_pin, Signal): + rst_pin = rst_pin.name + cmd.append('design.create_block("{}", block_type="{}", tx_mode="{}")'.format(name, block_type, tx_mode)) if self.platform.family == "Titanium": - cmd.append('design.set_property("{}", "TX_DELAY", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_DELAY", "{}", "{}")'.format(name, delay, block_type)) cmd.append('design.set_property("{}", "TX_DIFF_TYPE", "LVDS", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_HALF_RATE", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_HALF_RATE", "{}", "{}")'.format(name, half_rate, block_type)) cmd.append('design.set_property("{}", "TX_PRE_EMP", "MEDIUM_LOW", "{}")'.format(name, block_type)) cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) cmd.append('design.set_property("{}", "TX_VOD", "TYPICAL", "{}")'.format(name, block_type)) @@ -396,52 +410,73 @@ def generate_lvds(self, block, verbose=True): cmd.append('design.set_property("{}","TX_OUTPUT_LOAD","3","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","TX_REDUCED_SWING","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","TX_SLOWCLK_DIV","1","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","TX_EN_SER","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_EN_SER", "0", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_FASTCLK_PIN", "", "{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}","TX_EN_SER","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_EN_SER", "{}", "{}")'.format(name, serdes, block_type)) + cmd.append('design.set_property("{}", "TX_FASTCLK_PIN", "{}", "{}")'.format(name, fast_clk, block_type)) cmd.append('design.set_property("{}", "TX_MODE", "{}", "{}")'.format(name, tx_mode, block_type)) - cmd.append('design.set_property("{}", "TX_OE_PIN", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_OE_PIN", "{}", "{}")'.format(name, oe_pin, block_type)) cmd.append('design.set_property("{}", "TX_OUT_PIN", "{}", "{}")'.format(name, sig.name, block_type)) - cmd.append('design.set_property("{}", "TX_RST_PIN", "", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_SLOWCLK_PIN", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_RST_PIN", "{}", "{}")'.format(name, rst_pin, block_type)) + cmd.append('design.set_property("{}", "TX_SLOWCLK_PIN", "{}", "{}")'.format(name, slow_clk, block_type)) else: block_type = "LVDS_RX" rx_mode = block["rx_mode"] - term = block["term"] - ena = block["ena"] + term = block.get("term", "") + ena = block.get("ena", "") + rx_delay = block.get("rx_delay", "STATIC") + if isinstance(term, Signal): + term = term.name + if isinstance(ena, Signal): + ena = ena.name + + if rx_delay == "STATIC": + delay_ena = "" + delay_inc = "" + delay_rst = "" + else: + delay_ena = block.get("delay_ena", "") + delay_inc = block.get("delay_inc", "") + delay_rst = block.get("delay_rst", "") + + if isinstance(delay_ena, Signal): + delay_ena = delay_ena.name + if isinstance(delay_rst, Signal): + delay_rst = delay_rst.name + if isinstance(delay_inc, Signal): + delay_inc = delay_inc.name cmd.append('design.create_block("{}", block_type="{}", rx_conn_type="{}")'.format(name, block_type, rx_mode)) if self.platform.family == "Titanium": cmd.append('design.set_property("{}","GBUF","","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_DBG_PIN","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_TERM_PIN","{}","{}")'.format(name, term.name, block_type)) + cmd.append('design.set_property("{}","RX_TERM_PIN","{}","{}")'.format(name, term, block_type)) cmd.append('design.set_property("{}","RX_VOC_DRIVER","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_SLVS","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_FIFO","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_HALF_RATE","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_ENA_PIN","{}","{}")'.format(name, ena.name, block_type)) - cmd.append('design.set_property("{}","RX_DELAY_MODE","STATIC","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_DESER","1","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_HALF_RATE","{}","{}")'.format(name, half_rate, block_type)) + cmd.append('design.set_property("{}","RX_ENA_PIN","{}","{}")'.format(name, ena, block_type)) + cmd.append('design.set_property("{}","RX_DESER","{}","{}")'.format(name, size, block_type)) + cmd.append('design.set_property("{}","RX_DELAY_MODE","{}","{}")'.format(name, rx_delay, block_type)) + cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","{}","{}")'.format(name, delay_ena, block_type)) + cmd.append('design.set_property("{}","RX_DLY_INC_PIN","{}","{}")'.format(name, delay_inc, block_type)) + cmd.append('design.set_property("{}","RX_DLY_RST_PIN","{}","{}")'.format(name, delay_rst, block_type)) # Optional - #cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","lvds_rx_inst1_RX_DLY_ENA","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_DLY_INC_PIN","lvds_rx_inst1_RX_DLY_INC","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_DLY_RST_PIN","lvds_rx_inst1_RX_DLY_RST","{}")'.format(name, block_type)) #cmd.append('design.set_property("{}","RX_FIFOCLK_PIN","","{}")'.format(name, block_type)) #cmd.append('design.set_property("{}","RX_FIFO_EMPTY_PIN","lvds_rx_inst1_RX_FIFO_EMPTY","{}")'.format(name, block_type)) #cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) #cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) else: - cmd.append('design.set_property("{}","RX_EN_DELAY","0","{}")'.format(name, block_type)) + rx_delay = "0" if rx_delay == "STATIC" else "1" + cmd.append('design.set_property("{}","RX_EN_DELAY","{}","{}")'.format(name, rx_delay, block_type)) cmd.append('design.set_property("{}","RX_CONN_TYPE","{}","{}")'.format(name, rx_mode, block_type)) - cmd.append('design.set_property("{}","RX_DELAY","16","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_EN_DESER","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_FASTCLK_PIN","","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_DELAY","{}","{}")'.format(name, delay, block_type)) + cmd.append('design.set_property("{}","RX_EN_DESER","{}","{}")'.format(name, serdes, block_type)) + cmd.append('design.set_property("{}","RX_FASTCLK_PIN","{}","{}")'.format(name, fast_clk, block_type)) cmd.append('design.set_property("{}","RX_IN_PIN","{}","{}")'.format(name, sig.name, block_type)) - cmd.append('design.set_property("{}","RX_SLOWCLK_PIN","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_TERM","OFF","{}")'.format(name, block_type)) - # Optional - #cmd.append('design.set_property("{}","RX_RST_PIN","lvds_rx_inst1_RX_RST","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_SLOWCLK_PIN","{}","{}")'.format(name, slow_clk, block_type)) + cmd.append('design.set_property("{}","RX_TERM","ON","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}","RX_RST_PIN","{}","{}")'.format(name, rst_pin, block_type)) cmd.append('design.assign_resource("{}", "{}", "{}")\n'.format(name, location, block_type)) From 232941be24dc7285931075bf36d264836f41015a Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 14 Nov 2023 11:14:57 +0100 Subject: [PATCH 349/454] build/efinix/ifacewriter: generate_lvds: adding missing migen import (required by generate_lvds) --- litex/build/efinix/ifacewriter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 2e94493b9..5609a93b8 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -12,6 +12,8 @@ from xml.dom import expatbuilder import xml.etree.ElementTree as et +from migen import * + from litex.build import tools namespaces = { From 7cee8e10fd437eb8c8f03cfe268f0658f29f71b1 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 14 Nov 2023 11:24:17 +0100 Subject: [PATCH 350/454] build/efinix/ifacewriter: allowing PLL to have LVDS_RX as input type --- litex/build/efinix/ifacewriter.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 5609a93b8..95177b2c1 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -277,7 +277,11 @@ def generate_pll(self, block, partnumber, verbose=True): cmd += 'pll_config = {{ "REFCLK_FREQ":"{}" }}\n'.format(block["input_freq"] / 1e6) cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name) - if block["input_clock"] == "EXTERNAL": + if block["input_clock"] == "LVDS_RX": + cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_src="EXTERNAL", refclk_name="{}", ext_refclk_no="{}", ext_refclk_type="LVDS_RX")\n\n' \ + .format(name, block["resource"], block["input_clock_pad"], block["clock_no"]) + cmd += 'design.set_property("{}","FEEDBACK_MODE","CORE","PLL")\n\n'.format(name) + elif block["input_clock"] == "EXTERNAL": # PLL V1 has a different configuration if partnumber[0:2] in ["T4", "T8"]: cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_res="{}", refclk_name="{}", ext_refclk_no="{}")\n\n' \ From f41ae88d1c302185fe360714a6a8debd0d24aff4 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 14 Nov 2023 11:34:13 +0100 Subject: [PATCH 351/454] soc/cores/clock/efinix: create_clkin: adding lvds_input optional parameter (required when used with LVDS serdes) --- litex/soc/cores/clock/efinix.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index 14fe6414c..fae23d7d4 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -55,7 +55,7 @@ def __init__(self, platform,version="V1_V2", dyn_phase_shift_pads=[]): self.comb += self.platform.add_iface_io(self.name + "_rstn").eq(~self.reset) self.comb += self.locked.eq(self.platform.add_iface_io(self.name + "_locked")) - def register_clkin(self, clkin, freq, name=""): + def register_clkin(self, clkin, freq, name="", lvds_input=False): block = self.platform.toolchain.ifacewriter.get_block(self.name) block["input_clock_name"] = self.platform.get_pin_name(clkin) @@ -79,7 +79,7 @@ def register_clkin(self, clkin, freq, name=""): self.logger.error("Cannot find a pll with {} as input".format(pad_name)) quit() - block["input_clock"] = "EXTERNAL" + block["input_clock"] = "EXTERNAL" if not lvds_input else "LVDS_RX" block["input_clock_pad"] = pin_name block["resource"] = pll_res block["clock_no"] = clock_no From 6d9cacd465c50d3753d5bdeefb9e9097357e7aec Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 14 Nov 2023 13:45:01 +0100 Subject: [PATCH 352/454] core/NaxRiscv update (timing improvements) --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index c9f010ccc..294974b2e 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -315,7 +315,7 @@ def generate_netlist(reset_address): sdir = os.path.join(vdir, "ext", "SpinalHDL") if NaxRiscv.update_repo != "no": - NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "main", "b6d0712f" if NaxRiscv.update_repo=="recommended" else None) + NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "main", "ec3ee4dc" if NaxRiscv.update_repo=="recommended" else None) gen_args = [] gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}") From aa8e9dc32f8fd811b13dbc726c294fba8b3b83b2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 16 Nov 2023 12:38:59 +0100 Subject: [PATCH 353/454] integration/builder: Add bios_format/--bios-format support to allow selecting printf format and pass it to picolibc. Useful to printf of float/double is required. --- litex/soc/integration/builder.py | 5 +++++ litex/soc/software/libc/Makefile | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index ea75e0a66..5e0595ac7 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -86,6 +86,7 @@ def __init__(self, soc, # BIOS. bios_lto = False, + bios_format = "integer", bios_console = "full", # Documentation. @@ -113,6 +114,7 @@ def __init__(self, soc, # BIOS. self.bios_lto = bios_lto + self.bios_format = bios_format self.bios_console = bios_console # Documentation. @@ -159,6 +161,7 @@ def define(k, v): define("SOC_DIRECTORY", soc_directory) define("PICOLIBC_DIRECTORY", picolibc_directory) + define("PICOLIBC_FORMAT", self.bios_format) define("COMPILER_RT_DIRECTORY", compiler_rt_directory) variables_contents.append("export BUILDINC_DIRECTORY") define("BUILDINC_DIRECTORY", self.include_dir) @@ -406,6 +409,7 @@ def builder_args(parser): builder_group.add_argument("--doc", action="store_true", help="Generate SoC Documentation.") bios_group = parser.add_argument_group(title="BIOS options") # FIXME: Move? bios_group.add_argument("--bios-lto", action="store_true", help="Enable BIOS LTO (Link Time Optimization) compilation.") + bios_group.add_argument("--bios-format", default="integer", help="Select BIOS printf format.", choices=["integer", "float", "double"]) bios_group.add_argument("--bios-console", default="full" , help="Select BIOS console config.", choices=["full", "no-history", "no-autocomplete", "lite", "disable"]) def builder_argdict(args): @@ -424,5 +428,6 @@ def builder_argdict(args): "memory_x" : args.memory_x, "generate_doc" : args.doc, "bios_lto" : args.bios_lto, + "bios_format" : args.bios_format, "bios_console" : args.bios_console, } diff --git a/litex/soc/software/libc/Makefile b/litex/soc/software/libc/Makefile index 202460e2c..d67de92e3 100644 --- a/litex/soc/software/libc/Makefile +++ b/litex/soc/software/libc/Makefile @@ -49,7 +49,7 @@ __libc.a: cross.txt -Datomic-ungetc=false \ -Dthread-local-storage=false \ -Dio-long-long=true \ - -Dformat-default=integer \ + -Dformat-default=$(PICOLIBC_FORMAT) \ -Dincludedir=picolibc/$(TRIPLE)/include \ -Dlibdir=picolibc/$(TRIPLE)/lib \ --cross-file cross.txt From 4353135f02f81935a4a20c2e1b71284f385e00db Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 16 Nov 2023 13:47:17 +0100 Subject: [PATCH 354/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index b4b748dc6..1b0363d6e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,6 +27,8 @@ - litedram : Added initial GW5DDRPHY (compiles but not yet working). - build/gowin : Added GowinTristate implementation. - litepcie : Simplify/Cleanup Ultrascale(+) integration and allow .xci generation from .tcl. + - litepcie : Initial 64-bit DMA suppport. + - bios : Added bios_format / --bios-format to allow enabling float/double printf. [> Changed ---------- From c8a9f205e0cd44e7eac1f3d2ccc57e955a0c3b2d Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 14 Nov 2023 21:06:25 +0100 Subject: [PATCH 355/454] soc/cores/clock/efinix: allowing to specify LVDS input refclk name (Trion) --- litex/soc/cores/clock/efinix.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index fae23d7d4..9dd61647d 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -55,7 +55,7 @@ def __init__(self, platform,version="V1_V2", dyn_phase_shift_pads=[]): self.comb += self.platform.add_iface_io(self.name + "_rstn").eq(~self.reset) self.comb += self.locked.eq(self.platform.add_iface_io(self.name + "_locked")) - def register_clkin(self, clkin, freq, name="", lvds_input=False): + def register_clkin(self, clkin, freq, name="", refclk_name="", lvds_input=False): block = self.platform.toolchain.ifacewriter.get_block(self.name) block["input_clock_name"] = self.platform.get_pin_name(clkin) @@ -81,6 +81,7 @@ def register_clkin(self, clkin, freq, name="", lvds_input=False): block["input_clock"] = "EXTERNAL" if not lvds_input else "LVDS_RX" block["input_clock_pad"] = pin_name + block["input_refclk_name"] = refclk_name block["resource"] = pll_res block["clock_no"] = clock_no self.logger.info("Clock source: {}, using EXT_CLK{}".format(block["input_clock"], clock_no)) From cbba5b46e948976ef16ca609740a456c1d8b5426 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 14 Nov 2023 21:59:42 +0100 Subject: [PATCH 356/454] build/efinix/efinity: fix 90 phase shift float -> int (yes: WHY?) --- litex/build/efinix/efinity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 9e2592e01..04f6df610 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -280,6 +280,7 @@ def build_project(self): # FIXME: peri.xml is generated from Efinity, why does it require patching? tools.replace_in_file(f"{self._build_name}.peri.xml", 'adv_out_phase_shift="0.0"', 'adv_out_phase_shift="0"') + tools.replace_in_file(f"{self._build_name}.peri.xml", 'adv_out_phase_shift="90.0"', 'adv_out_phase_shift="90"') def build_script(self): return "" # not used From fecc0cb2271a0b37af13ff77c02fd6fc8ba23b03 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 14 Nov 2023 21:04:35 +0100 Subject: [PATCH 357/454] build/efinix/ifacewriter: PLL/LVDS serdes: Trion support --- litex/build/efinix/ifacewriter.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 95177b2c1..5dc9f59dd 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -278,9 +278,18 @@ def generate_pll(self, block, partnumber, verbose=True): cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name) if block["input_clock"] == "LVDS_RX": - cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_src="EXTERNAL", refclk_name="{}", ext_refclk_no="{}", ext_refclk_type="LVDS_RX")\n\n' \ - .format(name, block["resource"], block["input_clock_pad"], block["clock_no"]) - cmd += 'design.set_property("{}","FEEDBACK_MODE","CORE","PLL")\n\n'.format(name) + if block["version"] == "V3": + cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_src="EXTERNAL", refclk_name="{}", ext_refclk_no="{}", ext_refclk_type="LVDS_RX")\n\n' \ + .format(name, block["resource"], block["input_clock_pad"], block["clock_no"]) + cmd += 'design.set_property("{}","FEEDBACK_MODE","CORE","PLL")\n\n'.format(name) + + else: + cmd += 'design.set_property("{}","EXT_CLK","EXT_CLK{}","PLL")\n'.format(name, block["clock_no"]) + # FIXME: pll feedback + cmd += 'design.set_property("{}","FEEDBACK_MODE","INTERNAL","PLL")\n'.format(name) + cmd += 'design.assign_resource("{}","{}","PLL")\n'.format(name, block["resource"]) + + elif block["input_clock"] == "EXTERNAL": # PLL V1 has a different configuration if partnumber[0:2] in ["T4", "T8"]: @@ -410,13 +419,12 @@ def generate_lvds(self, block, verbose=True): cmd.append('design.set_property("{}", "TX_DIFF_TYPE", "LVDS", "{}")'.format(name, block_type)) cmd.append('design.set_property("{}", "TX_HALF_RATE", "{}", "{}")'.format(name, half_rate, block_type)) cmd.append('design.set_property("{}", "TX_PRE_EMP", "MEDIUM_LOW", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) cmd.append('design.set_property("{}", "TX_VOD", "TYPICAL", "{}")'.format(name, block_type)) else: cmd.append('design.set_property("{}","TX_OUTPUT_LOAD","3","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","TX_REDUCED_SWING","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","TX_SLOWCLK_DIV","1","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","TX_EN_SER","0","{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) cmd.append('design.set_property("{}", "TX_EN_SER", "{}", "{}")'.format(name, serdes, block_type)) cmd.append('design.set_property("{}", "TX_FASTCLK_PIN", "{}", "{}")'.format(name, fast_clk, block_type)) cmd.append('design.set_property("{}", "TX_MODE", "{}", "{}")'.format(name, tx_mode, block_type)) @@ -461,7 +469,6 @@ def generate_lvds(self, block, verbose=True): cmd.append('design.set_property("{}","RX_FIFO","0","{}")'.format(name, block_type)) cmd.append('design.set_property("{}","RX_HALF_RATE","{}","{}")'.format(name, half_rate, block_type)) cmd.append('design.set_property("{}","RX_ENA_PIN","{}","{}")'.format(name, ena, block_type)) - cmd.append('design.set_property("{}","RX_DESER","{}","{}")'.format(name, size, block_type)) cmd.append('design.set_property("{}","RX_DELAY_MODE","{}","{}")'.format(name, rx_delay, block_type)) cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","{}","{}")'.format(name, delay_ena, block_type)) cmd.append('design.set_property("{}","RX_DLY_INC_PIN","{}","{}")'.format(name, delay_inc, block_type)) @@ -472,9 +479,11 @@ def generate_lvds(self, block, verbose=True): #cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) #cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) else: - rx_delay = "0" if rx_delay == "STATIC" else "1" + rx_delay = "0" cmd.append('design.set_property("{}","RX_EN_DELAY","{}","{}")'.format(name, rx_delay, block_type)) + if not (self.platform.family == "Trion" and serdes == 0): + cmd.append('design.set_property("{}","RX_DESER","{}","{}")'.format(name, size, block_type)) cmd.append('design.set_property("{}","RX_CONN_TYPE","{}","{}")'.format(name, rx_mode, block_type)) cmd.append('design.set_property("{}","RX_DELAY","{}","{}")'.format(name, delay, block_type)) cmd.append('design.set_property("{}","RX_EN_DESER","{}","{}")'.format(name, serdes, block_type)) From 022776801a44320b1646b2dffb810c95b8496dfc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 17 Nov 2023 12:06:24 +0100 Subject: [PATCH 358/454] build/efinix/ifacewriter: Ident set_property in generate functions to make it more understandable (for the ones who like black magic... :) --- litex/build/efinix/ifacewriter.py | 148 +++++++++++++++--------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 5dc9f59dd..041928713 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -415,22 +415,22 @@ def generate_lvds(self, block, verbose=True): cmd.append('design.create_block("{}", block_type="{}", tx_mode="{}")'.format(name, block_type, tx_mode)) if self.platform.family == "Titanium": - cmd.append('design.set_property("{}", "TX_DELAY", "{}", "{}")'.format(name, delay, block_type)) - cmd.append('design.set_property("{}", "TX_DIFF_TYPE", "LVDS", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_HALF_RATE", "{}", "{}")'.format(name, half_rate, block_type)) - cmd.append('design.set_property("{}", "TX_PRE_EMP", "MEDIUM_LOW", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_VOD", "TYPICAL", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_DELAY", "{}", "{}")'.format(name, delay, block_type)) + cmd.append('design.set_property("{}", "TX_DIFF_TYPE", "LVDS", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_HALF_RATE", "{}", "{}")'.format(name, half_rate, block_type)) + cmd.append('design.set_property("{}", "TX_PRE_EMP", "MEDIUM_LOW", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_VOD", "TYPICAL", "{}")'.format(name, block_type)) else: - cmd.append('design.set_property("{}","TX_OUTPUT_LOAD","3","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","TX_REDUCED_SWING","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","TX_SLOWCLK_DIV","1","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) - cmd.append('design.set_property("{}", "TX_EN_SER", "{}", "{}")'.format(name, serdes, block_type)) + cmd.append('design.set_property("{}", "TX_OUTPUT_LOAD", "3", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_REDUCED_SWING", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_SLOWCLK_DIV", "1", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "TX_SER", "{}", "{}")'.format(name, size, block_type)) + cmd.append('design.set_property("{}", "TX_EN_SER", "{}", "{}")'.format(name, serdes, block_type)) cmd.append('design.set_property("{}", "TX_FASTCLK_PIN", "{}", "{}")'.format(name, fast_clk, block_type)) - cmd.append('design.set_property("{}", "TX_MODE", "{}", "{}")'.format(name, tx_mode, block_type)) - cmd.append('design.set_property("{}", "TX_OE_PIN", "{}", "{}")'.format(name, oe_pin, block_type)) - cmd.append('design.set_property("{}", "TX_OUT_PIN", "{}", "{}")'.format(name, sig.name, block_type)) - cmd.append('design.set_property("{}", "TX_RST_PIN", "{}", "{}")'.format(name, rst_pin, block_type)) + cmd.append('design.set_property("{}", "TX_MODE", "{}", "{}")'.format(name, tx_mode, block_type)) + cmd.append('design.set_property("{}", "TX_OE_PIN", "{}", "{}")'.format(name, oe_pin, block_type)) + cmd.append('design.set_property("{}", "TX_OUT_PIN", "{}", "{}")'.format(name, sig.name, block_type)) + cmd.append('design.set_property("{}", "TX_RST_PIN", "{}", "{}")'.format(name, rst_pin, block_type)) cmd.append('design.set_property("{}", "TX_SLOWCLK_PIN", "{}", "{}")'.format(name, slow_clk, block_type)) else: block_type = "LVDS_RX" @@ -461,37 +461,37 @@ def generate_lvds(self, block, verbose=True): cmd.append('design.create_block("{}", block_type="{}", rx_conn_type="{}")'.format(name, block_type, rx_mode)) if self.platform.family == "Titanium": - cmd.append('design.set_property("{}","GBUF","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_DBG_PIN","","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_TERM_PIN","{}","{}")'.format(name, term, block_type)) - cmd.append('design.set_property("{}","RX_VOC_DRIVER","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_SLVS","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_FIFO","0","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_HALF_RATE","{}","{}")'.format(name, half_rate, block_type)) - cmd.append('design.set_property("{}","RX_ENA_PIN","{}","{}")'.format(name, ena, block_type)) - cmd.append('design.set_property("{}","RX_DELAY_MODE","{}","{}")'.format(name, rx_delay, block_type)) - cmd.append('design.set_property("{}","RX_DLY_ENA_PIN","{}","{}")'.format(name, delay_ena, block_type)) - cmd.append('design.set_property("{}","RX_DLY_INC_PIN","{}","{}")'.format(name, delay_inc, block_type)) - cmd.append('design.set_property("{}","RX_DLY_RST_PIN","{}","{}")'.format(name, delay_rst, block_type)) + cmd.append('design.set_property("{}", "GBUF", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "RX_DBG_PIN", "", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "RX_TERM_PIN", "{}", "{}")'.format(name, term, block_type)) + cmd.append('design.set_property("{}", "RX_VOC_DRIVER", "0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "RX_SLVS","0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "RX_FIFO","0", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "RX_HALF_RATE", "{}", "{}")'.format(name, half_rate, block_type)) + cmd.append('design.set_property("{}", "RX_ENA_PIN", "{}", "{}")'.format(name, ena, block_type)) + cmd.append('design.set_property("{}", "RX_DELAY_MODE", "{}", "{}")'.format(name, rx_delay, block_type)) + cmd.append('design.set_property("{}", "RX_DLY_ENA_PIN", "{}", "{}")'.format(name, delay_ena, block_type)) + cmd.append('design.set_property("{}", "RX_DLY_INC_PIN", "{}", "{}")'.format(name, delay_inc, block_type)) + cmd.append('design.set_property("{}", "RX_DLY_RST_PIN", "{}", "{}")'.format(name, delay_rst, block_type)) # Optional - #cmd.append('design.set_property("{}","RX_FIFOCLK_PIN","","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_FIFO_EMPTY_PIN","lvds_rx_inst1_RX_FIFO_EMPTY","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_FIFO_RD_PIN","lvds_rx_inst1_RX_FIFO_RD","{}")'.format(name, block_type)) - #cmd.append('design.set_property("{}","RX_LOCK_PIN","lvds_rx_inst1_RX_LOCK","{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}", "RX_FIFOCLK_PIN", "", "{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}", "RX_FIFO_EMPTY_PIN", "lvds_rx_inst1_RX_FIFO_EMPTY", "{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}", "RX_FIFO_RD_PIN", "lvds_rx_inst1_RX_FIFO_RD", "{}")'.format(name, block_type)) + #cmd.append('design.set_property("{}", "RX_LOCK_PIN", "lvds_rx_inst1_RX_LOCK", "{}")'.format(name, block_type)) else: rx_delay = "0" cmd.append('design.set_property("{}","RX_EN_DELAY","{}","{}")'.format(name, rx_delay, block_type)) if not (self.platform.family == "Trion" and serdes == 0): cmd.append('design.set_property("{}","RX_DESER","{}","{}")'.format(name, size, block_type)) - cmd.append('design.set_property("{}","RX_CONN_TYPE","{}","{}")'.format(name, rx_mode, block_type)) - cmd.append('design.set_property("{}","RX_DELAY","{}","{}")'.format(name, delay, block_type)) - cmd.append('design.set_property("{}","RX_EN_DESER","{}","{}")'.format(name, serdes, block_type)) - cmd.append('design.set_property("{}","RX_FASTCLK_PIN","{}","{}")'.format(name, fast_clk, block_type)) - cmd.append('design.set_property("{}","RX_IN_PIN","{}","{}")'.format(name, sig.name, block_type)) - cmd.append('design.set_property("{}","RX_SLOWCLK_PIN","{}","{}")'.format(name, slow_clk, block_type)) - cmd.append('design.set_property("{}","RX_TERM","ON","{}")'.format(name, block_type)) - cmd.append('design.set_property("{}","RX_RST_PIN","{}","{}")'.format(name, rst_pin, block_type)) + cmd.append('design.set_property("{}", "RX_CONN_TYPE", "{}", "{}")'.format(name, rx_mode, block_type)) + cmd.append('design.set_property("{}", "RX_DELAY", "{}", "{}")'.format(name, delay, block_type)) + cmd.append('design.set_property("{}", "RX_EN_DESER", "{}", "{}")'.format(name, serdes, block_type)) + cmd.append('design.set_property("{}", "RX_FASTCLK_PIN", "{}", "{}")'.format(name, fast_clk, block_type)) + cmd.append('design.set_property("{}", "RX_IN_PIN", "{}", "{}")'.format(name, sig.name, block_type)) + cmd.append('design.set_property("{}", "RX_SLOWCLK_PIN", "{}", "{}")'.format(name, slow_clk, block_type)) + cmd.append('design.set_property("{}", "RX_TERM", "ON", "{}")'.format(name, block_type)) + cmd.append('design.set_property("{}", "RX_RST_PIN", "{}", "{}")'.format(name, rst_pin, block_type)) cmd.append('design.assign_resource("{}", "{}", "{}")\n'.format(name, location, block_type)) @@ -508,23 +508,23 @@ def generate_hyperram(self, block, verbose=True): cmd = [] cmd.append('design.create_block("{}", "{}")'.format(name, block_type)) - cmd.append('design.set_property("{}", "CK_N_HI_PIN", "{}", "{}")'.format(name, pads.clkn_h.name, block_type)) - cmd.append('design.set_property("{}", "CK_N_LO_PIN", "{}", "{}")'.format(name, pads.clkn_l.name, block_type)) - cmd.append('design.set_property("{}", "CK_P_HI_PIN", "{}", "{}")'.format(name, pads.clkp_h.name, block_type)) - cmd.append('design.set_property("{}", "CK_P_LO_PIN", "{}", "{}")'.format(name, pads.clkp_l.name, block_type)) - cmd.append('design.set_property("{}", "CLK90_PIN", "{}", "{}")'.format(name, clk90_clk, block_type)) - cmd.append('design.set_property("{}", "CLKCAL_PIN", "{}", "{}")'.format(name, cal_clk, block_type)) - cmd.append('design.set_property("{}", "CLK_PIN", "{}", "{}")'.format(name, ctl_clk, block_type)) - cmd.append('design.set_property("{}", "CS_N_PIN", "{}", "{}")'.format(name, pads.csn.name, block_type)) - cmd.append('design.set_property("{}", "DQ_IN_HI_PIN", "{}", "{}")'.format(name, pads.dq_i_h.name, block_type)) - cmd.append('design.set_property("{}", "DQ_IN_LO_PIN", "{}", "{}")'.format(name, pads.dq_i_l.name, block_type)) - cmd.append('design.set_property("{}", "DQ_OE_PIN", "{}", "{}")'.format(name, pads.dq_oe.name, block_type)) - cmd.append('design.set_property("{}", "DQ_OUT_HI_PIN", "{}", "{}")'.format(name, pads.dq_o_h.name, block_type)) - cmd.append('design.set_property("{}", "DQ_OUT_LO_PIN", "{}", "{}")'.format(name, pads.dq_o_l.name, block_type)) - cmd.append('design.set_property("{}", "RST_N_PIN", "{}", "{}")'.format(name, pads.rstn.name, block_type)) - cmd.append('design.set_property("{}", "RWDS_IN_HI_PIN", "{}", "{}")'.format(name, pads.rwds_i_h.name, block_type)) - cmd.append('design.set_property("{}", "RWDS_IN_LO_PIN", "{}", "{}")'.format(name, pads.rwds_i_l.name, block_type)) - cmd.append('design.set_property("{}", "RWDS_OE_PIN", "{}", "{}")'.format(name, pads.rwds_oe.name, block_type)) + cmd.append('design.set_property("{}", "CK_N_HI_PIN", "{}", "{}")'.format(name, pads.clkn_h.name, block_type)) + cmd.append('design.set_property("{}", "CK_N_LO_PIN", "{}", "{}")'.format(name, pads.clkn_l.name, block_type)) + cmd.append('design.set_property("{}", "CK_P_HI_PIN", "{}", "{}")'.format(name, pads.clkp_h.name, block_type)) + cmd.append('design.set_property("{}", "CK_P_LO_PIN", "{}", "{}")'.format(name, pads.clkp_l.name, block_type)) + cmd.append('design.set_property("{}", "CLK90_PIN", "{}", "{}")'.format(name, clk90_clk, block_type)) + cmd.append('design.set_property("{}", "CLKCAL_PIN", "{}", "{}")'.format(name, cal_clk, block_type)) + cmd.append('design.set_property("{}", "CLK_PIN", "{}", "{}")'.format(name, ctl_clk, block_type)) + cmd.append('design.set_property("{}", "CS_N_PIN", "{}", "{}")'.format(name, pads.csn.name, block_type)) + cmd.append('design.set_property("{}", "DQ_IN_HI_PIN", "{}", "{}")'.format(name, pads.dq_i_h.name, block_type)) + cmd.append('design.set_property("{}", "DQ_IN_LO_PIN", "{}", "{}")'.format(name, pads.dq_i_l.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OE_PIN", "{}", "{}")'.format(name, pads.dq_oe.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OUT_HI_PIN", "{}", "{}")'.format(name, pads.dq_o_h.name, block_type)) + cmd.append('design.set_property("{}", "DQ_OUT_LO_PIN", "{}", "{}")'.format(name, pads.dq_o_l.name, block_type)) + cmd.append('design.set_property("{}", "RST_N_PIN", "{}", "{}")'.format(name, pads.rstn.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_IN_HI_PIN", "{}", "{}")'.format(name, pads.rwds_i_h.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_IN_LO_PIN", "{}", "{}")'.format(name, pads.rwds_i_l.name, block_type)) + cmd.append('design.set_property("{}", "RWDS_OE_PIN", "{}", "{}")'.format(name, pads.rwds_oe.name, block_type)) cmd.append('design.set_property("{}", "RWDS_OUT_HI_PIN", "{}", "{}")'.format(name, pads.rwds_o_h.name, block_type)) cmd.append('design.set_property("{}", "RWDS_OUT_LO_PIN", "{}", "{}")'.format(name, pads.rwds_o_l.name, block_type)) @@ -548,27 +548,27 @@ def generate_spiflash(self, block, verbose=True): cmd = [] cmd.append('design.create_block("{}", "SPI_FLASH")'.format(name)) - cmd.append('design.set_property("{}", "MULT_CTRL_EN","0","SPI_FLASH")'.format(name)) - cmd.append('design.set_property("{}", "REG_EN","0","SPI_FLASH")'.format(name)) - cmd.append('design.set_property("{}", "CLK_PIN","","SPI_FLASH")'.format(name)) # only required when REG_EN==1 - cmd.append('design.set_property("{}", "RW_WIDTH","{}","SPI_FLASH")'.format(name, mode)) - - cmd.append('design.set_property("{}", "CS_N_OUT_PIN","{}","SPI_FLASH")'.format(name, pads.cs_n.name)) - cmd.append('design.set_property("{}", "SCLK_OUT_PIN","{}","SPI_FLASH")'.format(name, pads.clk.name)) - cmd.append('design.set_property("{}", "MOSI_OUT_PIN","{}","SPI_FLASH")'.format(name, dq0)) - cmd.append('design.set_property("{}", "MISO_IN_PIN","{}","SPI_FLASH")'.format(name, dq1)) - cmd.append('design.set_property("{}", "WP_N_OUT_PIN","{}","SPI_FLASH")'.format(name, dq2)) - cmd.append('design.set_property("{}", "HOLD_N_OUT_PIN","{}","SPI_FLASH")'.format(name, dq3)) + cmd.append('design.set_property("{}", "MULT_CTRL_EN", "0", "SPI_FLASH")'.format(name)) + cmd.append('design.set_property("{}", "REG_EN", "0", "SPI_FLASH")'.format(name)) + cmd.append('design.set_property("{}", "CLK_PIN", "", "SPI_FLASH")'.format(name)) # only required when REG_EN==1 + cmd.append('design.set_property("{}", "RW_WIDTH", "{}", "SPI_FLASH")'.format(name, mode)) + + cmd.append('design.set_property("{}", "CS_N_OUT_PIN", "{}", "SPI_FLASH")'.format(name, pads.cs_n.name)) + cmd.append('design.set_property("{}", "SCLK_OUT_PIN", "{}", "SPI_FLASH")'.format(name, pads.clk.name)) + cmd.append('design.set_property("{}", "MOSI_OUT_PIN", "{}", "SPI_FLASH")'.format(name, dq0)) + cmd.append('design.set_property("{}", "MISO_IN_PIN", "{}", "SPI_FLASH")'.format(name, dq1)) + cmd.append('design.set_property("{}", "WP_N_OUT_PIN", "{}", "SPI_FLASH")'.format(name, dq2)) + cmd.append('design.set_property("{}", "HOLD_N_OUT_PIN", "{}", "SPI_FLASH")'.format(name, dq3)) if mode == "x4": - cmd.append('design.set_property("{}", "HOLD_N_IN_PIN","{}","SPI_FLASH")'.format(name, dq3_i)) - cmd.append('design.set_property("{}", "HOLD_N_OE_PIN","{}","SPI_FLASH")'.format(name, dq3_oe)) - cmd.append('design.set_property("{}", "MISO_OUT_PIN","{}","SPI_FLASH")'.format(name, dq1_o)) - cmd.append('design.set_property("{}", "MISO_OE_PIN","{}","SPI_FLASH")'.format(name, dq1_oe)) - cmd.append('design.set_property("{}", "MOSI_IN_PIN","{}","SPI_FLASH")'.format(name, dq0_i)) - cmd.append('design.set_property("{}", "MOSI_OE_PIN","{}","SPI_FLASH")'.format(name, dq0_oe)) - cmd.append('design.set_property("{}", "WP_N_IN_PIN","{}","SPI_FLASH")'.format(name, dq2_i)) - cmd.append('design.set_property("{}", "WP_N_OE_PIN","{}","SPI_FLASH")'.format(name, dq2_oe)) + cmd.append('design.set_property("{}", "HOLD_N_IN_PIN", "{}", "SPI_FLASH")'.format(name, dq3_i)) + cmd.append('design.set_property("{}", "HOLD_N_OE_PIN", "{}", "SPI_FLASH")'.format(name, dq3_oe)) + cmd.append('design.set_property("{}", "MISO_OUT_PIN", "{}", "SPI_FLASH")'.format(name, dq1_o)) + cmd.append('design.set_property("{}", "MISO_OE_PIN", "{}", "SPI_FLASH")'.format(name, dq1_oe)) + cmd.append('design.set_property("{}", "MOSI_IN_PIN", "{}", "SPI_FLASH")'.format(name, dq0_i)) + cmd.append('design.set_property("{}", "MOSI_OE_PIN", "{}", "SPI_FLASH")'.format(name, dq0_oe)) + cmd.append('design.set_property("{}", "WP_N_IN_PIN", "{}", "SPI_FLASH")'.format(name, dq2_i)) + cmd.append('design.set_property("{}", "WP_N_OE_PIN", "{}", "SPI_FLASH")'.format(name, dq2_oe)) # mult ctrl en only #cmd.append('design.set_property("{}", "CS_N_OE_PIN","{}","SPI_FLASH")'.format(name, cs_n_oe)) From cba58a0e361b113108be2678a31e75d24cf64262 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 23 Nov 2023 16:30:29 +0100 Subject: [PATCH 359/454] tools/litex_client: Fix csr_data_width/csr_bus_address_width is None cases. --- litex/tools/litex_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/tools/litex_client.py b/litex/tools/litex_client.py index 5a9c18b49..ad30d687b 100644 --- a/litex/tools/litex_client.py +++ b/litex/tools/litex_client.py @@ -32,9 +32,9 @@ def __init__(self, host="localhost", port=1234, base_address=0, csr_csv=None, cs else: # Else if csr_data_width set to None, force to csr_data_width 32-bit. if csr_data_width is None: - csr_data_width = 32 + self.csr_data_width = 32 # Else if csr_bus_address_width set to None, force to csr_bus_address_width 32-bit. - if self.csr_bus_address_width is None: + if csr_bus_address_width is None: self.csr_bus_address_width = 32 self.host = host self.port = port From fba581f77e6542e438d990a59a5efbc7cf92641e Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 30 Nov 2023 17:46:55 +0100 Subject: [PATCH 360/454] build/efinix/ifacewriter: LVDS_RX/Trion: enable static rx delay when delay > 0 --- litex/build/efinix/ifacewriter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 041928713..bbd9a6e01 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -479,7 +479,7 @@ def generate_lvds(self, block, verbose=True): #cmd.append('design.set_property("{}", "RX_FIFO_RD_PIN", "lvds_rx_inst1_RX_FIFO_RD", "{}")'.format(name, block_type)) #cmd.append('design.set_property("{}", "RX_LOCK_PIN", "lvds_rx_inst1_RX_LOCK", "{}")'.format(name, block_type)) else: - rx_delay = "0" + rx_delay = "0" if delay == 0 else "1" cmd.append('design.set_property("{}","RX_EN_DELAY","{}","{}")'.format(name, rx_delay, block_type)) if not (self.platform.family == "Trion" and serdes == 0): From a4ead5cab9d341d1b642c016b5f8526b645b3b40 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 30 Nov 2023 17:47:32 +0100 Subject: [PATCH 361/454] litex/soc/integration/soc: SoCBusHandler 64bits address width support --- litex/soc/integration/soc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 96d7f2abb..eedcc82b2 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -108,7 +108,7 @@ def __init__(self, origin, busword, obj): class SoCBusHandler(LiteXModule): supported_standard = ["wishbone", "axi-lite", "axi"] supported_data_width = [32, 64, 128, 256, 512] - supported_address_width = [32] + supported_address_width = [32, 64] # Creation ------------------------------------------------------------------------------------- def __init__(self, name="SoCBusHandler", From 08a62d4b5fc8d70556e9f6eaa664690e591f1ae7 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 6 Dec 2023 16:58:50 +0100 Subject: [PATCH 362/454] build/efinix/ifacewriter: PLL feedback for Trion --- litex/build/efinix/ifacewriter.py | 36 +++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index bbd9a6e01..be480cb26 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -285,8 +285,11 @@ def generate_pll(self, block, partnumber, verbose=True): else: cmd += 'design.set_property("{}","EXT_CLK","EXT_CLK{}","PLL")\n'.format(name, block["clock_no"]) - # FIXME: pll feedback - cmd += 'design.set_property("{}","FEEDBACK_MODE","INTERNAL","PLL")\n'.format(name) + if block["feedback"] != -1: + cmd += 'design.set_property("{}","FEEDBACK_MODE","{}","PLL")\n'.format(name, "CORE" if block["feedback"] == 0 else "LOCAL") + cmd += 'design.set_property("{}","FEEDBACK_CLK","CLK{}","PLL")\n'.format(name, block["feedback"]) + else: + cmd += 'design.set_property("{}","FEEDBACK_MODE","INTERNAL","PLL")\n'.format(name) cmd += 'design.assign_resource("{}","{}","PLL")\n'.format(name, block["resource"]) @@ -326,15 +329,26 @@ def generate_pll(self, block, partnumber, verbose=True): else: cmd += 'design.set_property("{}","CLKOUT{}_PHASE_SETTING","{}","PLL")\n'.format(name, i, clock[2] // 45) - cmd += "target_freq = {\n" - for i, clock in enumerate(block["clk_out"]): - cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6) - cmd += ' "CLKOUT{}_PHASE": "{}",\n'.format(i, clock[2]) - if clock[4] == 1: - cmd += ' "CLKOUT{}_DYNPHASE_EN": "1",\n'.format(i) - cmd += "}\n" - - cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n'.format(name) + if block["feedback"] == -1: + cmd += "target_freq = {\n" + for i, clock in enumerate(block["clk_out"]): + cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6) + cmd += ' "CLKOUT{}_PHASE": "{}",\n'.format(i, clock[2]) + if clock[4] == 1: + cmd += ' "CLKOUT{}_DYNPHASE_EN": "1",\n'.format(i) + cmd += "}\n" + + cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n'.format(name) + cmd += 'for c in calc_result:\n' + cmd += ' print(c)\n' + else: + cmd += 'design.set_property("{}","M","{}","PLL")\n'.format(name, block["M"]) + cmd += 'design.set_property("{}","N","{}","PLL")\n'.format(name, block["N"]) + cmd += 'design.set_property("{}","O","{}","PLL")\n'.format(name, block["O"]) + for i, clock in enumerate(block["clk_out"]): + cmd += 'design.set_property("{}","CLKOUT{}_PHASE","{}","PLL")\n'.format(name, i, clock[2]) + #cmd += 'design.set_property("{}","CLKOUT{}_FREQ","{}","PLL")\n'.format(name, i, clock[2]) + cmd += 'design.set_property("{}","CLKOUT{}_DIV","{}","PLL")\n'.format(name, i, block[f"CLKOUT{i}_DIV"]) if "extra" in block: cmd += block["extra"] From 491a207a377ca30eedebced1502b28ca16260a7d Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 6 Dec 2023 17:02:53 +0100 Subject: [PATCH 363/454] soc/cores/clock/efinix: calc PLL parameters for Trion when feedback != INTERNAL --- litex/soc/cores/clock/efinix.py | 209 +++++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index 9dd61647d..ba803c741 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -45,6 +45,7 @@ def __init__(self, platform,version="V1_V2", dyn_phase_shift_pads=[]): block["locked"] = self.name + "_locked" block["rstn"] = self.name + "_rstn" block["version"] = version + block["feedback"] = -1 if len(dyn_phase_shift_pads) > 0: block["shift_ena"] = dyn_phase_shift_pads["shift_ena"] block["shift"] = dyn_phase_shift_pads["shift"] @@ -99,7 +100,7 @@ def register_clkin(self, clkin, freq, name="", refclk_name="", lvds_input=False) self.logger.info("Use {}".format(colorer(block["resource"], "green"))) - def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True, dyn_phase=False): + def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True, dyn_phase=False, is_feedback=False): assert self.nclkouts < self.nclkouts_max clk_out_name = f"{self.name}_clkout{self.nclkouts}" if name == "" else name @@ -116,9 +117,14 @@ def create_clkout(self, cd, freq, phase=0, margin=0, name="", with_reset=True, d create_clkout_log(self.logger, clk_out_name, freq, margin, self.nclkouts) + block = self.platform.toolchain.ifacewriter.get_block(self.name) + + if is_feedback: + assert block["feedback"] == -1 + block["feedback"] = self.nclkouts + self.nclkouts += 1 - block = self.platform.toolchain.ifacewriter.get_block(self.name) block["clk_out"].append([clk_out_name, freq, phase, margin, dyn_phase]) def extra(self, extra): @@ -126,13 +132,176 @@ def extra(self, extra): block["extra"] = extra def compute_config(self): - pass + import math + + block = self.platform.toolchain.ifacewriter.get_block(self.name) + if block["feedback"] == -1: + return + clks_out = {} + for clk_id, clk in enumerate(block["clk_out"]): + clks_out[clk_id] = {"freq": clk[1], "phase": clk[2]} + + n_out = self.nclkouts + clk_in_freq = block["input_freq"] + clk_fb_id = block["feedback"] + device = self.platform.device + + vco_range = self.get_vco_freq_range(device) + pfd_range = self.get_pfd_freq_range(device) + pll_range = self.get_pll_freq_range(device) + + if n_out > 1: + O_fact = [2, 4, 8] + else: + O_fact = [1, 2, 4, 8] + + # Pre-Divider (N). + # ----------------- + # F_PFD is between 10e6 and 100e6 + # so limit search to only acceptable factors + N_min = int(math.ceil(clk_in_freq / pfd_range[1])) + N_max = int(math.floor(clk_in_freq / pfd_range[0])) + ## limit + ### when fin is below FPLL_MAX min is < 1 + if N_min < 1: + N_min = 1 + ### when fin is above FPLL_MIN and/or near max possible freq max is > 15 + if N_max > 15: + N_max = 15 + + # Multiplier (M). + # --------------- + ## 1. needs to know all ffbk * o * cfbk acceptable to max FVCO range + oc_range = [] + oc_min = 256*8 + oc_max = 0 + clk_fb_freq = clks_out[clk_fb_id]["freq"] + clk_fb_phase = clks_out[clk_fb_id]["phase"] + + c_range = self.get_c_range(device, clk_fb_phase) + # FIXME: c_range must be limited to min/max + for c in c_range: # 1. iterate around C factor and check fPLL + if clk_fb_freq * c < pll_range[0] or clk_fb_freq > pll_range[1]: + continue + for o in O_fact: + oc = o * c + fvco_tmp = clk_fb_freq * oc + if fvco_tmp >= vco_range[0] and fvco_tmp <= vco_range[1]: + oc_range.append([o, c]) + # again get range + if oc > oc_max: + oc_max = oc + if oc < oc_min: + oc_min = oc + + ## 2. compute FVCO equation with informations already obtained + ## ie try all possible Fpfd freqs and try to find M with FVCO respect + ## when params are valid try to find Cx for each clock output enabled + params_list = [] + for n in range(N_min, N_max + 1): + fpfd_tmp = clk_in_freq / n + # limit range using FVCO_MAX & FVCO_MIN + # fVCO = fPFD * M * O * Cfbk + # so: + # fVCO + # M = --------------- + # fPFD * O * Cfbf + # + M_min = int(math.ceil(vco_range[0] / (fpfd_tmp * oc_max))) + M_max = int(math.floor(vco_range[1] / (fpfd_tmp * oc_min))) + if M_min < 1: + M_min = 1 + if M_max > 255: + M_max = 255 + for m in range(M_min, M_max + 1): + for oc in oc_range: + [o, c] = oc + fvco_tmp = fpfd_tmp * m * o * c + if fvco_tmp >= vco_range[0] and fvco_tmp <= vco_range[1]: + # m * o * c must be below 256 + if m * o * c > 255: + continue + + fpll_tmp = fvco_tmp / o + cx_list = [] + for clk_id, clk_cfg in clks_out.items(): + found = False + c_div = self.get_c_range(device, clk_cfg["phase"]) + c_list = [] + for cx in c_div: + if clk_id == clk_fb_id and cx != c: + continue + clk_out = fpll_tmp / cx + # if a C is found: no need to search more + if clk_out == clk_cfg["freq"]: + cx_list.append(cx) + found = True + break + # no solution found for this clk: params are uncompatibles + if found == False: + break + if len(cx_list) == 2: + params_list.append([n, m, o, c, cx_list[0], cx_list[1]]) + vco_max_freq = 0 + o_div_max = 0 + params_list2 = [] + for p in params_list: + (n, m, o, c, c0, c1) = p + fpfd_tmp = clk_in_freq / n + fvco_tmp = fpfd_tmp * m * o * c + if o > o_div_max: + o_div_max = o + # Interface designer always select high VCO freq + if fvco_tmp > vco_max_freq: + vco_max_freq = fvco_tmp + params_list2.clear() + fpll_tmp = fvco_tmp / o + if fvco_tmp == vco_max_freq: + params_list2.append({ + "fvco" : fvco_tmp, + "fpll" : fpll_tmp, + "fpfd" : fpfd_tmp, + "M" : m, + "N" : n, + "O" : o, + "Cfbk" : c, + "c0" : c0, + "c1" : c1, + }) + + # Again: Interface Designer prefers high O divider. + # ------------------------------------------------- + final_list = [] + for p in params_list2: + if p["O"] == o_div_max: + final_list.append(p) + + assert len(final_list) != 0 + + # Select first parameters set. + # ---------------------------- + final_list = final_list[0] + + # Fill block with PLL configuration parameters. + # --------------------------------------------- + block["M"] = final_list["M"] + block["N"] = final_list["N"] + block["O"] = final_list["O"] + block["VCO_FREQ"] = final_list["fvco"] + for i in range(self.nclkouts): + block[f"CLKOUT{i}_DIV"] = final_list[f"c{i}"] def set_configuration(self): pass def do_finalize(self): - pass + # FIXME + if not self.platform.family == "Trion": + return + + # compute PLL configuration and arbitrary select first result + self.compute_config() + # Efinix / TITANIUMPLL ----------------------------------------------------------------------------- @@ -147,3 +316,35 @@ class TRIONPLL(EFINIXPLL): nclkouts_max = 3 def __init__(self, platform): EFINIXPLL.__init__(self, platform, version="V1_V2") + + @staticmethod + def get_vco_freq_range(device): + FVCO_MIN = 500e6 + FVCO_MAX = 3600e6 # Local/Core, 1600 otherwise + #FVCO_MIN = 1600e6 + return (FVCO_MIN, FVCO_MAX) + + @staticmethod + def get_pfd_freq_range(device): + FPFD_MIN = 10e6 + FPFD_MAX = 100e6 + return (FPFD_MIN, FPFD_MAX) + + @staticmethod + def get_pll_freq_range(device): + FPLL_MIN = 62.5e6 + FPLL_MAX = 1800e6 # when all C are < 64 else 1400 + return (FPLL_MIN, FPLL_MAX) + + @staticmethod + def get_c_range(device, phase=0): + if phase == 0: + return [i for i in range(1, 257)] + + return { + 45: [4], + 90: [2, 4, 6], + 135: [4], + 180: [2], + 270: [2] + }[phase] From afaeca98ce750db211b64db23a9e9be72aa8f212 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 7 Dec 2023 16:33:32 +0100 Subject: [PATCH 364/454] CHANGES.md: Update. --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 1b0363d6e..8562ae949 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,6 +29,9 @@ - litepcie : Simplify/Cleanup Ultrascale(+) integration and allow .xci generation from .tcl. - litepcie : Initial 64-bit DMA suppport. - bios : Added bios_format / --bios-format to allow enabling float/double printf. + - soc/cores/clock : Added proper clock feedback support on Efinix TRIONPLL. + - liteiclink/phy : Added Efinix support/examples on Trion/Titanium. + - liteiclink/serwb : Reused Etherbone from LiteEth to avoid code duplication. [> Changed ---------- From 01ce8ab0d1fb33e9700f754409dd6d7ccb3d61e0 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Fri, 8 Dec 2023 11:57:35 +0100 Subject: [PATCH 365/454] soc/interconnect/axi/axi_lite:axi_lite_to_simple: avoid multiple read access --- litex/soc/interconnect/axi/axi_lite.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_lite.py b/litex/soc/interconnect/axi/axi_lite.py index 6c7ad3db9..37d7f6c5e 100644 --- a/litex/soc/interconnect/axi/axi_lite.py +++ b/litex/soc/interconnect/axi/axi_lite.py @@ -132,11 +132,12 @@ def read(self, addr): def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we=None): """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port""" - bus_data_width = axi_lite.data_width - adr_shift = log2_int(bus_data_width//8) - do_read = Signal() - do_write = Signal() - last_was_read = Signal() + bus_data_width = axi_lite.data_width + adr_shift = log2_int(bus_data_width//8) + do_read = Signal() + do_write = Signal() + last_was_read = Signal() + port_dat_r_latched = Signal(axi_lite.data_width) comb = [] if port_dat_w is not None: @@ -169,14 +170,17 @@ def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we= ) ).Elif(do_read, port_adr.eq(axi_lite.ar.addr[adr_shift:]), - NextState("SEND-READ-RESPONSE"), + NextState("LATCH-READ-RESPONSE"), ) ) + fsm.act("LATCH-READ-RESPONSE", + NextValue(port_dat_r_latched, port_dat_r), + NextState("SEND-READ-RESPONSE") + ), fsm.act("SEND-READ-RESPONSE", NextValue(last_was_read, 1), # As long as we have correct address port.dat_r will be valid. - port_adr.eq(axi_lite.ar.addr[adr_shift:]), - axi_lite.r.data.eq(port_dat_r), + axi_lite.r.data.eq(port_dat_r_latched), axi_lite.r.resp.eq(RESP_OKAY), axi_lite.r.valid.eq(1), If(axi_lite.r.ready, From 13987659a908852aba36ba33120723e8f3244a28 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Fri, 8 Dec 2023 11:59:33 +0100 Subject: [PATCH 366/454] soc/interconnect/axi/axi_lite: AXILiteInterconnectShared, AXILiteCrossbar: propagate master bus address width to Interface --- litex/soc/interconnect/axi/axi_lite.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_lite.py b/litex/soc/interconnect/axi/axi_lite.py index 37d7f6c5e..64d514d91 100644 --- a/litex/soc/interconnect/axi/axi_lite.py +++ b/litex/soc/interconnect/axi/axi_lite.py @@ -132,11 +132,12 @@ def read(self, addr): def axi_lite_to_simple(axi_lite, port_adr, port_dat_r, port_dat_w=None, port_we=None): """Connection of AXILite to simple bus with 1-cycle latency, such as CSR bus or Memory port""" - bus_data_width = axi_lite.data_width - adr_shift = log2_int(bus_data_width//8) - do_read = Signal() - do_write = Signal() - last_was_read = Signal() + bus_data_width = axi_lite.data_width + adr_shift = log2_int(bus_data_width//8) + do_read = Signal() + do_write = Signal() + last_was_read = Signal() + port_dat_r_latched = Signal(axi_lite.data_width) comb = [] @@ -777,7 +778,8 @@ class AXILiteInterconnectShared(LiteXModule): """AXI Lite shared interconnect""" def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) - shared = AXILiteInterface(data_width=data_width) + adr_width = max([m.address_width for m in masters]) + shared = AXILiteInterface(data_width=data_width, address_width=adr_width) self.arbiter = AXILiteArbiter(masters, shared) self.decoder = AXILiteDecoder(shared, slaves) if timeout_cycles is not None: @@ -790,8 +792,9 @@ class AXILiteCrossbar(LiteXModule): """ def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) + adr_width = max([m.address_width for m in masters]) matches, busses = zip(*slaves) - access_m_s = [[AXILiteInterface(data_width=data_width) for j in slaves] for i in masters] # a[master][slave] + access_m_s = [[AXILiteInterface(data_width=data_width, address_width=adr_width) for j in slaves] for i in masters] # a[master][slave] access_s_m = list(zip(*access_m_s)) # a[slave][master] # Decode each master into its access row. for slaves, master in zip(access_m_s, masters): From 1a8fd2e808cba1a0790b9ae28c4812c74fa2caf7 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Fri, 8 Dec 2023 12:00:50 +0100 Subject: [PATCH 367/454] soc/interconnect/axi/axi_full: AXIInterconnectShared, AXICrossbar: propagate master bus address width to Interface --- litex/soc/interconnect/axi/axi_full.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/litex/soc/interconnect/axi/axi_full.py b/litex/soc/interconnect/axi/axi_full.py index 83410819a..dd7303878 100644 --- a/litex/soc/interconnect/axi/axi_full.py +++ b/litex/soc/interconnect/axi/axi_full.py @@ -613,7 +613,8 @@ class AXIInterconnectShared(LiteXModule): """AXI shared interconnect""" def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) - shared = AXIInterface(data_width=data_width) + adr_width = max([m.address_width for m in masters]) + shared = AXIInterface(data_width=data_width, address_width=adr_width) self.arbiter = AXIArbiter(masters, shared) self.decoder = AXIDecoder(shared, slaves) if timeout_cycles is not None: @@ -626,8 +627,9 @@ class AXICrossbar(LiteXModule): """ def __init__(self, masters, slaves, register=False, timeout_cycles=1e6): data_width = get_check_parameters(ports=masters + [s for _, s in slaves]) + adr_width = max([m.address_width for m in masters]) matches, busses = zip(*slaves) - access_m_s = [[AXIInterface(data_width=data_width) for j in slaves] for i in masters] # a[master][slave] + access_m_s = [[AXIInterface(data_width=data_width, address_width=adr_width) for j in slaves] for i in masters] # a[master][slave] access_s_m = list(zip(*access_m_s)) # a[slave][master] # Decode each master into its access row. for slaves, master in zip(access_m_s, masters): From 2134c0d0b027934a99e135af93ac8ee48a2f0e5b Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Fri, 8 Dec 2023 12:02:45 +0100 Subject: [PATCH 368/454] soc/integration/soc: when adding a CSR Bridge bus_bridge must keep bus.address_width instead of the default value --- litex/soc/integration/soc.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index eedcc82b2..bede4562d 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1039,9 +1039,17 @@ def add_csr_bridge(self, name="csr", origin=None, register=False): "axi-lite": axi.AXILite2CSR, "axi" : axi.AXILite2CSR, # Note: CSR is a slow bus so using AXI-Lite is fine. }[self.bus.standard] + bus_bridge_cls = { + "wishbone": wishbone.Interface, + "axi-lite": axi.AXILiteInterface, + "axi" : axi.AXILiteInterface, + }[self.bus.standard] csr_bridge_name = f"{name}_bridge" self.check_if_exists(csr_bridge_name) csr_bridge = csr_bridge_cls( + bus_bridge_cls( + address_width = self.bus.address_width, + data_width = self.bus.data_width), bus_csr = csr_bus.Interface( address_width = self.csr.address_width, data_width = self.csr.data_width), From 8d6120c47683107e751ff7845f3d1f44b26efeb1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 8 Dec 2023 12:11:37 +0100 Subject: [PATCH 369/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 8562ae949..7ce0bbe08 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ - liteeth/arp : Fixed response on table update. - litesata/us(p)sataphy : Fixed data_width=32 case. - clock/lattice_ecp5 : Fixed phase calculation. + - interconnect/axi : Fixed AXILite2CSR read access (1 CSR cycle instead of 2). [> Added -------- @@ -32,6 +33,7 @@ - soc/cores/clock : Added proper clock feedback support on Efinix TRIONPLL. - liteiclink/phy : Added Efinix support/examples on Trion/Titanium. - liteiclink/serwb : Reused Etherbone from LiteEth to avoid code duplication. + - interconnect : Added 64-bit support to Wishbone/AXI-Lite/AXI. [> Changed ---------- From acd66f13464e2b8f8fb0cd996d6fdcb88dce83a8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 8 Dec 2023 15:25:27 +0100 Subject: [PATCH 370/454] soc/bus_addressing_convert: Fix s2m adaptation case, the 2 adaptation cases were swapped. --- litex/soc/integration/soc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index bede4562d..753f9b94b 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -371,9 +371,9 @@ def bus_addressing_convert(interface, direction): if direction == "s2m": self.comb += adapted_interface.connect(interface, omit={"adr"}) if (interface.addressing == "word") and (self.addressing == "byte"): - self.comb += interface.adr[address_shift:].eq(adapted_interface.adr) - if (interface.addressing == "byte") and (self.addressing == "word"): self.comb += interface.adr.eq(adapted_interface.adr[address_shift:]) + if (interface.addressing == "byte") and (self.addressing == "word"): + self.comb += interface.adr[address_shift:].eq(adapted_interface.adr) return adapted_interface # Bus-Standard conversion helper. @@ -1756,6 +1756,7 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, ethmac_region_size = (ethmac.rx_slots.constant + ethmac.tx_slots.constant)*ethmac.slot_size.constant ethmac_region = SoCRegion(origin=self.mem_map.get(name, None), size=ethmac_region_size, cached=False) self.bus.add_slave(name=name, slave=ethmac.bus, region=ethmac_region) + # Add IRQs (if enabled). if self.irq.enabled: self.irq.add(name, use_loc_if_exists=True) From c1871eaf42a32b4bafdc6a6383804f7a8a9e8e3b Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 9 Dec 2023 06:07:58 +0100 Subject: [PATCH 371/454] soc/integration/soc: add_jtagbone: pass address_width to UARTBone constructor --- litex/soc/integration/soc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 753f9b94b..91b3b0931 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1527,7 +1527,11 @@ def add_jtagbone(self, name="jtagbone", chain=1): # Core. self.check_if_exists(name) jtagbone_phy = JTAGPHY(device=self.platform.device, chain=chain, platform=self.platform) - jtagbone = uart.UARTBone(phy=jtagbone_phy, clk_freq=self.sys_clk_freq) + jtagbone = uart.UARTBone( + phy = jtagbone_phy, + clk_freq = self.sys_clk_freq, + address_width = self.bus.address_width + ) self.add_module(name=f"{name}_phy", module=jtagbone_phy) self.add_module(name=name, module=jtagbone) self.bus.add_master(name=name, master=jtagbone.wishbone) From 08ff00317851345c7486aa58d8d2f5d07c9c8522 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 9 Dec 2023 06:08:53 +0100 Subject: [PATCH 372/454] tools/litex_server.py: jtag/udp mode: add missing addr_width parameter --- litex/tools/litex_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/tools/litex_server.py b/litex/tools/litex_server.py index 9599a164b..6ca88c42f 100755 --- a/litex/tools/litex_server.py +++ b/litex/tools/litex_server.py @@ -231,7 +231,7 @@ def main(): jtag_uart = JTAGUART(config=args.jtag_config, chain=int(args.jtag_chain)) jtag_uart.open() print("[CommUART] port: JTAG / ", end="") - comm = CommUART(os.ttyname(jtag_uart.name), debug=args.debug) + comm = CommUART(os.ttyname(jtag_uart.name), debug=args.debug, addr_width=int(args.addr_width)) # UDP mode elif args.udp: @@ -250,7 +250,7 @@ def main(): exit() else: print("[CommUDP] ip: {} / port: {} / ".format(udp_ip, udp_port), end="") - comm = CommUDP(udp_ip, udp_port, debug=args.debug) + comm = CommUDP(udp_ip, udp_port, debug=args.debug, addr_width=int(args.addr_width)) # PCIe mode elif args.pcie: From 6d34b8ed87101f52880e020219a3eb0194413955 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 12 Dec 2023 12:05:47 +0100 Subject: [PATCH 373/454] soc/integration/soc: add_sdram, remove litedram_wb and converter: let LiteDRAMWishbone2Native dealing with addr/data width --- litex/soc/integration/soc.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 91b3b0931..b6ac59123 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1710,15 +1710,12 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, if l2_cache_full_memory_we: l2_cache = FullMemoryWE()(l2_cache) self.l2_cache = l2_cache - litedram_wb = self.l2_cache.slave + wb_sdram = self.l2_cache.slave self.add_config("L2_SIZE", l2_cache_size) - else: - litedram_wb = wishbone.Interface(data_width=port.data_width, address_width=32, addressing="word") - self.submodules += wishbone.Converter(wb_sdram, litedram_wb) # Wishbone Slave <--> LiteDRAM bridge. self.wishbone_bridge = LiteDRAMWishbone2Native( - wishbone = litedram_wb, + wishbone = wb_sdram, port = port, base_address = self.bus.regions["main_ram"].origin ) From 94eca8628c95e6ce3dd007b315d13f1574649962 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 12 Dec 2023 15:19:16 +0100 Subject: [PATCH 374/454] Revert "soc/integration/soc: add_sdram, remove litedram_wb and converter: let LiteDRAMWishbone2Native dealing with addr/data width" This reverts commit 6d34b8ed87101f52880e020219a3eb0194413955. --- litex/soc/integration/soc.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index b6ac59123..91b3b0931 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1710,12 +1710,15 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, if l2_cache_full_memory_we: l2_cache = FullMemoryWE()(l2_cache) self.l2_cache = l2_cache - wb_sdram = self.l2_cache.slave + litedram_wb = self.l2_cache.slave self.add_config("L2_SIZE", l2_cache_size) + else: + litedram_wb = wishbone.Interface(data_width=port.data_width, address_width=32, addressing="word") + self.submodules += wishbone.Converter(wb_sdram, litedram_wb) # Wishbone Slave <--> LiteDRAM bridge. self.wishbone_bridge = LiteDRAMWishbone2Native( - wishbone = wb_sdram, + wishbone = litedram_wb, port = port, base_address = self.bus.regions["main_ram"].origin ) From f2c5ff376cec12c1bfed24202d4fa015f0320565 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 13 Dec 2023 09:16:55 +0100 Subject: [PATCH 375/454] soc/cores/jtag: Switch to stream.ClockDomainCrossing and use common_rst. --- litex/soc/cores/jtag.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/litex/soc/cores/jtag.py b/litex/soc/cores/jtag.py index eff9144a8..4fae4bfc3 100644 --- a/litex/soc/cores/jtag.py +++ b/litex/soc/cores/jtag.py @@ -448,12 +448,16 @@ def __init__(self, jtag=None, device=None, data_width=8, clock_domain="sys", cha # JTAG clock domain crossing --------------------------------------------------------------- if clock_domain != "jtag": - tx_cdc = stream.AsyncFIFO([("data", data_width)], 4) - tx_cdc = ClockDomainsRenamer({"write": clock_domain, "read": "jtag"})(tx_cdc) - rx_cdc = stream.AsyncFIFO([("data", data_width)], 4) - rx_cdc = ClockDomainsRenamer({"write": "jtag", "read": clock_domain})(rx_cdc) - self.tx_cdc = tx_cdc - self.rx_cdc = rx_cdc + self.tx_cdc = tx_cdc = stream.ClockDomainCrossing([("data", data_width)], + cd_from = clock_domain, + cd_to = "jtag", + with_common_rst = True + ) + self.rx_cdc = rx_cdc = stream.ClockDomainCrossing([("data", data_width)], + cd_from = "jtag", + cd_to = clock_domain, + with_common_rst = True + ) self.comb += [ sink.connect(tx_cdc.sink), rx_cdc.source.connect(source) From 4e57cca85feb4665064cc4bd980963181b98689e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 13 Dec 2023 09:17:15 +0100 Subject: [PATCH 376/454] cpu/vexriscv: Cleanup reset. --- litex/soc/cores/cpu/vexriscv/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/cpu/vexriscv/core.py b/litex/soc/cores/cpu/vexriscv/core.py index 3145a7e95..02a9c4584 100644 --- a/litex/soc/cores/cpu/vexriscv/core.py +++ b/litex/soc/cores/cpu/vexriscv/core.py @@ -220,7 +220,7 @@ def add_debug(self): self.debug_bus = wishbone.Interface(data_width=32, address_width=32, addressing="word") self.sync += self.debug_bus.dat_r.eq(self.o_rsp_data) - self.sync += debug_reset.eq(reset_debug_logic | ResetSignal()) + self.sync += debug_reset.eq(reset_debug_logic) self.sync += [ # CYC is held high for the duration of the transfer. @@ -271,7 +271,7 @@ def add_debug(self): i_reset = ResetSignal("sys") | self.reset | debug_reset, i_iBusWishbone_ERR = self.ibus.err | ibus_err, i_dBusWishbone_ERR = self.dbus.err | dbus_err, - i_debugReset = ResetSignal("sys"), + i_debugReset = ResetSignal("sys") | self.reset, i_debug_bus_cmd_valid = self.i_cmd_valid, i_debug_bus_cmd_payload_wr = self.i_cmd_payload_wr, i_debug_bus_cmd_payload_address = self.i_cmd_payload_address, @@ -320,7 +320,7 @@ def add_cfu(self, cfu_filename): i_rsp_ready = cfu_bus.rsp.ready, o_rsp_payload_outputs_0 = cfu_bus.rsp.payload.outputs_0, i_clk = ClockSignal("sys"), - i_reset = ResetSignal("sys"), + i_reset = ResetSignal("sys") | self.reset, ) self.platform.add_source(cfu_filename) From faae1ea95aa9bc750d498cd02f2bddf18756675f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 13 Dec 2023 09:24:23 +0100 Subject: [PATCH 377/454] integration/soc/jtag: Switch JTAGPHY to sys_clk/simplify. --- litex/soc/integration/soc.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 91b3b0931..17fe98f79 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1440,10 +1440,7 @@ def add_uart(self, name="uart", uart_name="serial", baudrate=115200, fifo_depth= # JTAG UART. elif uart_name in ["jtag_uart"]: from litex.soc.cores.jtag import JTAGPHY - # Run JTAG-UART in sys_jtag clk domain similar to sys clk domain but without sys_rst. - self.cd_sys_jtag = ClockDomain() - self.comb += self.cd_sys_jtag.clk.eq(ClockSignal("sys")) - uart_phy = JTAGPHY(device=self.platform.device, clock_domain="sys_jtag", platform=self.platform) + uart_phy = JTAGPHY(device=self.platform.device, platform=self.platform) uart = UART(uart_phy, **uart_kwargs) # Sim. From 00b94a5512ef3e03a568da59d36302c8352273ef Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 13 Dec 2023 14:29:54 +0100 Subject: [PATCH 378/454] soc/software/bios/boot: serialboot: increase CMD_TIMEOUT_DELAY --- litex/soc/software/bios/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index 5ade1c89c..34079b69d 100755 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -99,7 +99,7 @@ void romboot(void) #ifdef CSR_UART_BASE #define ACK_TIMEOUT_DELAY CONFIG_CLOCK_FREQUENCY/4 -#define CMD_TIMEOUT_DELAY CONFIG_CLOCK_FREQUENCY/16 +#define CMD_TIMEOUT_DELAY CONFIG_CLOCK_FREQUENCY/4 static void timer0_load(unsigned int value) { timer0_en_write(0); From 84e376efcb76a1b22ebf4a290f5fc9bc360a3f19 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 13 Dec 2023 15:08:18 +0100 Subject: [PATCH 379/454] build/openocd: jtagstream_rxtx reduce tx to 16 and rx to 128 --- litex/build/openocd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/build/openocd.py b/litex/build/openocd.py index d0aff8596..2a8f47684 100644 --- a/litex/build/openocd.py +++ b/litex/build/openocd.py @@ -144,8 +144,8 @@ def stream(self, port=20000, chain=1): proc jtagstream_rxtx {tap client is_poll} { if {![$client eof]} { - set tx [$client read 512] - set rx [jtagstream_drain $tap $tx 512 4096] + set tx [$client read 16] + set rx [jtagstream_drain $tap $tx 128 4096] if {[string length $rx]} { #echo [string length $rx] $client puts -nonewline $rx From b6e89c646e108d3aeeaec74536b1ebebd737768e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 14 Dec 2023 11:08:55 +0100 Subject: [PATCH 380/454] CHANGES: Update. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 7ce0bbe08..b537e2812 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -34,6 +34,8 @@ - liteiclink/phy : Added Efinix support/examples on Trion/Titanium. - liteiclink/serwb : Reused Etherbone from LiteEth to avoid code duplication. - interconnect : Added 64-bit support to Wishbone/AXI-Lite/AXI. + - jtag : Fixed firmware upload over JTAG-UART. + - jtag : Improved speed (~X16) on JTABone/JTAGUART on all supported devices (Xilinx, Altera, Efinix, etc...) [> Changed ---------- From 2318ff37d2023fa32844873fdc6525f7abd55e44 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 19 Dec 2023 10:08:40 +0100 Subject: [PATCH 381/454] setup.py: Improve indentation. --- setup.py | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/setup.py b/setup.py index 08af7085f..0a0f7a601 100755 --- a/setup.py +++ b/setup.py @@ -9,25 +9,25 @@ setup( - name="litex", - version="2023.08", - description="Python SoC/Core builder for building FPGA based systems.", - long_description=long_description, - long_description_content_type="text/markdown", - author="Florent Kermarrec", - author_email="florent@enjoy-digital.fr", - url="http://enjoy-digital.fr", - download_url="https://github.com/enjoy-digital/litex", - test_suite="test", - license="BSD", - python_requires="~=3.6", - install_requires=[ + name = "litex", + version = "2023.08", + description = "Python SoC/Core builder for building FPGA based systems.", + long_description = long_description, + long_description_content_type = "text/markdown", + author = "Florent Kermarrec", + author_email = "florent@enjoy-digital.fr", + url = "http://enjoy-digital.fr", + download_url = "https://github.com/enjoy-digital/litex", + test_suite = "test", + license = "BSD", + python_requires = "~=3.6", + install_requires = [ "migen", "packaging", "pyserial", "requests", ], - extras_require={ + extras_require = { "develop": [ "meson" "pexpect" @@ -35,23 +35,23 @@ "requests" ] }, - packages=find_packages(exclude=("test*", "sim*", "doc*")), - include_package_data=True, - package_data={ + packages = find_packages(exclude=("test*", "sim*", "doc*")), + include_package_data = True, + package_data = { 'litex.soc.doc': ['static/*'] }, - platforms=["Any"], - keywords="HDL ASIC FPGA hardware design", - classifiers=[ - "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", - "Environment :: Console", - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", + platforms = ["Any"], + keywords = "HDL ASIC FPGA hardware design", + classifiers = [ + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", + "Environment :: Console", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", "Programming Language :: Python", ], - entry_points={ + entry_points = { "console_scripts": [ # Terminal/Server/Client. "litex_term = litex.tools.litex_term:main", From 0c3cda3ee823ef0877d2ccf3f48a6eb8e200376d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 19 Dec 2023 10:09:44 +0100 Subject: [PATCH 382/454] CHANGES.md: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index b537e2812..61d175b20 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -36,6 +36,7 @@ - interconnect : Added 64-bit support to Wishbone/AXI-Lite/AXI. - jtag : Fixed firmware upload over JTAG-UART. - jtag : Improved speed (~X16) on JTABone/JTAGUART on all supported devices (Xilinx, Altera, Efinix, etc...) + - litesata/phy : Added GTHE4 support on Ultrascale+. [> Changed ---------- From 33c07a094e7bf257dc34f230c4e9667ea0da0275 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 19 Dec 2023 10:16:15 +0100 Subject: [PATCH 383/454] setup.py: Specify UTF-8 encoding for long_description/README.md. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0a0f7a601..696177dc5 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import find_packages -with open("README.md", "r") as fp: +with open("README.md", "r", encoding="utf-8") as fp: long_description = fp.read() From 048c42820c8b934d5dc60660eab075de009d8d4d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 19 Dec 2023 10:32:12 +0100 Subject: [PATCH 384/454] setup.py: Switch minimum Python version to 3.7 (To allow more than 255 arguments in functions). --- CHANGES.md | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 61d175b20..82b322eae 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -40,7 +40,8 @@ [> Changed ---------- - - build/osfpga: Removed initial support (would need feedbacks/updates). + - build/osfpga : Removed initial support (would need feedbacks/updates). + - python3 : Updated minimum python3 version to 3.7 (To allow more than 255 arguments in functions). [> 2023.08, released on September 14th 2023 ------------------------------------------- diff --git a/setup.py b/setup.py index 696177dc5..c1d57adea 100755 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ download_url = "https://github.com/enjoy-digital/litex", test_suite = "test", license = "BSD", - python_requires = "~=3.6", + python_requires = "~=3.7", install_requires = [ "migen", "packaging", From cd503bc9af28e92116b17f0ace49756ae5d4e984 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Tue, 19 Dec 2023 21:25:59 +0100 Subject: [PATCH 385/454] build/efinix/ifacewriter: Titanium PLL's feedback clock --- litex/build/efinix/ifacewriter.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index be480cb26..325e49d55 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -281,7 +281,6 @@ def generate_pll(self, block, partnumber, verbose=True): if block["version"] == "V3": cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_src="EXTERNAL", refclk_name="{}", ext_refclk_no="{}", ext_refclk_type="LVDS_RX")\n\n' \ .format(name, block["resource"], block["input_clock_pad"], block["clock_no"]) - cmd += 'design.set_property("{}","FEEDBACK_MODE","CORE","PLL")\n\n'.format(name) else: cmd += 'design.set_property("{}","EXT_CLK","EXT_CLK{}","PLL")\n'.format(name, block["clock_no"]) @@ -329,7 +328,14 @@ def generate_pll(self, block, partnumber, verbose=True): else: cmd += 'design.set_property("{}","CLKOUT{}_PHASE_SETTING","{}","PLL")\n'.format(name, i, clock[2] // 45) - if block["feedback"] == -1: + # Titanium has always a feedback (local: CLK0, CORE: any output) + if block["version"] == "V3": + feedback_clk = block["feedback"] + cmd += 'design.set_property("{}", "FEEDBACK_MODE", "{}", "PLL")\n'.format(name, "LOCAL" if feedback_clk < 1 else "CORE") + cmd += 'design.set_property("{}", "FEEDBACK_CLK", "CLK{}", "PLL")\n'.format(name, 0 if feedback_clk < 1 else feedback_clk) + + # auto_calc_pll_clock is always working with Titanium and only working when feedback is unused for Trion + if block["feedback"] == -1 or block["version"] == "V3": cmd += "target_freq = {\n" for i, clock in enumerate(block["clk_out"]): cmd += ' "CLKOUT{}_FREQ": "{}",\n'.format(i, clock[1] / 1e6) @@ -358,7 +364,7 @@ def generate_pll(self, block, partnumber, verbose=True): cmd += 'print("#### {} ####")\n'.format(name) cmd += 'clksrc_info = design.trace_ref_clock("{}", block_type="PLL")\n'.format(name) cmd += 'pprint.pprint(clksrc_info)\n' - cmd += 'clock_source_prop = ["REFCLK_SOURCE", "CORE_CLK_PIN", "EXT_CLK", "REFCLK_FREQ", "RESOURCE"]\n' + cmd += 'clock_source_prop = ["REFCLK_SOURCE", "CORE_CLK_PIN", "EXT_CLK", "REFCLK_FREQ", "RESOURCE", "FEEDBACK_MODE", "FEEDBACK_CLK"]\n' for i, clock in enumerate(block["clk_out"]): cmd += 'clock_source_prop += ["CLKOUT{}_FREQ", "CLKOUT{}_PHASE", "CLKOUT{}_EN"]\n'.format(i, i, i) cmd += 'prop_map = design.get_property("{}", clock_source_prop, block_type="PLL")\n'.format(name) From fadea1d31bc7dc3cf5cf6030f44ee6ec61491976 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 20 Dec 2023 08:08:42 +0100 Subject: [PATCH 386/454] CHANGES.md: Update. --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 82b322eae..2b0affab0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,7 +30,7 @@ - litepcie : Simplify/Cleanup Ultrascale(+) integration and allow .xci generation from .tcl. - litepcie : Initial 64-bit DMA suppport. - bios : Added bios_format / --bios-format to allow enabling float/double printf. - - soc/cores/clock : Added proper clock feedback support on Efinix TRIONPLL. + - soc/cores/clock : Added proper clock feedback support on Efinix TRIONPLL/TITANIUMPLL. - liteiclink/phy : Added Efinix support/examples on Trion/Titanium. - liteiclink/serwb : Reused Etherbone from LiteEth to avoid code duplication. - interconnect : Added 64-bit support to Wishbone/AXI-Lite/AXI. From 4721029e58311cb9eaee72a2f5861f34f157c03a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 20 Dec 2023 15:25:14 +0100 Subject: [PATCH 387/454] CHANGES.md: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 2b0affab0..6d76c8bca 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,6 +37,7 @@ - jtag : Fixed firmware upload over JTAG-UART. - jtag : Improved speed (~X16) on JTABone/JTAGUART on all supported devices (Xilinx, Altera, Efinix, etc...) - litesata/phy : Added GTHE4 support on Ultrascale+. + - litex_boards : Added Machdyne's Mozart with the Sechzig ML1 module support. [> Changed ---------- From 23fbd1b334b715b92464687696c0a9cd7e730427 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 20 Dec 2023 16:10:03 +0100 Subject: [PATCH 388/454] CHANGES.md: Update. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 6d76c8bca..b20791b09 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -38,6 +38,7 @@ - jtag : Improved speed (~X16) on JTABone/JTAGUART on all supported devices (Xilinx, Altera, Efinix, etc...) - litesata/phy : Added GTHE4 support on Ultrascale+. - litex_boards : Added Machdyne's Mozart with the Sechzig ML1 module support. + - liteiclink : Added clk_ratio of 1:2, 1:4 on Efinix/SerWB to allow make clocking more flexible. [> Changed ---------- From 040b5540220889affb3b0d8482a4754322db3b51 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 20 Dec 2023 16:11:12 +0100 Subject: [PATCH 389/454] CHANGES.md: Update. --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index b20791b09..764da9aec 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -38,7 +38,7 @@ - jtag : Improved speed (~X16) on JTABone/JTAGUART on all supported devices (Xilinx, Altera, Efinix, etc...) - litesata/phy : Added GTHE4 support on Ultrascale+. - litex_boards : Added Machdyne's Mozart with the Sechzig ML1 module support. - - liteiclink : Added clk_ratio of 1:2, 1:4 on Efinix/SerWB to allow make clocking more flexible. + - liteiclink : Added clk_ratio of 1:2, 1:4 on Efinix/SerWB to make clocking more flexible. [> Changed ---------- From 7d5de90a247be3a32cba56178b81f5246d5e4410 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 20 Dec 2023 20:28:51 +0100 Subject: [PATCH 390/454] soc/cores/clock/efinix: remove 2 output clocks limit, reset o_div_max when a nex vco_max_freq is found --- litex/soc/cores/clock/efinix.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index ba803c741..d71197107 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -240,23 +240,24 @@ def compute_config(self): # no solution found for this clk: params are uncompatibles if found == False: break - if len(cx_list) == 2: - params_list.append([n, m, o, c, cx_list[0], cx_list[1]]) + if len(cx_list) == n_out: + params_list.append([n, m, o, c, cx_list]) vco_max_freq = 0 o_div_max = 0 params_list2 = [] for p in params_list: - (n, m, o, c, c0, c1) = p + (n, m, o, c, cx_list) = p fpfd_tmp = clk_in_freq / n fvco_tmp = fpfd_tmp * m * o * c - if o > o_div_max: - o_div_max = o # Interface designer always select high VCO freq if fvco_tmp > vco_max_freq: vco_max_freq = fvco_tmp params_list2.clear() + o_div_max = 0 fpll_tmp = fvco_tmp / o if fvco_tmp == vco_max_freq: + if o > o_div_max: + o_div_max = o params_list2.append({ "fvco" : fvco_tmp, "fpll" : fpll_tmp, @@ -265,8 +266,7 @@ def compute_config(self): "N" : n, "O" : o, "Cfbk" : c, - "c0" : c0, - "c1" : c1, + **{f"c{n}" : cx_list[n] for n in range(n_out)}, }) # Again: Interface Designer prefers high O divider. From 54c58ef8b9caa6b8c1a6ad9710793b9bec804994 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 20 Dec 2023 20:29:10 +0100 Subject: [PATCH 391/454] build/efinix/ifacewriter: reorder FEEDBACK for Trion devices. --- litex/build/efinix/ifacewriter.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index 325e49d55..dbeedc088 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -284,11 +284,6 @@ def generate_pll(self, block, partnumber, verbose=True): else: cmd += 'design.set_property("{}","EXT_CLK","EXT_CLK{}","PLL")\n'.format(name, block["clock_no"]) - if block["feedback"] != -1: - cmd += 'design.set_property("{}","FEEDBACK_MODE","{}","PLL")\n'.format(name, "CORE" if block["feedback"] == 0 else "LOCAL") - cmd += 'design.set_property("{}","FEEDBACK_CLK","CLK{}","PLL")\n'.format(name, block["feedback"]) - else: - cmd += 'design.set_property("{}","FEEDBACK_MODE","INTERNAL","PLL")\n'.format(name) cmd += 'design.assign_resource("{}","{}","PLL")\n'.format(name, block["resource"]) @@ -344,6 +339,9 @@ def generate_pll(self, block, partnumber, verbose=True): cmd += ' "CLKOUT{}_DYNPHASE_EN": "1",\n'.format(i) cmd += "}\n" + if block["version"] == "V1_V2": + cmd += 'design.set_property("{}","FEEDBACK_MODE","INTERNAL","PLL")\n'.format(name) + cmd += 'calc_result = design.auto_calc_pll_clock("{}", target_freq)\n'.format(name) cmd += 'for c in calc_result:\n' cmd += ' print(c)\n' @@ -355,6 +353,8 @@ def generate_pll(self, block, partnumber, verbose=True): cmd += 'design.set_property("{}","CLKOUT{}_PHASE","{}","PLL")\n'.format(name, i, clock[2]) #cmd += 'design.set_property("{}","CLKOUT{}_FREQ","{}","PLL")\n'.format(name, i, clock[2]) cmd += 'design.set_property("{}","CLKOUT{}_DIV","{}","PLL")\n'.format(name, i, block[f"CLKOUT{i}_DIV"]) + cmd += 'design.set_property("{}","FEEDBACK_MODE","{}","PLL")\n'.format(name, "LOCAL" if block["feedback"] == 0 else "CORE") + cmd += 'design.set_property("{}","FEEDBACK_CLK","CLK{}","PLL")\n'.format(name, block["feedback"]) if "extra" in block: cmd += block["extra"] From 7062e3379fdd80ac0523390ca46c87906b8c68ff Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 20 Dec 2023 20:33:15 +0100 Subject: [PATCH 392/454] build/efinix/ifacewriter: bypass clks out frequency check for Trion when a feedback clock is used --- litex/build/efinix/ifacewriter.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index dbeedc088..5ec2a3b88 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -370,11 +370,13 @@ def generate_pll(self, block, partnumber, verbose=True): cmd += 'prop_map = design.get_property("{}", clock_source_prop, block_type="PLL")\n'.format(name) cmd += 'pprint.pprint(prop_map)\n' - for i, clock in enumerate(block["clk_out"]): - cmd += '\nfreq = float(prop_map["CLKOUT{}_FREQ"])\n'.format(i) - cmd += 'if freq != {}:\n'.format(clock[1]/1e6) - cmd += ' print("ERROR: CLKOUT{} configured for {}MHz is {{}}MHz".format(freq))\n'.format(i, clock[1]/1e6) - cmd += ' exit("PLL ERROR")\n' + # Efinix python API is buggy for Trion devices when a feedback is defined... + if block["version"] == "V3" or (block["version"] == "V1_V2" and block["feedback"] == -1): + for i, clock in enumerate(block["clk_out"]): + cmd += '\nfreq = float(prop_map["CLKOUT{}_FREQ"])\n'.format(i) + cmd += 'if freq != {}:\n'.format(clock[1]/1e6) + cmd += ' print("ERROR: CLKOUT{} configured for {}MHz is {{}}MHz".format(freq))\n'.format(i, clock[1]/1e6) + cmd += ' exit("PLL ERROR")\n' cmd += "\n#---------- END PLL {} ---------\n\n".format(name) return cmd From 67cfcadf7933ec6a6e75735e340c153fe4ca8480 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 25 Dec 2023 15:36:10 +0100 Subject: [PATCH 393/454] setup.py/CHANGES.md: Prepare 2023.12 release. --- CHANGES.md | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 764da9aec..2d1d09728 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,5 @@ -[> Changes since 2023.08 ------------------------- +[> 2023.12, released on December 25th 2023 +------------------------------------------ [> Fixed -------- - liteeth/arp : Fixed response on table update. diff --git a/setup.py b/setup.py index c1d57adea..ab33e6b9a 100755 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ setup( name = "litex", - version = "2023.08", + version = "2023.12", description = "Python SoC/Core builder for building FPGA based systems.", long_description = long_description, long_description_content_type = "text/markdown", From 68cfb6eea04a8296f6ac38d6b2c94ca77dd15d42 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Thu, 28 Dec 2023 15:49:31 -0500 Subject: [PATCH 394/454] Fix classifiers to satisfy format checks --- setup.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index ab33e6b9a..a52575a62 100755 --- a/setup.py +++ b/setup.py @@ -43,12 +43,12 @@ platforms = ["Any"], keywords = "HDL ASIC FPGA hardware design", classifiers = [ - "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", - "Environment :: Console", - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", + "Environment :: Console", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", "Programming Language :: Python", ], entry_points = { From acf07a21c96cd2fc10dd53151af4a645e42c44bb Mon Sep 17 00:00:00 2001 From: gsomlo Date: Mon, 1 Jan 2024 13:32:40 -0500 Subject: [PATCH 395/454] soc: fix typo in cpu mem_bus axi-via-wb downconvert (#1865) Fixes: 002aad7a4 Signed-off-by: Gabriel Somlo --- litex/soc/integration/soc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 17fe98f79..dbce3a988 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1651,9 +1651,9 @@ def add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None, else: mem_wb = wishbone.Interface( data_width = self.cpu.mem_axi.data_width, - adr_width = 32-log2_int(mem_bus.data_width//8, + adr_width = 32-log2_int(mem_bus.data_width//8), addressing = "word", - )) + ) mem_a2w = axi.AXI2Wishbone( axi = mem_bus, wishbone = mem_wb, From 3909b1d6117231d420ddeeab12567c96ba5cec79 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 2 Jan 2024 13:43:48 +0100 Subject: [PATCH 396/454] build/openfpgaloader: Add kwargs support to flash method and some comments. --- litex/build/openfpgaloader.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index c6f38ae38..8721dcfb9 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -13,31 +13,62 @@ class OpenFPGALoader(GenericProgrammer): needs_bitreverse = False def __init__(self, board="", cable="", freq=0, fpga_part="", index_chain=None): + # openFPGALoader base command. self.cmd = ["openFPGALoader"] + + # Specify FPGA board. if board: self.cmd += ["--board", board] + + # Specify FPGA part/device. if fpga_part: self.cmd += ["--fpga-part", fpga_part] + + # Specify programmation cable. if cable: self.cmd += ["--cable", cable] + + # Specify programmation frequency. if freq: self.cmd += ["--freq", str(int(float(freq)))] + + # Specify index in the JTAG chain. if index_chain is not None: self.cmd += ["--index-chain", str(int(index_chain))] def load_bitstream(self, bitstream_file): + # Load base command. cmd = self.cmd + ["--bitstream", bitstream_file] + + # Execute command. self.call(cmd) - def flash(self, address, data_file, external=False, unprotect_flash=False, verify=False): + def flash(self, address, data_file, external=False, unprotect_flash=False, verify=False, **kwargs): + # Flash base command. cmd = self.cmd + ["--write-flash", "--bitstream", data_file] + + # Flash Internal/External selection. if external: cmd += ["--external-flash"] + + # Flash Offset. if address: cmd += ["--offset"] cmd += [str(address)] + + # Flash Unprotect. if unprotect_flash: cmd += ["--unprotect-flash"] + + # Flash Verify. if verify: cmd += ["--verify"] + + # Handle kwargs for specific, less common cases. + for key, value in kwargs.items(): + cmd.append(f"--{key}") + if value is not None: + cmd.append(str(value)) + + # Execute Command. self.call(cmd) From 456dda050cbf0eb8417670a2912c0487d27beb75 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jan 2024 19:07:55 +0100 Subject: [PATCH 397/454] cpu/gowin_emcu: Cleanup/Simplify. --- litex/soc/cores/cpu/gowin_emcu/core.py | 144 +++++++++++++------------ 1 file changed, 76 insertions(+), 68 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index c8551b21c..dddf86e23 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -2,6 +2,7 @@ # This file is part of LiteX. # # Copyright (c) 2021 Ilia Sergachev +# Copyright (c) 2024 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause from migen import * @@ -11,42 +12,6 @@ from litex.soc.interconnect import wishbone, ahb from litex.soc.cores.cpu import CPU -# AHB Flash ---------------------------------------------------------------------------------------- - -class AHBFlash(LiteXModule): - def __init__(self, bus): - addr = Signal(13) - read = Signal() - self.comb += bus.resp.eq(0) - - self.fsm = fsm = FSM() - fsm.act("IDLE", - bus.readyout.eq(1), - If(bus.sel & bus.trans[1], - NextValue(addr, bus.addr[2:]), - NextState("READ"), - ) - ) - fsm.act("READ", - read.eq(1), - NextState("WAIT"), - ) - fsm.act("WAIT", - NextState("IDLE") - ) - self.specials += Instance("FLASH256K", - o_DOUT = bus.rdata, - i_DIN = Signal(32), - i_XADR = addr[6:], - i_YADR = addr[:6], - i_XE = ~ResetSignal("sys"), - i_YE = ~ResetSignal("sys"), - i_SE = read, - i_PROG = 0, - i_ERASE = 0, - i_NVSTR = 0 - ) - # Gowin EMCU --------------------------------------------------------------------------------------- class GowinEMCU(CPU): @@ -64,7 +29,7 @@ class GowinEMCU(CPU): io_regions = { # Origin, Length. 0x4000_0000: 0x2000_0000, - 0xA000_0000: 0x6000_0000 + 0xa000_0000: 0x6000_0000 } @property @@ -78,45 +43,50 @@ def mem_map(self): def __init__(self, platform, variant, *args, **kwargs): super().__init__(*args, **kwargs) - - self.reset = Signal() - self.bus_reset = Signal() - bus_reset_n = Signal() - self.comb += self.bus_reset.eq(~bus_reset_n) + self.reset = Signal() self.interrupt = Signal(5) self.reset_address = self.mem_map["rom"] + 0 + self.periph_buses = [] - self.gpio_in = Signal(16) - self.gpio_out = Signal(16) - self.gpio_out_en = Signal(16) + # CPU Instance. + # ------------- + bus_reset_n = Signal() self.cpu_params = dict() self.cpu_params.update( - i_MTXREMAP = Signal(4, reset=0b1111), - o_MTXHRESETN = bus_reset_n, - - i_FLASHERR = Signal(), - i_FLASHINT = Signal(), - + # Clk/Rst. i_FCLK = ClockSignal("sys"), i_PORESETN = ~self.reset, i_SYSRESETN = ~self.reset, - i_RTCSRCCLK = Signal(), # TODO - RTC clk in + i_MTXREMAP = Signal(4, reset=0b1111), + o_MTXHRESETN = bus_reset_n, + + # RTC. + i_RTCSRCCLK = Signal(), # TODO: RTC Clk In. - i_IOEXPINPUTI = self.gpio_in, - o_IOEXPOUTPUTO = self.gpio_out, - o_IOEXPOUTPUTENO = self.gpio_out_en, + # GPIOs. + i_IOEXPINPUTI = Signal(), # TODO: GPIO Input (16-bit). + o_IOEXPOUTPUTO = Signal(), # TODO: GPIO Output (16-bit). + o_IOEXPOUTPUTENO = Signal(), # TODO: GPIO Output Enable (16-bit). + # Interrupts. i_GPINT = self.interrupt, o_INTMONITOR = Signal(), + + # Flash. + i_FLASHERR = Signal(), + i_FLASHINT = Signal(), ) - # 32b CPU SRAM split between 8 SRAMs x 4 bit each + # SRAM (32-bit RAM split between 8 SRAMs x 4 bit each). + # ----------------------------------------------------- + # Parameters. sram_dw = 32 single_sram_dw = 4 - n_srams = sram_dw // single_sram_dw + nsrams = sram_dw // single_sram_dw + # CPU SRAM Interface. sram0_addr = Signal(13) sram0_rdata = Signal(sram_dw) sram0_wdata = Signal(sram_dw) @@ -130,7 +100,8 @@ def __init__(self, platform, variant, *args, **kwargs): o_SRAM0CS = sram0_cs, ) - for i in range(n_srams): + # SRAMS Instances. + for i in range(nsrams): self.specials += Instance("SDPB", p_READ_MODE = 0, p_BIT_WIDTH_0 = single_sram_dw, @@ -144,16 +115,51 @@ def __init__(self, platform, variant, *args, **kwargs): i_ADB = Cat(Signal(2), sram0_addr[:-1]), i_CEA = sram0_wren[i // 2], i_CEB = ~sram0_wren[i // 2], - i_CLKA = ClockSignal(), - i_CLKB = ClockSignal(), + i_CLKA = ClockSignal("sys"), + i_CLKB = ClockSignal("sys"), i_RESETA = 0, - i_RESETB = self.bus_reset, + i_RESETB = ~bus_reset_n, i_OCE = 1, i_BLKSELA = Cat(sram0_cs, sram0_cs, sram0_cs), i_BLKSELB = Cat(sram0_cs, sram0_cs, sram0_cs), ) - # Boot Flash memory connected via AHB + # Flash (Boot Flash memory connected via AHB). + # -------------------------------------------- + + class AHBFlash(LiteXModule): + def __init__(self, bus): + addr = Signal(13) + read = Signal() + self.comb += bus.resp.eq(0) + + self.fsm = fsm = FSM() + fsm.act("IDLE", + bus.readyout.eq(1), + If(bus.sel & bus.trans[1], + NextValue(addr, bus.addr[2:]), + NextState("READ"), + ) + ) + fsm.act("READ", + read.eq(1), + NextState("WAIT"), + ) + fsm.act("WAIT", + NextState("IDLE") + ) + self.specials += Instance("FLASH256K", + o_DOUT = bus.rdata, + i_DIN = Signal(32), + i_XADR = addr[6:], + i_YADR = addr[:6], + i_XE = ~ResetSignal("sys"), + i_YE = ~ResetSignal("sys"), + i_SE = read, + i_PROG = 0, + i_ERASE = 0, + i_NVSTR = 0 + ) ahb_flash = ahb.Interface() for s, _ in ahb_flash.master_signals: @@ -163,26 +169,28 @@ def __init__(self, platform, variant, *args, **kwargs): for s, _ in ahb_flash.slave_signals: self.cpu_params[f"i_TARGFLASH0H{s.upper()}"] = getattr(ahb_flash, s) flash = ResetInserter()(AHBFlash(ahb_flash)) - self.comb += flash.reset.eq(self.bus_reset) + self.comb += flash.reset.eq(~bus_reset_n) self.submodules += flash - # Extension AHB -> Wishbone CSR via bridge + + # Peripheral Bus (AHB -> Wishbone). + # --------------------------------- self.pbus = wishbone.Interface(data_width=32, adr_width=30, addressing="word") - self.periph_buses = [self.pbus] ahb_targexp0 = ahb.Interface() for s, _ in ahb_targexp0.master_signals: self.cpu_params[f"o_TARGEXP0H{s.upper()}"] = getattr(ahb_targexp0, s) for s, _ in ahb_targexp0.slave_signals: self.cpu_params[f"i_TARGEXP0H{s.upper()}"] = getattr(ahb_targexp0, s) self.submodules += ahb.AHB2Wishbone(ahb_targexp0, self.pbus) + self.periph_buses.append(self.pbus) def connect_uart(self, pads, n=0): assert n in (0, 1), "this CPU has 2 built-in UARTs, 0 and 1" self.cpu_params.update({ - f"i_UART{n}RXDI": pads.rx, - f"o_UART{n}TXDO": pads.tx, - f"o_UART{n}BAUDTICK": Signal() + f"i_UART{n}RXDI" : pads.rx, + f"o_UART{n}TXDO" : pads.tx, + f"o_UART{n}BAUDTICK" : Signal() }) def connect_jtag(self, pads): From 3f9de470f6d647ef6c6f821293ce4152cdaca6b7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jan 2024 19:15:46 +0100 Subject: [PATCH 398/454] cpu/gowin_emcu: Add gcc_flags method and set UART_POLLING in it. --- litex/soc/cores/cpu/gowin_emcu/core.py | 9 ++++++++- litex/soc/cores/cpu/gowin_emcu/system.h | 1 - 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index dddf86e23..5046f01a2 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -23,7 +23,6 @@ class GowinEMCU(CPU): data_width = 32 endianness = "little" gcc_triple = "arm-none-eabi" - gcc_flags = "-mcpu=cortex-m3 -mthumb" linker_output_format = "elf32-littlearm" nop = "nop" io_regions = { @@ -32,6 +31,7 @@ class GowinEMCU(CPU): 0xa000_0000: 0x6000_0000 } + # Memory Mapping. @property def mem_map(self): return { @@ -41,6 +41,13 @@ def mem_map(self): "csr" : 0xa000_0000, } + # GCC Flags. + @property + def gcc_flags(self): + flags = f" -mcpu=cortex-m3 -mthumb" + flags += f" -DUART_POLLING" + return flags + def __init__(self, platform, variant, *args, **kwargs): super().__init__(*args, **kwargs) self.reset = Signal() diff --git a/litex/soc/cores/cpu/gowin_emcu/system.h b/litex/soc/cores/cpu/gowin_emcu/system.h index 2fc3a77d1..1e0b33aab 100644 --- a/litex/soc/cores/cpu/gowin_emcu/system.h +++ b/litex/soc/cores/cpu/gowin_emcu/system.h @@ -16,7 +16,6 @@ void busy_wait_us(unsigned int us); // FIXME #define CSR_UART_BASE -#define UART_POLLING struct EMCU_UART { From 85ef3bd8a79a2d5186e923361a3a237d0d507288 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jan 2024 19:41:03 +0100 Subject: [PATCH 399/454] cpu/gowin_emcu: Add missing reset signals. --- litex/soc/cores/cpu/gowin_emcu/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 5046f01a2..4a9dcdb6f 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -63,8 +63,8 @@ def __init__(self, platform, variant, *args, **kwargs): self.cpu_params.update( # Clk/Rst. i_FCLK = ClockSignal("sys"), - i_PORESETN = ~self.reset, - i_SYSRESETN = ~self.reset, + i_PORESETN = ~ResetSignal("sys") & ~self.reset, + i_SYSRESETN = ~ResetSignal("sys") & ~self.reset, i_MTXREMAP = Signal(4, reset=0b1111), o_MTXHRESETN = bus_reset_n, @@ -124,7 +124,7 @@ def __init__(self, platform, variant, *args, **kwargs): i_CEB = ~sram0_wren[i // 2], i_CLKA = ClockSignal("sys"), i_CLKB = ClockSignal("sys"), - i_RESETA = 0, + i_RESETA = ~bus_reset_n, i_RESETB = ~bus_reset_n, i_OCE = 1, i_BLKSELA = Cat(sram0_cs, sram0_cs, sram0_cs), From 6d3c955d59e564a8fcac281da8a5cc5bd5f419b3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 08:57:25 +0100 Subject: [PATCH 400/454] cpu/gowin_emcu: Increase similarities with cortex_m3 (since gowin_emcu is a Cortex M3). --- litex/soc/cores/cpu/cortex_m3/core.py | 2 -- litex/soc/cores/cpu/gowin_emcu/core.py | 34 ++++++++++++------------- litex/soc/cores/cpu/gowin_emcu/system.h | 4 +-- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/litex/soc/cores/cpu/cortex_m3/core.py b/litex/soc/cores/cpu/cortex_m3/core.py index b2a852afc..c1f88908a 100644 --- a/litex/soc/cores/cpu/cortex_m3/core.py +++ b/litex/soc/cores/cpu/cortex_m3/core.py @@ -5,8 +5,6 @@ # Copyright (c) 2022 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause -import os - from migen import * from litex.gen import * diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 4a9dcdb6f..0494befc7 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -9,8 +9,8 @@ from litex.gen import * -from litex.soc.interconnect import wishbone, ahb from litex.soc.cores.cpu import CPU +from litex.soc.interconnect import wishbone, ahb # Gowin EMCU --------------------------------------------------------------------------------------- @@ -22,38 +22,41 @@ class GowinEMCU(CPU): human_name = "Gowin EMCU" data_width = 32 endianness = "little" + reset_address = 0x0000_0000 gcc_triple = "arm-none-eabi" linker_output_format = "elf32-littlearm" nop = "nop" io_regions = { # Origin, Length. - 0x4000_0000: 0x2000_0000, - 0xa000_0000: 0x6000_0000 + 0x4000_0000 : 0x2000_0000, + 0xa000_0000 : 0x6000_0000, } # Memory Mapping. @property def mem_map(self): return { - "rom" : 0x0000_0000, - "sram" : 0x2000_0000, - "peripherals" : 0x4000_0000, - "csr" : 0xa000_0000, + "rom" : 0x0000_0000, + "sram" : 0x2000_0000, + "main_ram" : 0x1000_0000, + "csr" : 0xa000_0000, } # GCC Flags. @property def gcc_flags(self): - flags = f" -mcpu=cortex-m3 -mthumb" + flags = f" -march=armv7-m -mthumb" + flags += f" -D__CortexM3__" flags += f" -DUART_POLLING" return flags - def __init__(self, platform, variant, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, platform, variant="standard"): + self.platform = platform self.reset = Signal() self.interrupt = Signal(5) - self.reset_address = self.mem_map["rom"] + 0 - self.periph_buses = [] + self.pbus = wishbone.Interface(data_width=32, adr_width=30, addressing="word") + self.periph_buses = [self.pbus] + self.memory_buses = [] # CPU Instance. # ------------- @@ -63,8 +66,8 @@ def __init__(self, platform, variant, *args, **kwargs): self.cpu_params.update( # Clk/Rst. i_FCLK = ClockSignal("sys"), - i_PORESETN = ~ResetSignal("sys") & ~self.reset, - i_SYSRESETN = ~ResetSignal("sys") & ~self.reset, + i_PORESETN = ~ (ResetSignal("sys") | self.reset), + i_SYSRESETN = ~ (ResetSignal("sys") | self.reset), i_MTXREMAP = Signal(4, reset=0b1111), o_MTXHRESETN = bus_reset_n, @@ -182,15 +185,12 @@ def __init__(self, bus): # Peripheral Bus (AHB -> Wishbone). # --------------------------------- - - self.pbus = wishbone.Interface(data_width=32, adr_width=30, addressing="word") ahb_targexp0 = ahb.Interface() for s, _ in ahb_targexp0.master_signals: self.cpu_params[f"o_TARGEXP0H{s.upper()}"] = getattr(ahb_targexp0, s) for s, _ in ahb_targexp0.slave_signals: self.cpu_params[f"i_TARGEXP0H{s.upper()}"] = getattr(ahb_targexp0, s) self.submodules += ahb.AHB2Wishbone(ahb_targexp0, self.pbus) - self.periph_buses.append(self.pbus) def connect_uart(self, pads, n=0): assert n in (0, 1), "this CPU has 2 built-in UARTs, 0 and 1" diff --git a/litex/soc/cores/cpu/gowin_emcu/system.h b/litex/soc/cores/cpu/gowin_emcu/system.h index 1e0b33aab..c7a14e816 100644 --- a/litex/soc/cores/cpu/gowin_emcu/system.h +++ b/litex/soc/cores/cpu/gowin_emcu/system.h @@ -5,8 +5,8 @@ extern "C" { #endif -__attribute__((unused)) static void flush_cpu_icache(void){}; -__attribute__((unused)) static void flush_cpu_dcache(void){}; +__attribute__((unused)) static void flush_cpu_icache(void){}; /* No instruction cache */ +__attribute__((unused)) static void flush_cpu_dcache(void){}; /* No instruction cache */ void flush_l2_cache(void); void busy_wait(unsigned int ms); From 01520cd63895eb91a3234d374a50c2c57809dfef Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 09:51:17 +0100 Subject: [PATCH 401/454] cpu/gowin_emcu: Simplify SRAM. --- litex/soc/cores/cpu/gowin_emcu/core.py | 36 ++++++++++---------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 0494befc7..c2beb920a 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -62,8 +62,7 @@ def __init__(self, platform, variant="standard"): # ------------- bus_reset_n = Signal() - self.cpu_params = dict() - self.cpu_params.update( + self.cpu_params = dict( # Clk/Rst. i_FCLK = ClockSignal("sys"), i_PORESETN = ~ (ResetSignal("sys") | self.reset), @@ -88,18 +87,13 @@ def __init__(self, platform, variant="standard"): i_FLASHINT = Signal(), ) - # SRAM (32-bit RAM split between 8 SRAMs x 4 bit each). + # SRAM (32-bit RAM split between 8 SRAMs x 4-bit each). # ----------------------------------------------------- - # Parameters. - sram_dw = 32 - single_sram_dw = 4 - nsrams = sram_dw // single_sram_dw - # CPU SRAM Interface. sram0_addr = Signal(13) - sram0_rdata = Signal(sram_dw) - sram0_wdata = Signal(sram_dw) + sram0_rdata = Signal(32) + sram0_wdata = Signal(32) sram0_cs = Signal() sram0_wren = Signal(4) self.cpu_params.update( @@ -111,27 +105,23 @@ def __init__(self, platform, variant="standard"): ) # SRAMS Instances. - for i in range(nsrams): + for i in range(8): self.specials += Instance("SDPB", p_READ_MODE = 0, - p_BIT_WIDTH_0 = single_sram_dw, - p_BIT_WIDTH_1 = single_sram_dw, + p_BIT_WIDTH_0 = 4, + p_BIT_WIDTH_1 = 4, p_RESET_MODE = "SYNC", - p_BLK_SEL_0 = 0b111, - p_BLK_SEL_1 = 0b111, - o_DO = Cat(sram0_rdata[i * single_sram_dw: (i + 1) * single_sram_dw], Signal(sram_dw - single_sram_dw)), - i_DI = Cat(sram0_wdata[i * single_sram_dw: (i + 1) * single_sram_dw], Signal(sram_dw - single_sram_dw)), - i_ADA = Cat(Signal(2), sram0_addr[:-1]), - i_ADB = Cat(Signal(2), sram0_addr[:-1]), - i_CEA = sram0_wren[i // 2], - i_CEB = ~sram0_wren[i // 2], + o_DO = sram0_rdata[4*i:4*(i + 1)], + i_DI = sram0_wdata[4*i:4*(i + 1)], + i_ADA = Cat(Signal(2), sram0_addr), + i_ADB = Cat(Signal(2), sram0_addr), + i_CEA = sram0_cs & sram0_wren[i//2], + i_CEB = sram0_cs & ~sram0_wren[i//2], i_CLKA = ClockSignal("sys"), i_CLKB = ClockSignal("sys"), i_RESETA = ~bus_reset_n, i_RESETB = ~bus_reset_n, i_OCE = 1, - i_BLKSELA = Cat(sram0_cs, sram0_cs, sram0_cs), - i_BLKSELB = Cat(sram0_cs, sram0_cs, sram0_cs), ) # Flash (Boot Flash memory connected via AHB). From b0cde1acdd94c49b5aa4a96ae6bc24419dbdfca3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 10:12:36 +0100 Subject: [PATCH 402/454] cpu/gowin_emcu: Switch SRAM to 4 SRAMS of 8-bit each. --- litex/soc/cores/cpu/gowin_emcu/core.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index c2beb920a..8cbdcfd23 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -87,7 +87,7 @@ def __init__(self, platform, variant="standard"): i_FLASHINT = Signal(), ) - # SRAM (32-bit RAM split between 8 SRAMs x 4-bit each). + # SRAM (32-bit RAM split between 4 SRAMs x 8-bit each). # ----------------------------------------------------- # CPU SRAM Interface. @@ -105,18 +105,18 @@ def __init__(self, platform, variant="standard"): ) # SRAMS Instances. - for i in range(8): + for i in range(4): self.specials += Instance("SDPB", p_READ_MODE = 0, - p_BIT_WIDTH_0 = 4, - p_BIT_WIDTH_1 = 4, + p_BIT_WIDTH_0 = 8, + p_BIT_WIDTH_1 = 8, p_RESET_MODE = "SYNC", - o_DO = sram0_rdata[4*i:4*(i + 1)], - i_DI = sram0_wdata[4*i:4*(i + 1)], - i_ADA = Cat(Signal(2), sram0_addr), - i_ADB = Cat(Signal(2), sram0_addr), - i_CEA = sram0_cs & sram0_wren[i//2], - i_CEB = sram0_cs & ~sram0_wren[i//2], + o_DO = sram0_rdata[8*i:8*(i + 1)], + i_DI = sram0_wdata[8*i:8*(i + 1)], + i_ADA = Cat(Signal(3), sram0_addr), + i_ADB = Cat(Signal(3), sram0_addr), + i_CEA = sram0_cs & sram0_wren[i], + i_CEB = sram0_cs, i_CLKA = ClockSignal("sys"), i_CLKB = ClockSignal("sys"), i_RESETA = ~bus_reset_n, From de6fbf1271961988959759d9f26befc0fd7a8df8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 10:32:51 +0100 Subject: [PATCH 403/454] cpu/gowin_emcu: Directly connect AHB interfaces, using for loops make things unclear/difficult to follow. --- litex/soc/cores/cpu/gowin_emcu/core.py | 34 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 8cbdcfd23..3e8159280 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -162,12 +162,16 @@ def __init__(self, bus): ) ahb_flash = ahb.Interface() - for s, _ in ahb_flash.master_signals: - if s in ["wdata", "write", "mastlock", "prot"]: - continue - self.cpu_params[f"o_TARGFLASH0H{s.upper()}"] = getattr(ahb_flash, s) - for s, _ in ahb_flash.slave_signals: - self.cpu_params[f"i_TARGFLASH0H{s.upper()}"] = getattr(ahb_flash, s) + self.cpu_params.update( + o_TARGFLASH0HADDR = ahb_flash.addr, + o_TARGFLASH0HBURST = ahb_flash.burst, + o_TARGFLASH0HSIZE = ahb_flash.size, + o_TARGFLASH0HTRANS = ahb_flash.trans, + o_TARGFLASH0HSEL = ahb_flash.sel, + i_TARGFLASH0HRDATA = ahb_flash.rdata, + i_TARGFLASH0HREADYOUT = ahb_flash.readyout, + i_TARGFLASH0HRESP = ahb_flash.resp, + ) flash = ResetInserter()(AHBFlash(ahb_flash)) self.comb += flash.reset.eq(~bus_reset_n) self.submodules += flash @@ -176,10 +180,20 @@ def __init__(self, bus): # Peripheral Bus (AHB -> Wishbone). # --------------------------------- ahb_targexp0 = ahb.Interface() - for s, _ in ahb_targexp0.master_signals: - self.cpu_params[f"o_TARGEXP0H{s.upper()}"] = getattr(ahb_targexp0, s) - for s, _ in ahb_targexp0.slave_signals: - self.cpu_params[f"i_TARGEXP0H{s.upper()}"] = getattr(ahb_targexp0, s) + self.cpu_params.update( + o_TARGEXP0HADDR = ahb_targexp0.addr, + o_TARGEXP0HBURST = ahb_targexp0.burst, + o_TARGEXP0HMASTLOCK = ahb_targexp0.mastlock, + o_TARGEXP0HPROT = ahb_targexp0.prot, + o_TARGEXP0HSIZE = ahb_targexp0.size, + o_TARGEXP0HTRANS = ahb_targexp0.trans, + o_TARGEXP0HWDATA = ahb_targexp0.wdata, + o_TARGEXP0HWRITE = ahb_targexp0.write, + o_TARGEXP0HSEL = ahb_targexp0.sel, + i_TARGEXP0HRDATA = ahb_targexp0.rdata, + i_TARGEXP0HREADYOUT = ahb_targexp0.readyout, + i_TARGEXP0HRESP = ahb_targexp0.resp, + ) self.submodules += ahb.AHB2Wishbone(ahb_targexp0, self.pbus) def connect_uart(self, pads, n=0): From 386854cbd3f1b8e7952141cc1290d46eb6f8d9e1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 10:38:45 +0100 Subject: [PATCH 404/454] cpu/gowin_emcu: Use crt0.c from cortex_m3. --- litex/soc/cores/cpu/gowin_emcu/crt0.c | 67 +++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/crt0.c b/litex/soc/cores/cpu/gowin_emcu/crt0.c index bea687093..cafc474c8 100644 --- a/litex/soc/cores/cpu/gowin_emcu/crt0.c +++ b/litex/soc/cores/cpu/gowin_emcu/crt0.c @@ -8,6 +8,10 @@ void _start(void); void default_handler(void); void _start(void) { + __asm__( + "mov r0, %0\n" + "mov sp, r0\n" : : "r" (&_fstack) + ); uint32_t *y = &_fdata_rom; for (uint32_t *x = &_fdata; x < &_edata; x ++) *x = *y ++; @@ -22,26 +26,73 @@ void _start(void) { while(1); } + void default_handler(void) { while(1); } - const void* isr_vector[] __attribute__((__used__)) __attribute__((section(".isr_vector"))) = { &_fstack, - _start, + _start, // reset + default_handler, // nmi + default_handler, // hard fault + default_handler, // mem manage + default_handler, // bus fault + default_handler, // usage fault + (void *) 0x55, // reserved + 0, // reserved + 0, // reserved + 0, // reserved + default_handler, // svc + default_handler, // debug mon + 0, // reserved + default_handler, // pend sv + default_handler, // systick + // external + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, + default_handler, default_handler, default_handler, default_handler, default_handler, default_handler, - 0, - 0, - 0, - 0, default_handler, default_handler, - 0, default_handler, - default_handler }; + +__asm__ ( +"__gnu_thumb1_case_uhi:\n" +"push {r0, r1}\n" +"mov r1, lr\n" +"lsrs r1, r1, #1\n" +"lsls r0, r0, #1\n" +"lsls r1, r1, #1\n" +"ldrh r1, [r1, r0]\n" +"lsls r1, r1, #1\n" +"add lr, lr, r1\n" +"pop {r0, r1}\n" +"bx lr\n" +); From 6a6837062a0eebc99a81caee4ecc5a238489481c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 10:40:47 +0100 Subject: [PATCH 405/454] cpu/gowin_emcu: Remove interrupt signal since not yet functional/used. --- litex/soc/cores/cpu/gowin_emcu/core.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 3e8159280..22e5e8b30 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -53,7 +53,6 @@ def gcc_flags(self): def __init__(self, platform, variant="standard"): self.platform = platform self.reset = Signal() - self.interrupt = Signal(5) self.pbus = wishbone.Interface(data_width=32, adr_width=30, addressing="word") self.periph_buses = [self.pbus] self.memory_buses = [] @@ -79,7 +78,7 @@ def __init__(self, platform, variant="standard"): o_IOEXPOUTPUTENO = Signal(), # TODO: GPIO Output Enable (16-bit). # Interrupts. - i_GPINT = self.interrupt, + i_GPINT = Open(), o_INTMONITOR = Signal(), # Flash. From 5bbcda4d5ca53f7a36e4499cb4d3e970f7d2d328 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 13:09:31 +0100 Subject: [PATCH 406/454] interconnect/ahb/AHB2Wishbone: Fix size check that is too restrictive, can be <= log2_int(ahb.data_width//8). --- litex/soc/interconnect/ahb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index a39d3d2e2..e7c73f238 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -70,7 +70,7 @@ def __init__(self, ahb, wishbone): fsm.act("IDLE", ahb.readyout.eq(1), If(ahb.sel & - (ahb.size == wishbone_adr_shift) & + (ahb.size <= log2_int(ahb.data_width//8)) & (ahb.trans == TransferType.NONSEQUENTIAL), NextValue(wishbone.adr, ahb.addr[wishbone_adr_shift:]), NextValue(wishbone.dat_w, ahb.wdata), From 55e2a1cec6948470b02cc2c42c0bbd59b500d2f6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 13:13:21 +0100 Subject: [PATCH 407/454] cpu/gowin_emcu: Switch pbus to byte addresssing. --- litex/soc/cores/cpu/gowin_emcu/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 22e5e8b30..3c0352054 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -53,7 +53,7 @@ def gcc_flags(self): def __init__(self, platform, variant="standard"): self.platform = platform self.reset = Signal() - self.pbus = wishbone.Interface(data_width=32, adr_width=30, addressing="word") + self.pbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") self.periph_buses = [self.pbus] self.memory_buses = [] From 02f0a96c847d1327233a84c243eff3e1357d49d2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 15:21:32 +0100 Subject: [PATCH 408/454] interconnect/ahb: Add AHB prefix to TransferType/Interface (similar to AXI). --- litex/soc/cores/cpu/gowin_emcu/core.py | 7 ++++--- litex/soc/interconnect/ahb.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 3c0352054..6d8f8da90 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -10,7 +10,8 @@ from litex.gen import * from litex.soc.cores.cpu import CPU -from litex.soc.interconnect import wishbone, ahb +from litex.soc.interconnect import wishbone +from litex.soc.interconnect import ahb # Gowin EMCU --------------------------------------------------------------------------------------- @@ -160,7 +161,7 @@ def __init__(self, bus): i_NVSTR = 0 ) - ahb_flash = ahb.Interface() + ahb_flash = ahb.AHBInterface() self.cpu_params.update( o_TARGFLASH0HADDR = ahb_flash.addr, o_TARGFLASH0HBURST = ahb_flash.burst, @@ -178,7 +179,7 @@ def __init__(self, bus): # Peripheral Bus (AHB -> Wishbone). # --------------------------------- - ahb_targexp0 = ahb.Interface() + ahb_targexp0 = ahb.AHBInterface() self.cpu_params.update( o_TARGEXP0HADDR = ahb_targexp0.addr, o_TARGEXP0HBURST = ahb_targexp0.burst, diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index e7c73f238..6d0943d0a 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -15,7 +15,7 @@ # Helpers ------------------------------------------------------------------------------------------ -class TransferType(IntEnum): +class AHBTransferType(IntEnum): """Defines types of AHB transfers.""" IDLE = 0 BUSY = 1 @@ -24,7 +24,7 @@ class TransferType(IntEnum): # AHB Interface ------------------------------------------------------------------------------------ -class Interface(Record): +class AHBInterface(Record): """Sets up the AHB interface signals for master and slave.""" adr_width = 32 data_width = 32 @@ -71,7 +71,7 @@ def __init__(self, ahb, wishbone): ahb.readyout.eq(1), If(ahb.sel & (ahb.size <= log2_int(ahb.data_width//8)) & - (ahb.trans == TransferType.NONSEQUENTIAL), + (ahb.trans == AHBTransferType.NONSEQUENTIAL), NextValue(wishbone.adr, ahb.addr[wishbone_adr_shift:]), NextValue(wishbone.dat_w, ahb.wdata), NextValue(wishbone.we, ahb.write), From 70092991323680fe8218e29515aa34f0abf96349 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 15:30:26 +0100 Subject: [PATCH 409/454] interconnect/ahb: Simplify AHBInterface and add data_width/address_width parameters. --- litex/soc/interconnect/ahb.py | 49 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index 6d0943d0a..044636ace 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -22,31 +22,30 @@ class AHBTransferType(IntEnum): NONSEQUENTIAL = 2 SEQUENTIAL = 3 -# AHB Interface ------------------------------------------------------------------------------------ +# AHB Definition ----------------------------------------------------------------------------------- + +def ahb_description(data_width, address_width): + return [ + ("addr", address_width, DIR_M_TO_S), + ("burst", 3, DIR_M_TO_S), + ("mastlock", 1, DIR_M_TO_S), + ("prot", 4, DIR_M_TO_S), + ("size", 3, DIR_M_TO_S), + ("trans", 2, DIR_M_TO_S), + ("wdata", data_width, DIR_M_TO_S), + ("write", 1, DIR_M_TO_S), + ("sel", 1, DIR_M_TO_S), + ("rdata", data_width, DIR_S_TO_M), + ("readyout", 1, DIR_S_TO_M), + ("resp", 1, DIR_S_TO_M), +] class AHBInterface(Record): - """Sets up the AHB interface signals for master and slave.""" - adr_width = 32 - data_width = 32 - addressing = "byte" - master_signals = [ - ("addr", adr_width), - ("burst", 3), - ("mastlock", 1), - ("prot", 4), - ("size", 3), - ("trans", 2), - ("wdata", data_width), - ("write", 1), - ("sel", 1), - ] - slave_signals = [ - ("rdata", data_width), - ("readyout", 1), - ("resp", 1), - ] - def __init__(self): - Record.__init__(self, set_layout_parameters(self.master_signals + self.slave_signals)) + def __init__(self, data_width=32, address_width=32): + Record.__init__(self, ahb_description(data_width, address_width)) + self.data_width = data_width + self.address_width = address_width + self.addressing = "byte" # AHB to Wishbone --------------------------------------------------------------------------------- @@ -62,8 +61,8 @@ def __init__(self, ahb, wishbone): "word" : log2_int(ahb.data_width//8), "byte" : 0 }[wishbone.addressing] - assert ahb.data_width == wishbone.data_width - assert ahb.adr_width == wishbone.adr_width + wishbone_adr_shift + assert ahb.data_width == wishbone.data_width + assert ahb.address_width == wishbone.adr_width + wishbone_adr_shift # FSM. self.fsm = fsm = FSM() From 739a8db8c37205e3b3eec532af1f7db87e4a98ef Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 15:30:47 +0100 Subject: [PATCH 410/454] cpu/gowin_emcu: Specify AHB data_width/address_width. --- litex/soc/cores/cpu/gowin_emcu/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 6d8f8da90..6bd90550e 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -161,7 +161,7 @@ def __init__(self, bus): i_NVSTR = 0 ) - ahb_flash = ahb.AHBInterface() + ahb_flash = ahb.AHBInterface(data_width=32, address_width=32) self.cpu_params.update( o_TARGFLASH0HADDR = ahb_flash.addr, o_TARGFLASH0HBURST = ahb_flash.burst, @@ -179,7 +179,7 @@ def __init__(self, bus): # Peripheral Bus (AHB -> Wishbone). # --------------------------------- - ahb_targexp0 = ahb.AHBInterface() + ahb_targexp0 = ahb.AHBInterface(data_width=32, address_width=32) self.cpu_params.update( o_TARGEXP0HADDR = ahb_targexp0.addr, o_TARGEXP0HBURST = ahb_targexp0.burst, From cf165d3c2c6305c32880dd0598685dbac470b466 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 15:33:01 +0100 Subject: [PATCH 411/454] README/Bios: Bump year. --- README.md | 2 +- litex/soc/software/bios/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 721021380..becbbe4de 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

``` - Copyright 2012-2023 / Enjoy-Digital & LiteX developers + Copyright 2012-2024 / Enjoy-Digital & LiteX developers ``` [![](https://github.com/enjoy-digital/litex/workflows/ci/badge.svg)](https://github.com/enjoy-digital/litex/actions) ![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 69fbd22af..a39caafd3 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -110,7 +110,7 @@ __attribute__((__used__)) int main(int i, char **c) printf("\e[1m /____/_/\\__/\\__/_/|_|\e[0m\n"); printf("\e[1m Build your hardware, easily!\e[0m\n"); printf("\n"); - printf(" (c) Copyright 2012-2023 Enjoy-Digital\n"); + printf(" (c) Copyright 2012-2024 Enjoy-Digital\n"); printf(" (c) Copyright 2007-2015 M-Labs\n"); printf("\n"); #ifndef CONFIG_BIOS_NO_BUILD_TIME From c61d2de13b1665d28e86f5a2c20d4a613bf9da78 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 15:37:58 +0100 Subject: [PATCH 412/454] CHANGES.md: Update. --- CHANGES.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 2d1d09728..d431772ec 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,19 @@ +[> Changes since 2023.12 +------------------------ + [> Fixed + -------- + - integration/soc : Fixed typo in cpu mem_bus axi-via-wb downconvert + - interconnect/ahb/AHB2Wishbone : Fix size check that was too restrictive. + + [> Added + -------- + - build/openfpgaloader : Added kwargs support to flash for specific/less common cases. + - cpu/gowin_emcu : Improved/Cleaned-up. + - interconnect/ahb : Added data_width/address_width parameters. + + [> Changed + ---------- + [> 2023.12, released on December 25th 2023 ------------------------------------------ [> Fixed From 718c26d8fc30045b61c1760376dd27a52a57400d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 4 Jan 2024 19:33:43 +0100 Subject: [PATCH 413/454] cpu/gowin_emcu: Add interfaces directly to instances and simplify/cleanup to remove some warnings. --- litex/soc/cores/cpu/gowin_emcu/core.py | 125 ++++++++++++++++++------- 1 file changed, 90 insertions(+), 35 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index 6bd90550e..dcc38edc0 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -13,7 +13,7 @@ from litex.soc.interconnect import wishbone from litex.soc.interconnect import ahb -# Gowin EMCU --------------------------------------------------------------------------------------- +# Gowin EMCU (Enhanced MCU / Cortex M3) ------------------------------------------------------------ class GowinEMCU(CPU): variants = ["standard"] @@ -61,7 +61,10 @@ def __init__(self, platform, variant="standard"): # CPU Instance. # ------------- - bus_reset_n = Signal() + bus_reset_n = Signal() + ahb_flash = ahb.AHBInterface(data_width=32, address_width=32) + ahb_targexp0 = ahb.AHBInterface(data_width=32, address_width=32) + self.cpu_params = dict( # Clk/Rst. i_FCLK = ClockSignal("sys"), @@ -71,20 +74,95 @@ def __init__(self, platform, variant="standard"): o_MTXHRESETN = bus_reset_n, # RTC. - i_RTCSRCCLK = Signal(), # TODO: RTC Clk In. + i_RTCSRCCLK = 0b0, # RTC Clk In. # GPIOs. - i_IOEXPINPUTI = Signal(), # TODO: GPIO Input (16-bit). - o_IOEXPOUTPUTO = Signal(), # TODO: GPIO Output (16-bit). - o_IOEXPOUTPUTENO = Signal(), # TODO: GPIO Output Enable (16-bit). + i_IOEXPINPUTI = 0x0000, # GPIO Input (16-bit). + o_IOEXPOUTPUTO = Open(16), # GPIO Output (16-bit). + o_IOEXPOUTPUTENO = Open(16), # GPIO Output Enable (16-bit). + + # UART0. + i_UART0RXDI = 0b0, + o_UART0TXDO = Open(), + o_UART0BAUDTICK = Open(), + + # UART1. + i_UART1RXDI = 0b0, + o_UART1TXDO = Open(), + o_UART1BAUDTICK = Open(), # Interrupts. - i_GPINT = Open(), - o_INTMONITOR = Signal(), + i_GPINT = 0, + o_INTMONITOR = Open(), # Flash. i_FLASHERR = Signal(), i_FLASHINT = Signal(), + + # Debug/JTAG. + o_DAPTDO = Open(), + o_DAPJTAGNSW = Open(), + o_DAPNTDOEN = Open(), + i_DAPSWDITMS = 0, + i_DAPTDI = 0, + i_DAPNTRST = 0, + i_DAPSWCLKTCK = 0, + + # TARGFLASH0 / AHBLite Master. + o_TARGFLASH0HSEL = ahb_flash.sel, + o_TARGFLASH0HADDR = ahb_flash.addr, + o_TARGFLASH0HTRANS = ahb_flash.trans, + o_TARGFLASH0HSIZE = ahb_flash.size, + o_TARGFLASH0HBURST = ahb_flash.burst, + o_TARGFLASH0HREADYMUX = Open(), + i_TARGFLASH0HRDATA = ahb_flash.rdata, + i_TARGFLASH0HRUSER = 0b000, + i_TARGFLASH0HRESP = ahb_flash.resp, + i_TARGFLASH0EXRESP = 0b0, + i_TARGFLASH0HREADYOUT = ahb_flash.readyout, + + # TARGEXP0 / AHBLite Master. + o_TARGEXP0HSEL = ahb_targexp0.sel, + o_TARGEXP0HADDR = ahb_targexp0.addr, + o_TARGEXP0HTRANS = ahb_targexp0.trans, + o_TARGEXP0HWRITE = ahb_targexp0.write, + o_TARGEXP0HSIZE = ahb_targexp0.size, + o_TARGEXP0HBURST = ahb_targexp0.burst, + o_TARGEXP0HPROT = ahb_targexp0.prot, + o_TARGEXP0MEMATTR = Open(2), + o_TARGEXP0EXREQ = Open(), + o_TARGEXP0HMASTER = Open(4), + o_TARGEXP0HWDATA = ahb_targexp0.wdata, + o_TARGEXP0HMASTLOCK = ahb_targexp0.mastlock, + o_TARGEXP0HREADYMUX = Open(), + o_TARGEXP0HAUSER = Open(), + o_TARGEXP0HWUSER = Open(4), + i_TARGEXP0HRDATA = ahb_targexp0.rdata, + i_TARGEXP0HREADYOUT = ahb_targexp0.readyout, + i_TARGEXP0HRESP = ahb_targexp0.resp, + i_TARGEXP0EXRESP = 0b0, + i_TARGEXP0HRUSER = 0b000, + + # INITEXP0 / AHBLite Slave. + o_INITEXP0HRDATA = Open(32), + o_INITEXP0HREADY = Open(), + o_INITEXP0HRESP = Open(), + o_INITEXP0EXRESP = Open(), + o_INITEXP0HRUSER = Open(3), + i_INITEXP0HSEL = 0b0, + i_INITEXP0HADDR = 0x00000000, + i_INITEXP0HTRANS = 0b00, + i_INITEXP0HWRITE = 0b0, + i_INITEXP0HSIZE = 0b000, + i_INITEXP0HBURST = 0b000, + i_INITEXP0HPROT = 0b0000, + i_INITEXP0MEMATTR = 0b00, + i_INITEXP0EXREQ = 0b0, + i_INITEXP0HMASTER = 0b0000, + i_INITEXP0HWDATA = 0x00000000, + i_INITEXP0HMASTLOCK = 0b0, + i_INITEXP0HAUSER = 0b0, + i_INITEXP0HWUSER = 0b0000, ) # SRAM (32-bit RAM split between 4 SRAMs x 8-bit each). @@ -111,6 +189,10 @@ def __init__(self, platform, variant="standard"): p_BIT_WIDTH_0 = 8, p_BIT_WIDTH_1 = 8, p_RESET_MODE = "SYNC", + p_BLK_SEL_0 = Constant(0, 3), + p_BLK_SEL_1 = Constant(0, 3), + i_BLKSELA = 0b000, + i_BLKSELB = 0b000, o_DO = sram0_rdata[8*i:8*(i + 1)], i_DI = sram0_wdata[8*i:8*(i + 1)], i_ADA = Cat(Signal(3), sram0_addr), @@ -161,39 +243,12 @@ def __init__(self, bus): i_NVSTR = 0 ) - ahb_flash = ahb.AHBInterface(data_width=32, address_width=32) - self.cpu_params.update( - o_TARGFLASH0HADDR = ahb_flash.addr, - o_TARGFLASH0HBURST = ahb_flash.burst, - o_TARGFLASH0HSIZE = ahb_flash.size, - o_TARGFLASH0HTRANS = ahb_flash.trans, - o_TARGFLASH0HSEL = ahb_flash.sel, - i_TARGFLASH0HRDATA = ahb_flash.rdata, - i_TARGFLASH0HREADYOUT = ahb_flash.readyout, - i_TARGFLASH0HRESP = ahb_flash.resp, - ) flash = ResetInserter()(AHBFlash(ahb_flash)) self.comb += flash.reset.eq(~bus_reset_n) self.submodules += flash - # Peripheral Bus (AHB -> Wishbone). # --------------------------------- - ahb_targexp0 = ahb.AHBInterface(data_width=32, address_width=32) - self.cpu_params.update( - o_TARGEXP0HADDR = ahb_targexp0.addr, - o_TARGEXP0HBURST = ahb_targexp0.burst, - o_TARGEXP0HMASTLOCK = ahb_targexp0.mastlock, - o_TARGEXP0HPROT = ahb_targexp0.prot, - o_TARGEXP0HSIZE = ahb_targexp0.size, - o_TARGEXP0HTRANS = ahb_targexp0.trans, - o_TARGEXP0HWDATA = ahb_targexp0.wdata, - o_TARGEXP0HWRITE = ahb_targexp0.write, - o_TARGEXP0HSEL = ahb_targexp0.sel, - i_TARGEXP0HRDATA = ahb_targexp0.rdata, - i_TARGEXP0HREADYOUT = ahb_targexp0.readyout, - i_TARGEXP0HRESP = ahb_targexp0.resp, - ) self.submodules += ahb.AHB2Wishbone(ahb_targexp0, self.pbus) def connect_uart(self, pads, n=0): From 91fbc79ac2e0af4e9edf3a3fe423f98fb7bdeffb Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 8 Jan 2024 07:28:56 +0100 Subject: [PATCH 414/454] build/gowin/common: adding missing TX/Q1 ODDR signals --- litex/build/gowin/common.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/build/gowin/common.py b/litex/build/gowin/common.py index fd554e946..1869385af 100644 --- a/litex/build/gowin/common.py +++ b/litex/build/gowin/common.py @@ -7,6 +7,8 @@ from migen.fhdl.module import Module from migen.genlib.resetsync import AsyncResetSynchronizer +from litex.gen import * + from litex.build.io import * # Gowin AsyncResetSynchronizer --------------------------------------------------------------------- @@ -58,7 +60,9 @@ def __init__(self, i1, i2, o, clk): i_CLK = clk, i_D0 = i1, i_D1 = i2, + i_TX = 0, o_Q0 = o, + o_Q1 = Open(), ) class GowinDDROutput: From 31d3325219a387c4e426061799f28019b7069951 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 10 Jan 2024 06:51:18 +0100 Subject: [PATCH 415/454] build/gowin/platform: adding mock add_false_path_constraint method Signed-off-by: Gwenhael Goavec-Merou --- litex/build/gowin/platform.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litex/build/gowin/platform.py b/litex/build/gowin/platform.py index 2e8a75f44..f21d11ee7 100644 --- a/litex/build/gowin/platform.py +++ b/litex/build/gowin/platform.py @@ -43,3 +43,6 @@ def get_verilog(self, *args, special_overrides=dict(), **kwargs): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) + + def add_false_path_constraint(self, from_, to): + pass From a2c2d7084176b8b16ed1076dbeab1ffa13f1941c Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 10 Jan 2024 06:52:06 +0100 Subject: [PATCH 416/454] build/gowin/gowin: adding list of additional cst commands (to place resources) Signed-off-by: Gwenhael Goavec-Merou --- litex/build/gowin/gowin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litex/build/gowin/gowin.py b/litex/build/gowin/gowin.py index 8ee97cecf..7129db38e 100644 --- a/litex/build/gowin/gowin.py +++ b/litex/build/gowin/gowin.py @@ -26,6 +26,7 @@ class GowinToolchain(GenericToolchain): def __init__(self): super().__init__() self.options = {} + self.additional_cst_commands = [] def finalize(self): if self.platform.verilog_include_paths: @@ -108,6 +109,8 @@ def _search_pin_entry(pin_lst, pin_name): if self.named_pc: cst.extend(self.named_pc) + cst.extend(self.additional_cst_commands) + tools.write_to_file(f"{self._build_name}.cst", "\n".join(cst)) return (f"{self._build_name}.cst", "CST") From 80dfb5ca34daa7bc13c1e3b20eae58419f8cbd52 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 10 Jan 2024 12:10:15 +0100 Subject: [PATCH 417/454] interconnect/ahb/AHB2Wishbone: Simplify and add proper Address/Data-Phases. --- litex/soc/interconnect/ahb.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index 044636ace..8fe6aff4f 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -66,27 +66,24 @@ def __init__(self, ahb, wishbone): # FSM. self.fsm = fsm = FSM() - fsm.act("IDLE", + fsm.act("ADDRESS-PHASE", ahb.readyout.eq(1), If(ahb.sel & (ahb.size <= log2_int(ahb.data_width//8)) & (ahb.trans == AHBTransferType.NONSEQUENTIAL), - NextValue(wishbone.adr, ahb.addr[wishbone_adr_shift:]), - NextValue(wishbone.dat_w, ahb.wdata), - NextValue(wishbone.we, ahb.write), - NextValue(wishbone.sel, 2**len(wishbone.sel) - 1), - NextState("ACT"), + NextValue(wishbone.adr, ahb.addr[wishbone_adr_shift:]), + NextValue(wishbone.we, ahb.write), + NextState("DATA-PHASE"), ) ) - fsm.act("ACT", + fsm.act("DATA-PHASE", wishbone.stb.eq(1), wishbone.cyc.eq(1), + wishbone.dat_w.eq(ahb.wdata), + wishbone.sel.eq(2**len(wishbone.sel) - 1), + ahb.resp.eq(wishbone.err), If(wishbone.ack, - If(~wishbone.we, - NextValue(ahb.rdata, wishbone.dat_r) - ), - NextState("IDLE") + NextValue(ahb.rdata, wishbone.dat_r), + NextState("ADDRESS-PHASE") ) ) - - self.comb += ahb.resp.eq(wishbone.err) From e689aab18a9eb8b11a99463e04df146890c72c28 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 11 Jan 2024 10:17:22 +0100 Subject: [PATCH 418/454] interconnect/ahb/AHB2Wishbone: Add proper Wishbone sel decoder/support. --- litex/soc/interconnect/ahb.py | 39 +++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index 8fe6aff4f..cee3540cd 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -64,6 +64,37 @@ def __init__(self, ahb, wishbone): assert ahb.data_width == wishbone.data_width assert ahb.address_width == wishbone.adr_width + wishbone_adr_shift + def wishbone_sel_decoder(ahb_size, ahb_addr): + wishbone_sel = Signal(8) + self.comb += Case(ahb_size, { + # 8-bit access. + 0b00 : Case(ahb_addr[0:3], { + 0b000 : wishbone_sel.eq(0b0000_0001), + 0b001 : wishbone_sel.eq(0b0000_0010), + 0b010 : wishbone_sel.eq(0b0000_0100), + 0b011 : wishbone_sel.eq(0b0000_1000), + 0b100 : wishbone_sel.eq(0b0001_0000), + 0b101 : wishbone_sel.eq(0b0010_0000), + 0b110 : wishbone_sel.eq(0b0100_0000), + 0b111 : wishbone_sel.eq(0b1000_0000), + }), + # 16-bit access. + 0b01 : Case(ahb_addr[1:3], { + 0b00 : wishbone_sel.eq(0b0000_0011), + 0b01 : wishbone_sel.eq(0b0000_1100), + 0b10 : wishbone_sel.eq(0b0011_0000), + 0b11 : wishbone_sel.eq(0b1100_0000), + }), + # 32-bit access. + 0b10 : Case(ahb_addr[2:3], { + 0b0 : wishbone_sel.eq(0b0000_1111), + 0b1 : wishbone_sel.eq(0b1111_0000), + }), + # 64-bit access. + 0b11 : wishbone_sel.eq(0b1111_1111), + }) + return wishbone_sel + # FSM. self.fsm = fsm = FSM() fsm.act("ADDRESS-PHASE", @@ -71,16 +102,16 @@ def __init__(self, ahb, wishbone): If(ahb.sel & (ahb.size <= log2_int(ahb.data_width//8)) & (ahb.trans == AHBTransferType.NONSEQUENTIAL), - NextValue(wishbone.adr, ahb.addr[wishbone_adr_shift:]), - NextValue(wishbone.we, ahb.write), - NextState("DATA-PHASE"), + NextValue(wishbone.adr, ahb.addr[wishbone_adr_shift:]), + NextValue(wishbone.we, ahb.write), + NextValue(wishbone.sel, wishbone_sel_decoder(ahb.size, ahb.addr)), + NextState("DATA-PHASE"), ) ) fsm.act("DATA-PHASE", wishbone.stb.eq(1), wishbone.cyc.eq(1), wishbone.dat_w.eq(ahb.wdata), - wishbone.sel.eq(2**len(wishbone.sel) - 1), ahb.resp.eq(wishbone.err), If(wishbone.ack, NextValue(ahb.rdata, wishbone.dat_r), From 8aa5958fb7138add921c9f959d6bf4ea8f50d0d7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 11 Jan 2024 13:11:56 +0100 Subject: [PATCH 419/454] cores/cpu: Add intitial gowin_ae350 support. --- CHANGES.md | 2 + litex/soc/cores/cpu/gowin_ae350/__init__.py | 1 + litex/soc/cores/cpu/gowin_ae350/boot-helper.S | 4 + litex/soc/cores/cpu/gowin_ae350/core.py | 308 ++++++++++++++++++ litex/soc/cores/cpu/gowin_ae350/crt0.S | 75 +++++ litex/soc/cores/cpu/gowin_ae350/irq.h | 4 + litex/soc/cores/cpu/gowin_ae350/system.h | 19 ++ litex/soc/software/bios/main.c | 4 + 8 files changed, 417 insertions(+) create mode 100644 litex/soc/cores/cpu/gowin_ae350/__init__.py create mode 100644 litex/soc/cores/cpu/gowin_ae350/boot-helper.S create mode 100644 litex/soc/cores/cpu/gowin_ae350/core.py create mode 100644 litex/soc/cores/cpu/gowin_ae350/crt0.S create mode 100644 litex/soc/cores/cpu/gowin_ae350/irq.h create mode 100644 litex/soc/cores/cpu/gowin_ae350/system.h diff --git a/CHANGES.md b/CHANGES.md index d431772ec..9efb5d1ee 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ - build/openfpgaloader : Added kwargs support to flash for specific/less common cases. - cpu/gowin_emcu : Improved/Cleaned-up. - interconnect/ahb : Added data_width/address_width parameters. + - interconnect/ahb : Added proper byte/sel support to AHB2Wishbone. + - cpu/gowin_ae350 : Added initial support. [> Changed ---------- diff --git a/litex/soc/cores/cpu/gowin_ae350/__init__.py b/litex/soc/cores/cpu/gowin_ae350/__init__.py new file mode 100644 index 000000000..55596975c --- /dev/null +++ b/litex/soc/cores/cpu/gowin_ae350/__init__.py @@ -0,0 +1 @@ +from litex.soc.cores.cpu.gowin_ae350.core import GowinAE350 diff --git a/litex/soc/cores/cpu/gowin_ae350/boot-helper.S b/litex/soc/cores/cpu/gowin_ae350/boot-helper.S new file mode 100644 index 000000000..e8bd5c760 --- /dev/null +++ b/litex/soc/cores/cpu/gowin_ae350/boot-helper.S @@ -0,0 +1,4 @@ + .section .text, "ax", @progbits + .global boot_helper +boot_helper: + jr x13 diff --git a/litex/soc/cores/cpu/gowin_ae350/core.py b/litex/soc/cores/cpu/gowin_ae350/core.py new file mode 100644 index 000000000..6d7a8271e --- /dev/null +++ b/litex/soc/cores/cpu/gowin_ae350/core.py @@ -0,0 +1,308 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2024 Gwenhael Goavec-Merou +# Copyright (c) 2024 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from migen import * + +from litex.gen import * + +from litex.soc.interconnect import wishbone, ahb +from litex.soc.interconnect.csr import * +from litex.soc.cores.cpu import CPU, CPU_GCC_TRIPLE_RISCV32 + +# Gowin AE350 Constants ---------------------------------------------------------------------------- + +APB_CE_APB = (1 << 0) +APB_CE_UART1 = (1 << 1) +APB_CE_UART2 = (1 << 2) +APB_CE_SPI = (1 << 3) +APB_CE_GPIO = (1 << 4) +APB_CE_PIT = (1 << 5) +APB_CE_I2C = (1 << 6) +APB_CE_WDT = (1 << 7) + +# Gowin AE350 -------------------------------------------------------------------------------------- + +class GowinAE350(CPU): + variants = ["standard"] + category = "hardcore" + family = "riscv" + name = "gowin_ae350" + human_name = "Gowin AE350" + data_width = 32 + endianness = "little" + reset_address = 0x8000_0000 + gcc_triple = CPU_GCC_TRIPLE_RISCV32 + linker_output_format = "elf32-littleriscv" + nop = "nop" + io_regions = { + # Origin, Length. + 0xe800_0000: 0x6000_0000 + } + + @property + def mem_map(self): + return { + "rom" : 0x80000000, + "sram" : 0x00000000, + "peripherals" : 0xf0000000, + "csr" : 0xe8000000, + } + + # GCC Flags. + @property + def gcc_flags(self): + flags = f" -mabi=ilp32 -march=rv32imafdc" + flags += f" -D__AE350__" + return flags + + def __init__(self, platform, variant, *args, **kwargs): + self.platform = platform + self.reset = Signal() + self.ibus = ibus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.dbus = dbus = wishbone.Interface(data_width=64, address_width=32, addressing="word") + self.pbus = pbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.periph_buses = [ibus, dbus, pbus] # Peripheral buses (Connected to main SoC's bus). + self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM). + + + # AHBLite Buses. + # -------------- + self.ahb_rom = ahb_rom = ahb.AHBInterface(data_width=32, address_width=32) + self.ahb_ram = ahb_ram = ahb.AHBInterface(data_width=64, address_width=32) + self.ahb_exts = ahb_exts = ahb.AHBInterface(data_width=32, address_width=32) + self.comb += [ + # Set AHBLite ROM static signals. + ahb_rom.sel.eq(1), + ahb_rom.size.eq(0b010), + ahb_rom.burst.eq(0), + # Set AHBLite RAM static signals. + ahb_ram.sel.eq(1), + ] + + # CPU Instance. + # ------------- + self.cpu_params = dict( + # Clk/Rst. + i_CORE_CLK = ClockSignal("cpu"), + i_DDR_CLK = ClockSignal("sys"), + i_AHB_CLK = ClockSignal("sys"), + i_APB_CLK = ClockSignal("sys"), + i_POR_N = 1, + i_HW_RSTN = ~(ResetSignal("sys") | self.reset), + o_PRESETN = Open(), + o_HRESETN = Open(), + o_DDR_RSTN = Open(), + + # Features/Peripherals Enable. + i_CORE_CE = 1, + i_AXI_CE = 1, + i_DDR_CE = 1, + i_AHB_CE = 1, + i_APB_CE = Constant(APB_CE_APB, 8), + i_APB2AHB_CE = 1, + + # WFI. + o_CORE0_WFI_MODE = Open(), + i_WAKEUP_IN = 0, + + # RTC. + i_RTC_CLK = ClockSignal("sys"), + o_RTC_WAKEUP = Open(), + + # Interrupts. + i_GP_INT = Constant(0, 16), + + # DMA. + i_DMA_REQ = Constant(0, 8), + o_DMA_ACK = Open(8), + + # AHBLite ROM interface. + i_ROM_HRDATA = ahb_rom.rdata, + i_ROM_HREADY = ahb_rom.readyout, + i_ROM_HRESP = ahb_rom.resp, + o_ROM_HADDR = ahb_rom.addr, + o_ROM_HTRANS = ahb_rom.trans, + o_ROM_HWRITE = ahb_rom.write, + + # APBLite Fabric interface (Slave). + o_APB_PADDR = Open(32), + o_APB_PENABLE = Open(), + i_APB_PRDATA = Constant(0, 32), + i_APB_PREADY = 0, + o_APB_PSEL = Open(), + o_APB_PWDATA = Open(32), + o_APB_PWRITE = Open(), + i_APB_PSLVERR = 0, + o_APB_PPROT = Open(3), + o_APB_PSTRB = Open(4), + + # AHBLite Peripheral interface (Master). + i_EXTS_HRDATA = ahb_exts.rdata, + i_EXTS_HREADYIN = ahb_exts.readyout, + i_EXTS_HRESP = ahb_exts.resp, + o_EXTS_HADDR = ahb_exts.addr, + o_EXTS_HBURST = ahb_exts.burst, + o_EXTS_HPROT = ahb_exts.prot, + o_EXTS_HSEL = ahb_exts.sel, + o_EXTS_HSIZE = ahb_exts.size, + o_EXTS_HTRANS = ahb_exts.trans, + o_EXTS_HWDATA = ahb_exts.wdata, + o_EXTS_HWRITE = ahb_exts.write, + + # AHBLite Peripheral interface (Slave). + i_EXTM_HADDR = Constant(0, 32), + i_EXTM_HBURST = Constant(0, 3), + i_EXTM_HPROT = Constant(0, 4), + o_EXTM_HRDATA = Open(64), + i_EXTM_HREADY = 0, + o_EXTM_HREADYOUT = Open(), + o_EXTM_HRESP = Open(), + i_EXTM_HSEL = 0, + i_EXTM_HSIZE = Constant(0, 3), + i_EXTM_HTRANS = Constant(0, 2), + i_EXTM_HWDATA = Constant(0, 64), + i_EXTM_HWRITE = 0, + + # AHBLite RAM interface (Slave). + i_DDR_HRDATA = ahb_ram.rdata, + i_DDR_HREADY = ahb_ram.readyout, + i_DDR_HRESP = ahb_ram.resp, + o_DDR_HADDR = ahb_ram.addr, + o_DDR_HBURST = ahb_ram.burst, + o_DDR_HPROT = ahb_ram.prot, + o_DDR_HSIZE = ahb_ram.size, + o_DDR_HTRANS = ahb_ram.trans, + o_DDR_HWDATA = ahb_ram.wdata, + o_DDR_HWRITE = ahb_ram.write, + + # GPIOs. + i_GPIO_IN = Constant(0, 32), + o_GPIO_OUT = Open(32), + o_GPIO_OE = Open(32), + + # SCAN. + i_SCAN_EN = 0, + i_SCAN_TEST = 0, + i_SCAN_IN = Constant(0xfffff, 20), + o_SCAN_OUT = Open(20), + + # Integrated JTAG. + i_INTEG_TCK = 1, + i_INTEG_TDI = 1, + i_INTEG_TMS = 1, + i_INTEG_TRST = 1, + o_INTEG_TDO = Open(), + + # SRAM (FIXME : Cleanup). + i_PGEN_CHAIN_I = 1, + o_PRDYN_CHAIN_O = Open(), + i_EMA = Constant(0b011, 3), + i_EMAW = Constant(0b01, 2), + i_EMAS = 0, + i_RET1N = 1, + i_RET2N = 1, + + # SPI. + i_SPI2_HOLDN_IN = 0, + i_SPI2_WPN_IN = 0, + i_SPI2_CLK_IN = 0, + i_SPI2_CSN_IN = 0, + i_SPI2_MISO_IN = 0, + i_SPI2_MOSI_IN = 0, + o_SPI2_HOLDN_OUT = Open(), + o_SPI2_HOLDN_OE = Open(), + o_SPI2_WPN_OUT = Open(), + o_SPI2_WPN_OE = Open(), + o_SPI2_CLK_OUT = Open(), + o_SPI2_CLK_OE = Open(), + o_SPI2_CSN_OUT = Open(), + o_SPI2_CSN_OE = Open(), + o_SPI2_MISO_OUT = Open(), + o_SPI2_MISO_OE = Open(), + o_SPI2_MOSI_OUT = Open(), + o_SPI2_MOSI_OE = Open(), + + # I2C. + i_I2C_SCL_IN = 0, + i_I2C_SDA_IN = 0, + o_I2C_SCL = Open(), + o_I2C_SDA = Open(), + + # PIT/PWM. + o_CH0_PWM = Open(), + o_CH0_PWMOE = Open(), + o_CH1_PWM = Open(), + o_CH1_PWMOE = Open(), + o_CH2_PWM = Open(), + o_CH2_PWMOE = Open(), + o_CH3_PWM = Open(), + o_CH3_PWMOE = Open(), + + # UART1. + o_UART1_TXD = Open(), + o_UART1_RTSN = Open(), + i_UART1_RXD = 0, + i_UART1_CTSN = 0, + i_UART1_DSRN = 0, + i_UART1_DCDN = 0, + i_UART1_RIN = 0, + o_UART1_DTRN = Open(), + o_UART1_OUT1N = Open(), + o_UART1_OUT2N = Open(), + + # UART2. + o_UART2_TXD = Open(), + o_UART2_RTSN = Open(), + i_UART2_RXD = 0, + i_UART2_CTSN = 1, + i_UART2_DCDN = 1, + i_UART2_DSRN = 1, + i_UART2_RIN = 1, + o_UART2_DTRN = Open(), + o_UART2_OUT1N = Open(), + o_UART2_OUT2N = Open(), + + # JTAG. + i_DBG_TCK = 1, + i_TMS_IN = 1, + i_TRST_IN = 1, + i_TDI_IN = 0, + o_TDO_OUT = Open(), + o_TDO_OE = Open(), + + # Test. + i_TEST_CLK = 0, + i_TEST_MODE = 0, + i_TEST_RSTN = 1, + ) + + # AHBLite ROM Interface. + # ---------------------- + self.submodules += ahb.AHB2Wishbone(ahb_rom, self.ibus) + + # AHBLite RAM Interface. + # ---------------------- + self.submodules += ahb.AHB2Wishbone(ahb_ram, self.dbus) + + # AHBLite Peripheral Interface. + # ----------------------------- + self.submodules += ahb.AHB2Wishbone(ahb_exts, self.pbus) + + def connect_jtag(self, pads): + self.cpu_params.update( + i_DBG_TCK = pads.tck, + i_TMS_IN = pads.tms, + i_TRST_IN = pads.trst, + i_TDI_IN = pads.tdi, + o_TDO_OUT = pads.tdo, + o_TDO_OE = Open(), + ) + + def do_finalize(self): + self.specials += Instance("AE350_SOC", **self.cpu_params) diff --git a/litex/soc/cores/cpu/gowin_ae350/crt0.S b/litex/soc/cores/cpu/gowin_ae350/crt0.S new file mode 100644 index 000000000..13bfc48e9 --- /dev/null +++ b/litex/soc/cores/cpu/gowin_ae350/crt0.S @@ -0,0 +1,75 @@ +#define MIE_MEIE 0x800 + + .global _start +_start: + j reset_vector + +reset_vector: + la sp, _fstack + la t0, trap_vector + csrw mtvec, t0 + + // initialize .data + la t0, _fdata + la t1, _edata + la t2, _fdata_rom +1: beq t0, t1, 2f + lw t3, 0(t2) + sw t3, 0(t0) + addi t0, t0, 4 + addi t2, t2, 4 + j 1b +2: + + // initialize .bss + la t0, _fbss + la t1, _ebss +1: beq t0, t1, 3f + sw zero, 0(t0) + addi t0, t0, 4 + j 1b +3: + // enable external interrupts + li t0, MIE_MEIE + csrs mie, t0 + + call main +1: j 1b + +trap_vector: + addi sp, sp, -16*4 + sw ra, 0*4(sp) + sw t0, 1*4(sp) + sw t1, 2*4(sp) + sw t2, 3*4(sp) + sw a0, 4*4(sp) + sw a1, 5*4(sp) + sw a2, 6*4(sp) + sw a3, 7*4(sp) + sw a4, 8*4(sp) + sw a5, 9*4(sp) + sw a6, 10*4(sp) + sw a7, 11*4(sp) + sw t3, 12*4(sp) + sw t4, 13*4(sp) + sw t5, 14*4(sp) + sw t6, 15*4(sp) + call isr + lw ra, 0*4(sp) + lw t0, 1*4(sp) + lw t1, 2*4(sp) + lw t2, 3*4(sp) + lw a0, 4*4(sp) + lw a1, 5*4(sp) + lw a2, 6*4(sp) + lw a3, 7*4(sp) + lw a4, 8*4(sp) + lw a5, 9*4(sp) + lw a6, 10*4(sp) + lw a7, 11*4(sp) + lw t3, 12*4(sp) + lw t4, 13*4(sp) + lw t5, 14*4(sp) + lw t6, 15*4(sp) + addi sp, sp, 16*4 + mret diff --git a/litex/soc/cores/cpu/gowin_ae350/irq.h b/litex/soc/cores/cpu/gowin_ae350/irq.h new file mode 100644 index 000000000..7374cf506 --- /dev/null +++ b/litex/soc/cores/cpu/gowin_ae350/irq.h @@ -0,0 +1,4 @@ +#ifndef __IRQ_H +#define __IRQ_H + +#endif /* __IRQ_H */ diff --git a/litex/soc/cores/cpu/gowin_ae350/system.h b/litex/soc/cores/cpu/gowin_ae350/system.h new file mode 100644 index 000000000..c27fc4da8 --- /dev/null +++ b/litex/soc/cores/cpu/gowin_ae350/system.h @@ -0,0 +1,19 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((unused)) static void flush_cpu_icache(void){}; /* FIXME */ +__attribute__((unused)) static void flush_cpu_dcache(void){}; /* FIXME */ +void flush_l2_cache(void); + +void busy_wait(unsigned int ms); +void busy_wait_us(unsigned int us); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_H */ diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index a39caafd3..67ca3d590 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -125,7 +125,11 @@ __attribute__((__used__)) int main(int i, char **c) printf("--=============== \e[1mSoC\e[0m ==================--\n"); printf("\e[1mCPU\e[0m:\t\t%s @ %dMHz\n", CONFIG_CPU_HUMAN_NAME, +#ifdef CONFIG_CPU_CLK_FREQ + CONFIG_CPU_CLK_FREQ/1000000); +#else CONFIG_CLOCK_FREQUENCY/1000000); +#endif printf("\e[1mBUS\e[0m:\t\t%s %d-bit @ %dGiB\n", CONFIG_BUS_STANDARD, CONFIG_BUS_DATA_WIDTH, From 6b79644108a49411c20a982441a2f908fda32852 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 11 Jan 2024 13:53:15 +0100 Subject: [PATCH 420/454] cores/cpu/gowin_emcu: Switch to LiteX's UART. A UART does not cost that much ressources and this avoid specific code/allow simplifying support. --- litex/soc/cores/cpu/gowin_emcu/core.py | 8 ---- litex/soc/cores/cpu/gowin_emcu/crt0.c | 3 -- litex/soc/cores/cpu/gowin_emcu/system.h | 52 ------------------------- 3 files changed, 63 deletions(-) diff --git a/litex/soc/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index dcc38edc0..d9ba87858 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -251,14 +251,6 @@ def __init__(self, bus): # --------------------------------- self.submodules += ahb.AHB2Wishbone(ahb_targexp0, self.pbus) - def connect_uart(self, pads, n=0): - assert n in (0, 1), "this CPU has 2 built-in UARTs, 0 and 1" - self.cpu_params.update({ - f"i_UART{n}RXDI" : pads.rx, - f"o_UART{n}TXDO" : pads.tx, - f"o_UART{n}BAUDTICK" : Signal() - }) - def connect_jtag(self, pads): self.cpu_params.update( i_DAPSWDITMS = pads.tms, diff --git a/litex/soc/cores/cpu/gowin_emcu/crt0.c b/litex/soc/cores/cpu/gowin_emcu/crt0.c index cafc474c8..54415dad1 100644 --- a/litex/soc/cores/cpu/gowin_emcu/crt0.c +++ b/litex/soc/cores/cpu/gowin_emcu/crt0.c @@ -19,9 +19,6 @@ void _start(void) { for (uint32_t *x = &_fbss; x < &_ebss; x ++) *x = 0; - UART0->ctrl = 0b11; // set rx and tx enable bits - UART0->baud_div = CONFIG_CLOCK_FREQUENCY / 115200; // FIXME - __asm__("bl main"); while(1); } diff --git a/litex/soc/cores/cpu/gowin_emcu/system.h b/litex/soc/cores/cpu/gowin_emcu/system.h index c7a14e816..262446a62 100644 --- a/litex/soc/cores/cpu/gowin_emcu/system.h +++ b/litex/soc/cores/cpu/gowin_emcu/system.h @@ -12,58 +12,6 @@ void flush_l2_cache(void); void busy_wait(unsigned int ms); void busy_wait_us(unsigned int us); -#include - -// FIXME -#define CSR_UART_BASE - -struct EMCU_UART -{ - volatile uint32_t data; - volatile uint32_t state; - volatile uint32_t ctrl; - volatile uint32_t int_ctrl; - volatile uint32_t baud_div; -}; - -#define PERIPHERALS_BASE 0x40000000 -#define UART0 ((struct EMCU_UART *) (PERIPHERALS_BASE + 0x4000)) - -static inline char uart_txfull_read(void); -static inline char uart_rxempty_read(void); -static inline void uart_ev_enable_write(char c); -static inline void uart_rxtx_write(char c); -static inline char uart_rxtx_read(void); -static inline void uart_ev_pending_write(char); -static inline char uart_ev_pending_read(void); - -static inline char uart_txfull_read(void) { - return UART0->state & 0b01; -} - -static inline char uart_rxempty_read(void) { - return !(UART0->state & 0b10); -} - -static inline void uart_ev_enable_write(char c) { - // FIXME -} - -static inline void uart_rxtx_write(char c) { - UART0->data = (uint32_t) c; -} - -static inline char uart_rxtx_read(void) -{ - return (char)(UART0->data); -} - -static inline void uart_ev_pending_write(char x) {} -static inline char uart_ev_pending_read(void) { - return 0; -} - - #ifdef __cplusplus } #endif From b19d992f231699f1ac7d07b73a15deb400d23b59 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Jan 2024 11:40:25 +0100 Subject: [PATCH 421/454] inteconnect/ahb: Add specific case for 32-bit data width, fix CSR accesses with gowin_ae350. --- litex/soc/interconnect/ahb.py | 81 ++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index cee3540cd..178eeb346 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -61,39 +61,62 @@ def __init__(self, ahb, wishbone): "word" : log2_int(ahb.data_width//8), "byte" : 0 }[wishbone.addressing] + assert ahb.data_width in [32, 64] assert ahb.data_width == wishbone.data_width assert ahb.address_width == wishbone.adr_width + wishbone_adr_shift def wishbone_sel_decoder(ahb_size, ahb_addr): - wishbone_sel = Signal(8) - self.comb += Case(ahb_size, { - # 8-bit access. - 0b00 : Case(ahb_addr[0:3], { - 0b000 : wishbone_sel.eq(0b0000_0001), - 0b001 : wishbone_sel.eq(0b0000_0010), - 0b010 : wishbone_sel.eq(0b0000_0100), - 0b011 : wishbone_sel.eq(0b0000_1000), - 0b100 : wishbone_sel.eq(0b0001_0000), - 0b101 : wishbone_sel.eq(0b0010_0000), - 0b110 : wishbone_sel.eq(0b0100_0000), - 0b111 : wishbone_sel.eq(0b1000_0000), - }), - # 16-bit access. - 0b01 : Case(ahb_addr[1:3], { - 0b00 : wishbone_sel.eq(0b0000_0011), - 0b01 : wishbone_sel.eq(0b0000_1100), - 0b10 : wishbone_sel.eq(0b0011_0000), - 0b11 : wishbone_sel.eq(0b1100_0000), - }), - # 32-bit access. - 0b10 : Case(ahb_addr[2:3], { - 0b0 : wishbone_sel.eq(0b0000_1111), - 0b1 : wishbone_sel.eq(0b1111_0000), - }), - # 64-bit access. - 0b11 : wishbone_sel.eq(0b1111_1111), - }) - return wishbone_sel + if ahb.data_width == 64: + wishbone_sel = Signal(8) + self.comb += Case(ahb_size, { + # 8-bit access. + 0b00 : Case(ahb_addr[0:3], { + 0b000 : wishbone_sel.eq(0b0000_0001), + 0b001 : wishbone_sel.eq(0b0000_0010), + 0b010 : wishbone_sel.eq(0b0000_0100), + 0b011 : wishbone_sel.eq(0b0000_1000), + 0b100 : wishbone_sel.eq(0b0001_0000), + 0b101 : wishbone_sel.eq(0b0010_0000), + 0b110 : wishbone_sel.eq(0b0100_0000), + 0b111 : wishbone_sel.eq(0b1000_0000), + }), + # 16-bit access. + 0b01 : Case(ahb_addr[1:3], { + 0b00 : wishbone_sel.eq(0b0000_0011), + 0b01 : wishbone_sel.eq(0b0000_1100), + 0b10 : wishbone_sel.eq(0b0011_0000), + 0b11 : wishbone_sel.eq(0b1100_0000), + }), + # 32-bit access. + 0b10 : Case(ahb_addr[2:3], { + 0b0 : wishbone_sel.eq(0b0000_1111), + 0b1 : wishbone_sel.eq(0b1111_0000), + }), + # 64-bit access. + 0b11 : wishbone_sel.eq(0b1111_1111), + }) + return wishbone_sel + if ahb.data_width == 32: + wishbone_sel = Signal(4) + self.comb += Case(ahb_size, { + # 8-bit access. + 0b00 : Case(ahb_addr[0:2], { + 0b00 : wishbone_sel.eq(0b0001), + 0b01 : wishbone_sel.eq(0b0010), + 0b10 : wishbone_sel.eq(0b0100), + 0b11 : wishbone_sel.eq(0b1000), + }), + # 16-bit access. + 0b01 : Case(ahb_addr[1:2], { + 0b0 : wishbone_sel.eq(0b0011), + 0b1 : wishbone_sel.eq(0b1100), + }), + # 32-bit access. + 0b10 : wishbone_sel.eq(0b1111), + # 64-bit access (Should not happen but do a full 32-bit access). + 0b11 : wishbone_sel.eq(0b1111), + }) + return wishbone_sel # FSM. self.fsm = fsm = FSM() From 4222a585c920c516edec6873145356966bc6e0df Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 18 Jan 2024 15:04:09 +0100 Subject: [PATCH 422/454] soc/cores/cpu/naxriscv/core: fix arch definition --- litex/soc/cores/cpu/naxriscv/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 294974b2e..da2376258 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -69,7 +69,7 @@ def get_abi(): # Arch. @staticmethod def get_arch(): - arch = f"rv{NaxRiscv.xlen}ima" + arch = f"rv{NaxRiscv.xlen}i2p0_ma" if NaxRiscv.with_fpu: arch += "fd" if NaxRiscv.with_rvc: From f00d49211b7e54c5e90dd487bc1fea86f762494a Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 18 Jan 2024 15:21:37 +0100 Subject: [PATCH 423/454] soc/cores/cpu/naxriscv/core: force go back previous directory after git clone --- litex/soc/cores/cpu/naxriscv/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index da2376258..ca644ac80 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -302,10 +302,12 @@ def git_setup(name, dir, repo, branch, hash): ), shell=True) # Use specific SHA1 (Optional). print(f"Updating {name} Git repository...") + cwd = os.getcwd() os.chdir(os.path.join(dir)) wipe_cmd = "&& git clean --force -d -x && git reset --hard" if "wipe" in NaxRiscv.update_repo else "" checkout_cmd = f"&& git checkout {hash}" if hash is not None else "" subprocess.check_call(f"cd {dir} {wipe_cmd} && git checkout {branch} && git submodule init && git pull --recurse-submodules {checkout_cmd}", shell=True) + os.chdir(cwd) # Netlist Generation. @staticmethod From 854541d5c7b2c726ee331711a442af6d91d646ff Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Fri, 19 Jan 2024 07:37:55 +0100 Subject: [PATCH 424/454] soc/cores/cpu/naxriscv/core: adding argument to enable rvc extension --- litex/soc/cores/cpu/naxriscv/core.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index ca644ac80..a052dc6b2 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -115,6 +115,7 @@ def args_fill(parser): cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)") cpu_group.add_argument("--no-netlist-cache", action="store_true", help="Always (re-)build the netlist.") cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU.") + cpu_group.add_argument("--with-rvc", action="store_true", help="Enable the Compress ISA extension.") cpu_group.add_argument("--l2-bytes", default=128*1024, help="NaxRiscv L2 bytes, default 128 KB.") cpu_group.add_argument("--l2-ways", default=8, help="NaxRiscv L2 ways, default 8.") @@ -127,6 +128,7 @@ def args_read(args): NaxRiscv.update_repo = args.update_repo NaxRiscv.no_netlist_cache = args.no_netlist_cache NaxRiscv.with_fpu = args.with_fpu + NaxRiscv.with_rvc = args.with_rvc if args.scala_file: NaxRiscv.scala_files = args.scala_file if args.scala_args: @@ -344,6 +346,8 @@ def generate_netlist(reset_address): gen_args.append(f"--scala-file={file}") if(NaxRiscv.with_fpu): gen_args.append(f"--scala-args=rvf=true,rvd=true") + if(NaxRiscv.with_rvc): + gen_args.append(f"--scala-args=rvc=true") cmd = f"""cd {ndir} && sbt "runMain naxriscv.platform.litex.NaxGen {" ".join(gen_args)}\"""" print("NaxRiscv generation command :") From bb62f7aa63a6e1eb4ffd5658ff0b4849442a182e Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 22 Jan 2024 18:27:17 +0100 Subject: [PATCH 425/454] soc/cores/cpu/vexriscv_smp/core: allowing configure CSR/CLINT/PLIC base address by overriding default value or using args --- litex/soc/cores/cpu/vexriscv_smp/core.py | 61 ++++++++++++++---------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index 4031dc70a..62bf0bf6c 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -57,32 +57,38 @@ class VexRiscvSMP(CPU): with_rvc = False dtlb_size = 4 itlb_size = 4 + csr_base = 0xf000_0000 + clint_base = 0xf001_0000 + plic_base = 0xf0c0_0000 # Command line configuration arguments. @staticmethod def args_fill(parser): cpu_group = parser.add_argument_group(title="CPU options") - cpu_group.add_argument("--cpu-count", default=1, help="Number of CPU(s) in the cluster.", type=int) - cpu_group.add_argument("--with-coherent-dma", action="store_true", help="Enable Coherent DMA Slave interface.") - cpu_group.add_argument("--without-coherent-dma", action="store_true", help="Disable Coherent DMA Slave interface.") - cpu_group.add_argument("--dcache-width", default=None, help="L1 data cache bus width.") - cpu_group.add_argument("--icache-width", default=None, help="L1 instruction cache bus width.") - cpu_group.add_argument("--dcache-size", default=None, help="L1 data cache size in byte per CPU.") - cpu_group.add_argument("--dcache-ways", default=None, help="L1 data cache ways per CPU.") - cpu_group.add_argument("--icache-size", default=None, help="L1 instruction cache size in byte per CPU.") - cpu_group.add_argument("--icache-ways", default=None, help="L1 instruction cache ways per CPU") - cpu_group.add_argument("--aes-instruction", default=None, help="Enable AES instruction acceleration.") - cpu_group.add_argument("--without-out-of-order-decoder", action="store_true", help="Reduce area at cost of peripheral access speed") - cpu_group.add_argument("--with-wishbone-memory", action="store_true", help="Disable native LiteDRAM interface") - cpu_group.add_argument("--with-privileged-debug", action="store_true", help="Enable official RISC-V debug spec") - cpu_group.add_argument("--hardware-breakpoints", default=1, help="Number of hardware breapoints", type=int) - cpu_group.add_argument("--wishbone-force-32b", action="store_true", help="Force the wishbone bus to be 32 bits") - cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU") - cpu_group.add_argument("--cpu-per-fpu", default="4", help="Maximal ratio between CPU count and FPU count. Will instanciate as many FPU as necessary.") - cpu_group.add_argument("--with-rvc", action="store_true", help="Enable RISC-V compressed instruction support") - cpu_group.add_argument("--dtlb-size", default=4, help="Data TLB size.") - cpu_group.add_argument("--itlb-size", default=4, help="Instruction TLB size.") - cpu_group.add_argument("--expose-time", action="store_true", help="Add CLINT time output.") + cpu_group.add_argument("--cpu-count", default=1, help="Number of CPU(s) in the cluster.", type=int) + cpu_group.add_argument("--with-coherent-dma", action="store_true", help="Enable Coherent DMA Slave interface.") + cpu_group.add_argument("--without-coherent-dma", action="store_true", help="Disable Coherent DMA Slave interface.") + cpu_group.add_argument("--dcache-width", default=None, help="L1 data cache bus width.") + cpu_group.add_argument("--icache-width", default=None, help="L1 instruction cache bus width.") + cpu_group.add_argument("--dcache-size", default=None, help="L1 data cache size in byte per CPU.") + cpu_group.add_argument("--dcache-ways", default=None, help="L1 data cache ways per CPU.") + cpu_group.add_argument("--icache-size", default=None, help="L1 instruction cache size in byte per CPU.") + cpu_group.add_argument("--icache-ways", default=None, help="L1 instruction cache ways per CPU") + cpu_group.add_argument("--aes-instruction", default=None, help="Enable AES instruction acceleration.") + cpu_group.add_argument("--without-out-of-order-decoder", action="store_true", help="Reduce area at cost of peripheral access speed") + cpu_group.add_argument("--with-wishbone-memory", action="store_true", help="Disable native LiteDRAM interface") + cpu_group.add_argument("--with-privileged-debug", action="store_true", help="Enable official RISC-V debug spec") + cpu_group.add_argument("--hardware-breakpoints", default=1, help="Number of hardware breapoints", type=int) + cpu_group.add_argument("--wishbone-force-32b", action="store_true", help="Force the wishbone bus to be 32 bits") + cpu_group.add_argument("--with-fpu", action="store_true", help="Enable the F32/F64 FPU") + cpu_group.add_argument("--cpu-per-fpu", default="4", help="Maximal ratio between CPU count and FPU count. Will instanciate as many FPU as necessary.") + cpu_group.add_argument("--with-rvc", action="store_true", help="Enable RISC-V compressed instruction support") + cpu_group.add_argument("--dtlb-size", default=4, help="Data TLB size.") + cpu_group.add_argument("--itlb-size", default=4, help="Instruction TLB size.") + cpu_group.add_argument("--expose-time", action="store_true", help="Add CLINT time output.") + cpu_group.add_argument("--csr-base", default="0xf0000000", help="CSR base address.") + cpu_group.add_argument("--clint-base", default="0xf0010000", help="CLINT base address.") + cpu_group.add_argument("--plic-base", default="0xf0c00000", help="PLIC base address.") @staticmethod def args_read(args): @@ -118,8 +124,11 @@ def args_read(args): VexRiscvSMP.cpu_per_fpu = args.cpu_per_fpu if(args.with_rvc): VexRiscvSMP.with_rvc = True - if(args.dtlb_size): VexRiscvSMP.dtlb_size = int(args.dtlb_size) - if(args.itlb_size): VexRiscvSMP.itlb_size = int(args.itlb_size) + if(args.dtlb_size): VexRiscvSMP.dtlb_size = int(args.dtlb_size) + if(args.itlb_size): VexRiscvSMP.itlb_size = int(args.itlb_size) + if(args.csr_base): VexRiscvSMP.csr_base = int(args.csr_base, 16) + if(args.clint_base): VexRiscvSMP.clint_base = int(args.clint_base, 16) + if(args.plic_base): VexRiscvSMP.plic_base = int(args.plic_base, 16) # ABI. @staticmethod @@ -146,9 +155,9 @@ def mem_map(self): "rom": 0x0000_0000, "sram": 0x1000_0000, "main_ram": 0x4000_0000, - "csr": 0xf000_0000, - "clint": 0xf001_0000, - "plic": 0xf0c0_0000, + "csr": VexRiscvSMP.csr_base, + "clint": VexRiscvSMP.clint_base, + "plic": VexRiscvSMP.plic_base, } # GCC Flags. From c31ec799811419e8b4bf8a1a171904d8d39cbf0e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 23 Jan 2024 16:02:11 +0100 Subject: [PATCH 426/454] CHANGES.md: Update. --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 9efb5d1ee..e51a6ce7a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,9 @@ - interconnect/ahb : Added data_width/address_width parameters. - interconnect/ahb : Added proper byte/sel support to AHB2Wishbone. - cpu/gowin_ae350 : Added initial support. + - cpu/naxriscv : Updated arch definition and added rvc configuration parameters. + - cpu/vexriscv_smp : Added csr/clint/plic base address configuration parameters. + - liteeth/phy : Added 7-Series/Ultrascale(+) 2500BaseX PHYs. [> Changed ---------- From bcde71b051b7c13289e85f01c69dd54a6dc77df5 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 24 Jan 2024 14:59:45 +0100 Subject: [PATCH 427/454] soc/integration/soc: add_etherbone: allowing to specify local/remote IP --- litex/soc/integration/soc.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index dbce3a988..f637f6c6f 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1726,7 +1726,9 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, nrxslots = 2, rxslots_read_only = True, ntxslots = 2, txslots_write_only = False, with_timestamp = False, - with_timing_constraints = True): + with_timing_constraints = True, + local_ip = None, + remote_ip = None): # Imports from liteeth.mac import LiteEthMAC from liteeth.phy.model import LiteEthPHYModel @@ -1764,8 +1766,23 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, # Dynamic IP (if enabled). if dynamic_ip: + assert local_ip is None self.add_constant("ETH_DYNAMIC_IP") + if local_ip: + local_ip = local_ip.split(".") + self.add_constant("LOCALIP1", int(local_ip[0])) + self.add_constant("LOCALIP2", int(local_ip[1])) + self.add_constant("LOCALIP3", int(local_ip[2])) + self.add_constant("LOCALIP4", int(local_ip[3])) + + if remote_ip: + remote_ip = remote_ip.split(".") + self.add_constant("REMOTEIP1", int(remote_ip[0])) + self.add_constant("REMOTEIP2", int(remote_ip[1])) + self.add_constant("REMOTEIP3", int(remote_ip[2])) + self.add_constant("REMOTEIP4", int(remote_ip[3])) + # Software Debug if software_debug: self.add_constant("ETH_UDP_TX_DEBUG") From f543b18d026a83b6ede61d3fa36b91821810643f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 24 Jan 2024 15:28:18 +0100 Subject: [PATCH 428/454] soc/add_ethernet: Refactor local/remote_ip configuration and add basic checks for IP address length + validity. --- litex/soc/integration/soc.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index f637f6c6f..cc09c8e8c 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1769,19 +1769,17 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, assert local_ip is None self.add_constant("ETH_DYNAMIC_IP") + # Local/Remote IP Configuration (optional). + def add_ip_constants(name, ip): + _ip = ip.split(".") + assert len(_ip) == 4 + for n in range(4): + assert int(_ip[n]) < 256 + self.add_constant(f"{name}{n+1}", _ip[n]) if local_ip: - local_ip = local_ip.split(".") - self.add_constant("LOCALIP1", int(local_ip[0])) - self.add_constant("LOCALIP2", int(local_ip[1])) - self.add_constant("LOCALIP3", int(local_ip[2])) - self.add_constant("LOCALIP4", int(local_ip[3])) - + add_ip_constants("LOCALIP", local_ip) if remote_ip: - remote_ip = remote_ip.split(".") - self.add_constant("REMOTEIP1", int(remote_ip[0])) - self.add_constant("REMOTEIP2", int(remote_ip[1])) - self.add_constant("REMOTEIP3", int(remote_ip[2])) - self.add_constant("REMOTEIP4", int(remote_ip[3])) + add_ip_constants("REMOTEIP", remote_ip) # Software Debug if software_debug: From d32095540abe105fea73fc7e2d4127dc69bb2815 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 24 Jan 2024 16:06:44 +0100 Subject: [PATCH 429/454] soc/integration/soc: add_ethernet/add_ip_constants: cast str to int (avoid double quote in soc.h --- litex/soc/integration/soc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index cc09c8e8c..442ba3176 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1775,7 +1775,7 @@ def add_ip_constants(name, ip): assert len(_ip) == 4 for n in range(4): assert int(_ip[n]) < 256 - self.add_constant(f"{name}{n+1}", _ip[n]) + self.add_constant(f"{name}{n+1}", int(_ip[n])) if local_ip: add_ip_constants("LOCALIP", local_ip) if remote_ip: From 245bed719559bb93960e910ec0f98ff63288bbad Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 25 Jan 2024 17:39:12 +0100 Subject: [PATCH 430/454] soc/cores/clock/efinix: fix input clock code for trion when the input clock comes from another PLL --- litex/soc/cores/clock/efinix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index d71197107..63cca6839 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -88,7 +88,7 @@ def register_clkin(self, clkin, freq, name="", refclk_name="", lvds_input=False) self.logger.info("Clock source: {}, using EXT_CLK{}".format(block["input_clock"], clock_no)) self.platform.get_pll_resource(pll_res) else: - block["input_clock"] = "INTERNAL" + block["input_clock"] = "INTERNAL" if self.type == "TITANIUMPLL" else "CORE" block["resource"] = self.platform.get_free_pll_resource() block["input_signal"] = name self.logger.info("Clock source: {}".format(block["input_clock"])) From 488247e4f7bbbe17b01cc1f9bc4e5772586b85e8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 30 Jan 2024 09:44:52 +0100 Subject: [PATCH 431/454] build/efinix/programmer: Define EFXDBG_HOME now required by latest Efinity versions. --- litex/build/efinix/programmer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/build/efinix/programmer.py b/litex/build/efinix/programmer.py index 1b91863b4..1c42a0c9f 100644 --- a/litex/build/efinix/programmer.py +++ b/litex/build/efinix/programmer.py @@ -28,7 +28,8 @@ def __init__(self, cable_name=""): os.environ["EFINITY_HOME"] = self.efinity_path def load_bitstream(self, bitstream_file, cable_suffix=""): - os.environ['EFXPGM_HOME'] = self.efinity_path + '/pgm' + os.environ['EFXPGM_HOME'] = self.efinity_path + "/pgm" + os.environ["EFXDBG_HOME"] = self.efinity_path + "/debugger" if (subprocess.call([self.efinity_path + '/bin/python3', self.efinity_path + '/pgm/bin/efx_pgm/ftdi_program.py', bitstream_file, "-m", "jtag"], env=os.environ.copy()) != 0): From a3904ac26d595c0e86357697697c873b4f3ad1ba Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 30 Jan 2024 09:51:05 +0100 Subject: [PATCH 432/454] CHANGES.md: Update. --- CHANGES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index e51a6ce7a..769675550 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,7 +3,9 @@ [> Fixed -------- - integration/soc : Fixed typo in cpu mem_bus axi-via-wb downconvert - - interconnect/ahb/AHB2Wishbone : Fix size check that was too restrictive. + - interconnect/ahb/AHB2Wishbone : Fixed size check that was too restrictive. + - liteeth/phy/gw5rgmii : Fixed Clk assignments. + - build/efinix/programmer : Updated for compatibility with latest Efinity versions. [> Added -------- From f73fbee309b6c8c98e6cc0cd236f8ca87311c6fa Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 30 Jan 2024 10:56:55 +0100 Subject: [PATCH 433/454] cores/spi/spi_master: Improve documentation, especially on Raw/Aligned mode and CS control. --- litex/soc/cores/spi/spi_master.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/litex/soc/cores/spi/spi_master.py b/litex/soc/cores/spi/spi_master.py index 377cb4782..a7d42f9b7 100644 --- a/litex/soc/cores/spi/spi_master.py +++ b/litex/soc/cores/spi/spi_master.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2019-2020 Florent Kermarrec +# Copyright (c) 2019-2024 Florent Kermarrec # SPDX-License-Identifier: BSD-2-Clause import math @@ -18,8 +18,26 @@ class SPIMaster(LiteXModule): """4-wire SPI Master - Provides a simple and minimal hardware SPI Master with CPOL=0, CPHA=0 and build time - configurable data_width and frequency. + Implements a 4-wire SPI Master with CPOL=0 and CPHA=0, tailored for FPGA designs. It allows + configurable data_width and SPI clock frequency at build time. Supports Raw and Aligned modes + for data transfer and software-controlled Chip Select (CS) for extended SPI operations. + + Parameters: + pads (Record) : Interface pads for SPI signals. If None, a default layout is used. + data_width (int) : Maximum Data width of SPI transactions. + sys_clk_freq (int) : System clock frequency in Hz. + spi_clk_freq (int) : Desired SPI clock frequency in Hz. + with_csr (bool, optional) : Enables CSR interface if True. + mode (str, optional) : 'raw' for as-is data transfer or 'aligned' for transaction length-based alignment. + + Modes: + Raw : MOSI data is aligned to the core's data-width. Optimal for data-width matching SPI transactions. + Aligned : MOSI data is aligned based on the transaction's length. Suitable for variable-length SPI transactions. + + CS Control: + Software-controlled CS is available for scenarios requiring precise control over CS assertion, like + SPI Flash page programming or when hardware CS lines are insufficient. It allows manual CS management, + enabling complex transaction sequences and extended device communication. """ pads_layout = [("clk", 1), ("cs_n", 1), ("mosi", 1), ("miso", 1)] def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True, mode="raw"): From 4dae3a9f4da14aa602ffda87ac4c3d2682577ba1 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 29 Jan 2024 16:19:44 +1100 Subject: [PATCH 434/454] build/openfpgaloader: report command line on error Helps explain failures --- litex/build/openfpgaloader.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index 8721dcfb9..21e704bf4 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -71,4 +71,8 @@ def flash(self, address, data_file, external=False, unprotect_flash=False, verif cmd.append(str(value)) # Execute Command. - self.call(cmd) + try: + self.call(cmd) + except OSError as e: + print(' '.join(cmd)) + raise From 08189663ba5e568d1667c8743af98adda4839e8e Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Tue, 30 Jan 2024 17:15:45 +1100 Subject: [PATCH 435/454] soc/add_spi_flash: fix bios 1x mode support require both phy and flash support to enable QUAD/QPI capability. Many flash devices support 4x read but may be on a 1x phy --- litex/soc/integration/soc.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 442ba3176..385e83da1 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1909,10 +1909,11 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, self.add_constant(f"{name}_MODULE_NAME", module.name.upper()) self.add_constant(f"{name}_MODULE_TOTAL_SIZE", module.total_size) self.add_constant(f"{name}_MODULE_PAGE_SIZE", module.page_size) - 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 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") From 1dddfa6841f9e40914f735d8d589d171096a24c0 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 1 Feb 2024 09:57:51 +1100 Subject: [PATCH 436/454] soc/add_spi_flash: fix default divisor and PHY_CLOCK calculation Ensure default_divisor is set to desired default - 1 as required by LiteSPIClkGen Calculate actual PHY_CLK based on default_divisor --- litex/soc/integration/soc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 385e83da1..1031c43be 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1884,17 +1884,21 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, from litespi import LiteSPI from litespi.phy.generic import LiteSPIPHY from litespi.opcodes import SpiNorFlashOpCodes + import math # Checks/Parameters. assert mode in ["1x", "4x"] if clk_freq is None: clk_freq = self.sys_clk_freq + # From LiteSPIClkGen: clk_freq will be ``sys_clk_freq/(2*(1+div))``. + default_divisor = math.ceil(self.sys_clk_freq/(clk_freq*2))-1 + clk_freq = int(self.sys_clk_freq/(2*(1+default_divisor))) # PHY. spiflash_phy = phy if spiflash_phy is None: self.check_if_exists(f"{name}_phy") spiflash_pads = self.platform.request(name if mode == "1x" else name + mode) - spiflash_phy = LiteSPIPHY(spiflash_pads, module, device=self.platform.device, default_divisor=int(self.sys_clk_freq/clk_freq), rate=rate) + spiflash_phy = LiteSPIPHY(spiflash_pads, module, device=self.platform.device, default_divisor=default_divisor, rate=rate) self.add_module(name=f"{name}_phy", module=spiflash_phy) # Core. From 51c3cb3552a8770c817ead7c1e87d477f384effb Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 1 Feb 2024 10:01:15 +1100 Subject: [PATCH 437/454] soc/add_spi_flash: default clk_freq to 20MHz This is safer than defaulting to sys_clock / 2 if sys_clock > 100MHz clk_freq tuning will result in a faster clock if supported by hardware. --- litex/soc/integration/soc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 1031c43be..16fba83ab 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1879,7 +1879,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, self.add_constant("ETH_PHY_NO_RESET") # Disable reset from BIOS to avoid disabling Hardware Interface. # Add SPI Flash -------------------------------------------------------------------------------- - def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, phy=None, rate="1:1", software_debug=False, **kwargs): + def add_spi_flash(self, name="spiflash", 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 @@ -1888,7 +1888,6 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=None, module=None, # Checks/Parameters. assert mode in ["1x", "4x"] - if clk_freq is None: clk_freq = self.sys_clk_freq # From LiteSPIClkGen: clk_freq will be ``sys_clk_freq/(2*(1+div))``. default_divisor = math.ceil(self.sys_clk_freq/(clk_freq*2))-1 clk_freq = int(self.sys_clk_freq/(2*(1+default_divisor))) From e0416639f762b4035e22b98ed61cb7fe713c2b7c Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 1 Feb 2024 10:09:06 +1100 Subject: [PATCH 438/454] software/liblitespi/spiflash: fix reported flash clk --- litex/soc/software/liblitespi/spiflash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index 410c43948..e31f21410 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -46,13 +46,13 @@ int spiflash_freq_init(void) #endif } lowest_div++; - printf("SPI Flash clk configured to %d MHz\n", (SPIFLASH_PHY_FREQUENCY/(2*(1 + lowest_div)))/1000000); + printf("SPI Flash clk configured to %d MHz\n", CONFIG_CLOCK_FREQUENCY/(2*(1+lowest_div)*1000000)); spiflash_phy_clk_divisor_write(lowest_div); #else - printf("SPI Flash clk configured to %ld MHz\n", (unsigned long)(SPIFLASH_PHY_FREQUENCY/1e6)); + printf("SPI Flash clk configured to %ld MHz\n", SPIFLASH_PHY_FREQUENCY/1000000); #endif From 3a890a077b138d674f11841564db2042f6871827 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 1 Feb 2024 10:14:20 +1100 Subject: [PATCH 439/454] software/liblitespi/spiflash: fix clk_freq tuning with L2 cache Correct CRC was always calculated, regardless of divisor, as the test flash block was in the L2 cache. This resulted in the minimum divisor being used and incorrect flash reads with 200MHz sys_clock. --- litex/soc/software/liblitespi/spiflash.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index e31f21410..987b7493e 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -25,6 +25,8 @@ int spiflash_freq_init(void) unsigned int lowest_div, crc, crc_test; lowest_div = spiflash_phy_clk_divisor_read(); + flush_cpu_dcache(); + flush_l2_cache(); crc = crc32((unsigned char *)SPIFLASH_BASE, SPI_FLASH_BLOCK_SIZE); crc_test = crc; @@ -40,6 +42,8 @@ int spiflash_freq_init(void) while((crc == crc_test) && (lowest_div-- > 0)) { spiflash_phy_clk_divisor_write((uint32_t)lowest_div); + flush_cpu_dcache(); + flush_l2_cache(); crc_test = crc32((unsigned char *)SPIFLASH_BASE, SPI_FLASH_BLOCK_SIZE); #ifdef SPIFLASH_DEBUG printf("[DIV: %d] %08x\n\r", lowest_div, crc_test); From de594e44c983abcb32ea56c35608dc77e293e82f Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 1 Feb 2024 10:18:52 +1100 Subject: [PATCH 440/454] software/bios/cmds: fix crc command with L2 cache Same CRC was always reported if the memory region was in the cache... Noticed when manually testing spiflash divisor. --- litex/soc/software/bios/cmds/cmd_bios.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/litex/soc/software/bios/cmds/cmd_bios.c b/litex/soc/software/bios/cmds/cmd_bios.c index 2006dd540..5acf67140 100644 --- a/litex/soc/software/bios/cmds/cmd_bios.c +++ b/litex/soc/software/bios/cmds/cmd_bios.c @@ -115,6 +115,8 @@ static void crc_handler(int nb_params, char **params) return; } + flush_cpu_dcache(); + flush_l2_cache(); printf("CRC32: %08x", crc32((unsigned char *)addr, length)); } From afe7b939952d15672612716059b09f99edb0466e Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 1 Feb 2024 10:22:46 +1100 Subject: [PATCH 441/454] software/liblitespi/spiflash: fix warnings --- litex/soc/software/liblitespi/spiflash.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index 987b7493e..53bb936ef 100644 --- a/litex/soc/software/liblitespi/spiflash.c +++ b/litex/soc/software/liblitespi/spiflash.c @@ -1,6 +1,7 @@ // This file is Copyright (c) 2020 Antmicro // License: BSD +#include #include #include #include @@ -67,7 +68,7 @@ void spiflash_dummy_bits_setup(unsigned int dummy_bits) { spiflash_core_mmap_dummy_bits_write((uint32_t)dummy_bits); #ifdef SPIFLASH_DEBUG - printf("Dummy bits set to: %d\n\r", spiflash_core_mmap_dummy_bits_read()); + printf("Dummy bits set to: %" PRIx32 "\n\r", spiflash_core_mmap_dummy_bits_read()); #endif } @@ -111,7 +112,7 @@ static uint32_t transfer_byte(uint8_t b) return spiflash_core_master_rxtx_read(); } -static void transfer_cmd(uint8_t *bs, uint8_t *resp, int len) +static void transfer_cmd(volatile uint8_t *bs, volatile uint8_t *resp, int len) { spiflash_core_master_phyconfig_len_write(8); spiflash_core_master_phyconfig_width_write(1); @@ -174,7 +175,7 @@ static void page_program(uint32_t addr, uint8_t *data, int len) w_buf[1] = addr>>16; w_buf[2] = addr>>8; w_buf[3] = addr>>0; - memcpy(w_buf+4, data, len); + memcpy((void *)w_buf+4, (void *)data, len); transfer_cmd(w_buf, r_buf, len+4); } From fc85fdd178fa6711cb9055128fdc71df9ba86dd7 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Thu, 1 Feb 2024 15:51:30 +1100 Subject: [PATCH 442/454] build/openfpgaloader: support args with '-' many openfpgaloader args have a name with '-' as per normal convention. This kwarg now works: file_type="raw" --- litex/build/openfpgaloader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index 21e704bf4..8b41d3093 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -66,7 +66,7 @@ def flash(self, address, data_file, external=False, unprotect_flash=False, verif # Handle kwargs for specific, less common cases. for key, value in kwargs.items(): - cmd.append(f"--{key}") + cmd.append(f"--{key.replace('_', '-')}") if value is not None: cmd.append(str(value)) From e44631294a368a839df75c738409b29b1a4fda74 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 1 Feb 2024 08:34:17 +0100 Subject: [PATCH 443/454] CHANGES.md: Update. --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 769675550..34b60119c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ - interconnect/ahb/AHB2Wishbone : Fixed size check that was too restrictive. - liteeth/phy/gw5rgmii : Fixed Clk assignments. - build/efinix/programmer : Updated for compatibility with latest Efinity versions. + - litespi/software: : Fixed SPI Flash Clk Divider computation when with L2 Cache. [> Added -------- @@ -17,6 +18,8 @@ - cpu/naxriscv : Updated arch definition and added rvc configuration parameters. - cpu/vexriscv_smp : Added csr/clint/plic base address configuration parameters. - liteeth/phy : Added 7-Series/Ultrascale(+) 2500BaseX PHYs. + - litespi/sdrphy: : Allowed flash parameter to be None. + - litespi/integration : Improved integration and simplifications. [> Changed ---------- From e498a5669858936dd34c3681b4fa0617c2b6fa8a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 1 Feb 2024 08:42:11 +0100 Subject: [PATCH 444/454] soc/add_spi_flash: Minor integration cleanup and remove PHY_FREQUENCY constants that is no longer used. --- litex/soc/integration/soc.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 16fba83ab..53c75a4fa 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -8,6 +8,7 @@ import os import sys +import math import time import logging import argparse @@ -1884,13 +1885,11 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=20e6, module=None, from litespi import LiteSPI from litespi.phy.generic import LiteSPIPHY from litespi.opcodes import SpiNorFlashOpCodes - import math # Checks/Parameters. assert mode in ["1x", "4x"] - # From LiteSPIClkGen: clk_freq will be ``sys_clk_freq/(2*(1+div))``. - default_divisor = math.ceil(self.sys_clk_freq/(clk_freq*2))-1 - clk_freq = int(self.sys_clk_freq/(2*(1+default_divisor))) + default_divisor = math.ceil(self.sys_clk_freq/(2*clk_freq)) - 1 + clk_freq = int(self.sys_clk_freq/(2*(default_divisor + 1))) # PHY. spiflash_phy = phy @@ -1908,7 +1907,6 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=20e6, module=None, self.bus.add_slave(name=name, slave=spiflash_core.bus, region=spiflash_region) # Constants. - self.add_constant(f"{name}_PHY_FREQUENCY", clk_freq) self.add_constant(f"{name}_MODULE_NAME", module.name.upper()) self.add_constant(f"{name}_MODULE_TOTAL_SIZE", module.total_size) self.add_constant(f"{name}_MODULE_PAGE_SIZE", module.page_size) From a59b67e4ee0bca90fc95b99b8d5dce55e29ebd01 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 1 Feb 2024 08:44:52 +0100 Subject: [PATCH 445/454] soc: Avoid .upper() on add_config/constant since already done in methods. --- litex/soc/integration/soc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 53c75a4fa..ad63ce048 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1247,7 +1247,7 @@ def finalize(self): if hasattr(self, "ctrl") and self.bus.timeout is not None: if hasattr(self.ctrl, "bus_error") and hasattr(self.bus._interconnect, "timeout"): self.comb += self.ctrl.bus_error.eq(self.bus._interconnect.timeout.error) - self.add_config("BUS_STANDARD", self.bus.standard.upper()) + self.add_config("BUS_STANDARD", self.bus.standard) self.add_config("BUS_DATA_WIDTH", self.bus.data_width) self.add_config("BUS_ADDRESS_WIDTH", self.bus.address_width) self.add_config("BUS_BURSTING", int(self.bus.bursting)) @@ -1907,7 +1907,7 @@ def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=20e6, module=None, self.bus.add_slave(name=name, slave=spiflash_core.bus, region=spiflash_region) # Constants. - self.add_constant(f"{name}_MODULE_NAME", module.name.upper()) + 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" ]: From d9f006e123ed6991578466cf3740305cd4b6eb6b Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 5 Feb 2024 10:38:24 +1100 Subject: [PATCH 446/454] litex/build/efinix: add spi_width Doesn't seem needed for Trion but probably essential for Titanium? --- litex/build/efinix/efinity.py | 2 +- litex/build/efinix/platform.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 04f6df610..5fdd4ea1f 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -361,7 +361,7 @@ def run_script(self, script): "--io_weak_pullup", "on", "--enable_roms", "on", "--mode", self.platform.spi_mode, - "--width", "1", + "--width", self.platform.spi_width, "--enable_crc_check", "on" ], common.colors) if r != 0: diff --git a/litex/build/efinix/platform.py b/litex/build/efinix/platform.py index 1dc76fb90..52d1fc4cc 100644 --- a/litex/build/efinix/platform.py +++ b/litex/build/efinix/platform.py @@ -23,13 +23,14 @@ class EfinixPlatform(GenericPlatform): _supported_toolchains = ["efinity"] - def __init__(self, *args, iobank_info=None, toolchain="efinity", spi_mode="active", **kwargs): + def __init__(self, *args, iobank_info=None, toolchain="efinity", spi_mode="active", spi_width="1", **kwargs): GenericPlatform.__init__(self, *args, **kwargs) self.timing_model = self.device[-2:] self.device = self.device[:-2] self.iobank_info = iobank_info self.spi_mode = spi_mode + self.spi_width = spi_width if self.device[:2] == "Ti": self.family = "Titanium" else: From f81c940e7bb123d0fbc4c7eeacc01e8418a938c2 Mon Sep 17 00:00:00 2001 From: Andrew Dennison Date: Mon, 5 Feb 2024 10:40:04 +1100 Subject: [PATCH 447/454] litex/build/efinix: add binary output This is the file required for passive SPI loading. --- litex/build/efinix/efinity.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/litex/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 5fdd4ea1f..2e0b79963 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -366,3 +366,14 @@ def run_script(self, script): ], common.colors) if r != 0: raise OSError("Error occurred during efx_pgm execution.") + + # BINARY + os.environ['EFXPGM_HOME'] = self.efinity_path + "/pgm" + r = tools.subprocess_call_filtered([self.efinity_path + "/bin/python3", + self.efinity_path + "/pgm/bin/efx_pgm/export_bitstream.py", + "hex_to_bin", + f"{self._build_name}.hex", + f"{self._build_name}.bin" + ], common.colors) + if r != 0: + raise OSError("Error occurred during export_bitstream execution.") From 3127e504d3ae509317b801918813dbccb621197e Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 5 Feb 2024 11:45:34 +0100 Subject: [PATCH 448/454] soc/integration: Allow 0x400 CSR paging It's a convenient way to get more CSR locations without changing the whole address space layout (i.e. more space for CSR). It still leaves 256 full 32b registers in each location which I've never encountered a device even coming close to this, so it should be fairly safe to do. This doesn't change the default, just allow the user to select it. Signed-off-by: Sylvain Munaut --- litex/soc/integration/soc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index ad63ce048..0f0b4edce 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -652,7 +652,7 @@ class SoCCSRHandler(SoCLocHandler): supported_data_width = [8, 32] supported_address_width = [14+i for i in range(4)] supported_alignment = [32] - supported_paging = [0x800*2**i for i in range(4)] + supported_paging = [0x400*2**i for i in range(5)] supported_ordering = ["big", "little"] # Creation ------------------------------------------------------------------------------------- From 57bc0369c728c3666f51c3da9281c122132ee594 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 5 Feb 2024 12:57:06 +0100 Subject: [PATCH 449/454] integration/soc/SocCSRHandler: Make supported_address_width/paging values explicit. --- litex/soc/integration/soc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 0f0b4edce..22c1d50c5 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -650,9 +650,9 @@ def __str__(self): class SoCCSRHandler(SoCLocHandler): supported_data_width = [8, 32] - supported_address_width = [14+i for i in range(4)] + supported_address_width = [14, 15, 16, 17, 18] supported_alignment = [32] - supported_paging = [0x400*2**i for i in range(5)] + supported_paging = [0x400, 0x800, 0x1000, 0x2000, 0x4000] supported_ordering = ["big", "little"] # Creation ------------------------------------------------------------------------------------- From 13c57e8304d8c685268be67400a66a5f7c08c4a2 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 7 Feb 2024 07:20:31 +0100 Subject: [PATCH 450/454] soc/integration/soc: add_etherbone/ClockDomainRenamer: keep sys connected to sys instead of eth rx --- litex/soc/integration/soc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 22c1d50c5..6f85dfb47 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1834,8 +1834,7 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, # Use PHY's eth_tx/eth_rx clock domains. ethcore = ClockDomainsRenamer({ "eth_tx": phy_cd + "_tx", - "eth_rx": phy_cd + "_rx", - "sys": phy_cd + "_rx"})(ethcore) + "eth_rx": phy_cd + "_rx"})(ethcore) self.add_module(name=f"ethcore_{name}", module=ethcore) etherbone_cd = "sys" From e866892798237eddd8ef52d5298b3d4a6d9544d7 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 7 Feb 2024 11:16:12 +0100 Subject: [PATCH 451/454] soc/software/bios/boot: allow to override macaddr by using constant MACADDRx --- litex/soc/software/bios/boot.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/soc/software/bios/boot.c b/litex/soc/software/bios/boot.c index 34079b69d..7c62409e4 100755 --- a/litex/soc/software/bios/boot.c +++ b/litex/soc/software/bios/boot.c @@ -304,7 +304,11 @@ int serialboot(void) #define TFTP_SERVER_PORT 69 #endif +#ifdef MACADDR1 +static unsigned char macadr[6] = {MACADDR1, MACADDR2, MACADDR3, MACADDR4, MACADDR5, MACADDR6}; +#else static unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00}; +#endif #ifdef LOCALIP1 static unsigned int local_ip[4] = {LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4}; From 177df0b57e4307ff7875ea70dcf44048890d0e87 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 7 Feb 2024 11:18:21 +0100 Subject: [PATCH 452/454] soc/integration/soc: move add_ip_constant to helpers with a renaming to add_ip_address_constants, adding function to add MACADDRx constant --- litex/soc/integration/soc.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 6f85dfb47..85cba9003 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -41,6 +41,18 @@ def build_time(with_time=True): fmt = "%Y-%m-%d %H:%M:%S" if with_time else "%Y-%m-%d" return datetime.datetime.fromtimestamp(time.time()).strftime(fmt) +def add_ip_address_constants(soc, name, ip_address): + _ip_address = ip_address.split(".") + assert len(_ip_address) == 4 + for n in range(4): + assert int(_ip_address[n]) < 256 + soc.add_constant(f"{name}{n+1}", int(_ip_address[n])) + +def add_mac_address_constants(soc, name, mac_address): + assert mac_address < 2**48 + for n in range(6): + soc.add_constant(f"{name}{n+1}", (mac_address >> ((5 - n) * 8)) & 0xff) + # SoCError ----------------------------------------------------------------------------------------- class SoCError(Exception): @@ -1771,16 +1783,10 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, self.add_constant("ETH_DYNAMIC_IP") # Local/Remote IP Configuration (optional). - def add_ip_constants(name, ip): - _ip = ip.split(".") - assert len(_ip) == 4 - for n in range(4): - assert int(_ip[n]) < 256 - self.add_constant(f"{name}{n+1}", int(_ip[n])) if local_ip: - add_ip_constants("LOCALIP", local_ip) + add_ip_address_constants(self, "LOCALIP", local_ip) if remote_ip: - add_ip_constants("REMOTEIP", remote_ip) + add_ip_address_constants(self, "REMOTEIP", remote_ip) # Software Debug if software_debug: From 7f211048ac39f6ac0b8f52590a619576e2695cb5 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 7 Feb 2024 11:21:49 +0100 Subject: [PATCH 453/454] soc/integration/soc/add_etherbone: adding ethernet mac address, local/remote ip as parameters, sanity check when hybrid mode and adding ip/mac constants --- litex/soc/integration/soc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 85cba9003..5c465d5ad 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1809,6 +1809,9 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, mac_address = 0x10e2d5000000, ip_address = "192.168.1.50", + ethernet_mac_address = 0x10e2d5000001, + ethernet_local_ip = "192.168.1.51", + ethernet_remote_ip = "192.168.1.100", arp_entries = 1, udp_port = 1234, buffer_depth = 16, @@ -1871,6 +1874,9 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, # Ethernet MAC (CPU). if with_ethmac: + assert mac_address != ethernet_mac_address + assert ip_address != ethernet_local_ip + self.check_if_exists("ethmac") ethcore.autocsr_exclude = {"mac"} # Software Interface. @@ -1884,6 +1890,10 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, self.add_constant("ETH_PHY_NO_RESET") # Disable reset from BIOS to avoid disabling Hardware Interface. + add_ip_address_constants(self, "LOCALIP", ethernet_local_ip) + add_ip_address_constants(self, "REMOTEIP", ethernet_remote_ip) + add_mac_address_constants(self, "MACADDR", ethernet_mac_address) + # Add SPI Flash -------------------------------------------------------------------------------- def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=20e6, module=None, phy=None, rate="1:1", software_debug=False, **kwargs): # Imports. From afcf78f6433a7f274e9791833d210e44ce6c0162 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 7 Feb 2024 19:21:38 +0100 Subject: [PATCH 454/454] soc/add_etherbone: Rename ethmac parameters with ethmac suffix since related to ethmac. --- litex/soc/integration/soc.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 5c465d5ad..121d3b691 100644 --- a/litex/soc/integration/soc.py +++ b/litex/soc/integration/soc.py @@ -1809,15 +1809,16 @@ def add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, mac_address = 0x10e2d5000000, ip_address = "192.168.1.50", - ethernet_mac_address = 0x10e2d5000001, - ethernet_local_ip = "192.168.1.51", - ethernet_remote_ip = "192.168.1.100", arp_entries = 1, udp_port = 1234, buffer_depth = 16, with_ip_broadcast = True, with_timing_constraints = True, - with_ethmac = False): + with_ethmac = False, + ethmac_address = 0x10e2d5000001, + ethmac_local_ip = "192.168.1.51", + ethmac_remote_ip = "192.168.1.100"): + # Imports from liteeth.core import LiteEthUDPIPCore from liteeth.frontend.etherbone import LiteEthEtherbone @@ -1874,8 +1875,8 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, # Ethernet MAC (CPU). if with_ethmac: - assert mac_address != ethernet_mac_address - assert ip_address != ethernet_local_ip + assert mac_address != ethmac_address + assert ip_address != ethmac_local_ip self.check_if_exists("ethmac") ethcore.autocsr_exclude = {"mac"} @@ -1890,9 +1891,9 @@ def add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, self.add_constant("ETH_PHY_NO_RESET") # Disable reset from BIOS to avoid disabling Hardware Interface. - add_ip_address_constants(self, "LOCALIP", ethernet_local_ip) - add_ip_address_constants(self, "REMOTEIP", ethernet_remote_ip) - add_mac_address_constants(self, "MACADDR", ethernet_mac_address) + add_ip_address_constants(self, "LOCALIP", ethmac_local_ip) + add_ip_address_constants(self, "REMOTEIP", ethmac_remote_ip) + add_mac_address_constants(self, "MACADDR", ethmac_address) # Add SPI Flash -------------------------------------------------------------------------------- def add_spi_flash(self, name="spiflash", mode="4x", clk_freq=20e6, module=None, phy=None, rate="1:1", software_debug=False, **kwargs):