diff --git a/CHANGES.md b/CHANGES.md index b537e2812..f672c3d10 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,33 @@ -[> Changes since 2023.08 +[> Changes since 2023.12 ------------------------ + [> Fixed + -------- + - integration/soc : Fixed typo in cpu mem_bus axi-via-wb downconvert + - 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. + - litepcie/us(p)pciephy : Fixed x8 / 256-bit wide case. + + [> 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. + - 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. + - litespi/sdrphy: : Allowed flash parameter to be None. + - litespi/integration : Improved integration and simplifications. + - export/builder : Add import/merge of Sub-SoCs .json files. + + [> Changed + ---------- + +[> 2023.12, released on December 25th 2023 +------------------------------------------ [> Fixed -------- - liteeth/arp : Fixed response on table update. @@ -30,16 +58,20 @@ - 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. - 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. + - liteiclink : Added clk_ratio of 1:2, 1:4 on Efinix/SerWB to make clocking more flexible. [> 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/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/build/efinix/efinity.py b/litex/build/efinix/efinity.py index 04f6df610..2e0b79963 100644 --- a/litex/build/efinix/efinity.py +++ b/litex/build/efinix/efinity.py @@ -361,8 +361,19 @@ class EfinityToolchain(GenericToolchain): "--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: 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.") diff --git a/litex/build/efinix/ifacewriter.py b/litex/build/efinix/ifacewriter.py index be480cb26..5ec2a3b88 100644 --- a/litex/build/efinix/ifacewriter.py +++ b/litex/build/efinix/ifacewriter.py @@ -281,15 +281,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=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"]) - 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"]) @@ -329,7 +323,14 @@ design.create("{2}", "{3}", "./../gateware", overwrite=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) @@ -338,6 +339,9 @@ design.create("{2}", "{3}", "./../gateware", overwrite=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' @@ -349,6 +353,8 @@ design.create("{2}", "{3}", "./../gateware", overwrite=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"] @@ -358,17 +364,19 @@ design.create("{2}", "{3}", "./../gateware", overwrite=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) 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 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: 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 @@ class EfinixProgrammer(GenericProgrammer): 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): 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 @@ class GowinDDROutputImpl(Module): i_CLK = clk, i_D0 = i1, i_D1 = i2, + i_TX = 0, o_Q0 = o, + o_Q1 = Open(), ) class GowinDDROutput: 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 @@ class GowinToolchain(GenericToolchain): 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") 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 @@ class GowinPlatform(GenericPlatform): def build(self, *args, **kwargs): return self.toolchain.build(self, *args, **kwargs) + + def add_false_path_constraint(self, from_, to): + pass diff --git a/litex/build/openfpgaloader.py b/litex/build/openfpgaloader.py index c6f38ae38..8b41d3093 100644 --- a/litex/build/openfpgaloader.py +++ b/litex/build/openfpgaloader.py @@ -13,31 +13,66 @@ 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"] - self.call(cmd) + + # Handle kwargs for specific, less common cases. + for key, value in kwargs.items(): + cmd.append(f"--{key.replace('_', '-')}") + if value is not None: + cmd.append(str(value)) + + # Execute Command. + try: + self.call(cmd) + except OSError as e: + print(' '.join(cmd)) + raise diff --git a/litex/soc/cores/clock/efinix.py b/litex/soc/cores/clock/efinix.py index ba803c741..63cca6839 100644 --- a/litex/soc/cores/clock/efinix.py +++ b/litex/soc/cores/clock/efinix.py @@ -88,7 +88,7 @@ class EFINIXPLL(LiteXModule): 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"])) @@ -240,23 +240,24 @@ class EFINIXPLL(LiteXModule): # 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 @@ class EFINIXPLL(LiteXModule): "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. 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_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/cores/cpu/gowin_emcu/core.py b/litex/soc/cores/cpu/gowin_emcu/core.py index c8551b21c..d9ba87858 100644 --- a/litex/soc/cores/cpu/gowin_emcu/core.py +++ b/litex/soc/cores/cpu/gowin_emcu/core.py @@ -2,52 +2,18 @@ # 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 * from litex.gen import * -from litex.soc.interconnect import wishbone, ahb from litex.soc.cores.cpu import CPU +from litex.soc.interconnect import wishbone +from litex.soc.interconnect import ahb -# 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 --------------------------------------------------------------------------------------- +# Gowin EMCU (Enhanced MCU / Cortex M3) ------------------------------------------------------------ class GowinEMCU(CPU): variants = ["standard"] @@ -57,69 +23,155 @@ class GowinEMCU(CPU): human_name = "Gowin EMCU" data_width = 32 endianness = "little" + reset_address = 0x0000_0000 gcc_triple = "arm-none-eabi" - gcc_flags = "-mcpu=cortex-m3 -mthumb" 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, } - def __init__(self, platform, variant, *args, **kwargs): - super().__init__(*args, **kwargs) + # GCC Flags. + @property + def gcc_flags(self): + flags = f" -march=armv7-m -mthumb" + flags += f" -D__CortexM3__" + flags += f" -DUART_POLLING" + return flags - self.reset = Signal() - self.bus_reset = Signal() - bus_reset_n = Signal() - self.comb += self.bus_reset.eq(~bus_reset_n) - self.interrupt = Signal(5) - self.reset_address = self.mem_map["rom"] + 0 + def __init__(self, platform, variant="standard"): + self.platform = platform + self.reset = Signal() + self.pbus = wishbone.Interface(data_width=32, address_width=32, addressing="byte") + self.periph_buses = [self.pbus] + self.memory_buses = [] - self.gpio_in = Signal(16) - self.gpio_out = Signal(16) - self.gpio_out_en = Signal(16) + # CPU Instance. + # ------------- - self.cpu_params = dict() - self.cpu_params.update( + 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"), + i_PORESETN = ~ (ResetSignal("sys") | self.reset), + i_SYSRESETN = ~ (ResetSignal("sys") | self.reset), i_MTXREMAP = Signal(4, reset=0b1111), o_MTXHRESETN = bus_reset_n, + # RTC. + i_RTCSRCCLK = 0b0, # RTC Clk In. + + # GPIOs. + 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 = 0, + o_INTMONITOR = Open(), + + # Flash. i_FLASHERR = Signal(), i_FLASHINT = Signal(), - i_FCLK = ClockSignal("sys"), - i_PORESETN = ~self.reset, - i_SYSRESETN = ~self.reset, - i_RTCSRCCLK = Signal(), # TODO - RTC clk in + # Debug/JTAG. + o_DAPTDO = Open(), + o_DAPJTAGNSW = Open(), + o_DAPNTDOEN = Open(), + i_DAPSWDITMS = 0, + i_DAPTDI = 0, + i_DAPNTRST = 0, + i_DAPSWCLKTCK = 0, - i_IOEXPINPUTI = self.gpio_in, - o_IOEXPOUTPUTO = self.gpio_out, - o_IOEXPOUTPUTENO = self.gpio_out_en, + # 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, - i_GPINT = self.interrupt, - o_INTMONITOR = Signal(), + # 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, ) - # 32b CPU SRAM split between 8 SRAMs x 4 bit each - - sram_dw = 32 - single_sram_dw = 4 - n_srams = sram_dw // single_sram_dw + # SRAM (32-bit RAM split between 4 SRAMs x 8-bit each). + # ----------------------------------------------------- + # 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( @@ -130,61 +182,75 @@ class GowinEMCU(CPU): o_SRAM0CS = sram0_cs, ) - for i in range(n_srams): + # SRAMS Instances. + for i in range(4): 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 = 8, + p_BIT_WIDTH_1 = 8, 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], - i_CLKA = ClockSignal(), - i_CLKB = ClockSignal(), - i_RESETA = 0, - i_RESETB = self.bus_reset, + 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), + 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, + 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: - 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) 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 - - 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) + # Peripheral Bus (AHB -> Wishbone). + # --------------------------------- 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 bea687093..54415dad1 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 ++; @@ -15,33 +19,77 @@ 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); } + 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" +); diff --git a/litex/soc/cores/cpu/gowin_emcu/system.h b/litex/soc/cores/cpu/gowin_emcu/system.h index 2fc3a77d1..262446a62 100644 --- a/litex/soc/cores/cpu/gowin_emcu/system.h +++ b/litex/soc/cores/cpu/gowin_emcu/system.h @@ -5,66 +5,13 @@ 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); void busy_wait_us(unsigned int us); -#include - -// FIXME -#define CSR_UART_BASE -#define UART_POLLING - -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 diff --git a/litex/soc/cores/cpu/naxriscv/core.py b/litex/soc/cores/cpu/naxriscv/core.py index 294974b2e..a052dc6b2 100755 --- a/litex/soc/cores/cpu/naxriscv/core.py +++ b/litex/soc/cores/cpu/naxriscv/core.py @@ -69,7 +69,7 @@ class NaxRiscv(CPU): # 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: @@ -115,6 +115,7 @@ class NaxRiscv(CPU): 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 @@ class NaxRiscv(CPU): 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: @@ -302,10 +304,12 @@ class NaxRiscv(CPU): ), 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 @@ -342,6 +346,8 @@ class NaxRiscv(CPU): 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 :") diff --git a/litex/soc/cores/cpu/vexriscv_smp/core.py b/litex/soc/cores/cpu/vexriscv_smp/core.py index 6760a4b6d..776d07de1 100755 --- a/litex/soc/cores/cpu/vexriscv_smp/core.py +++ b/litex/soc/cores/cpu/vexriscv_smp/core.py @@ -58,32 +58,38 @@ class VexRiscvSMP(CPU): jtag_tap = 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.") cpu_group.add_argument("--jtag-tap", action="store_true", help="Add the jtag tap instead of jtag instruction interface") @staticmethod @@ -120,8 +126,11 @@ class VexRiscvSMP(CPU): 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) if(args.jtag_tap): VexRiscvSMP.jtag_tap = int(args.jtag_tap) # ABI. @@ -149,9 +158,9 @@ class VexRiscvSMP(CPU): "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. 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 @@ from litex.soc.interconnect.csr import * 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"): diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index 5e0595ac7..955c29293 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -2,7 +2,7 @@ # This file is part of LiteX. # # This file is Copyright (c) 2015 Sebastien Bourdeauducq -# This file is Copyright (c) 2015-2021 Florent Kermarrec +# This file is Copyright (c) 2015-2024 Florent Kermarrec # This file is Copyright (c) 2018-2019 Antmicro # This file is Copyright (c) 2018 Sergiusz Bazanski # This file is Copyright (c) 2016-2017 Tim 'mithro' Ansell @@ -127,6 +127,9 @@ class Builder: self.add_software_package(name) self.add_software_library(name) + # JSONs. + self.jsons = [] + def add_software_package(self, name, src_dir=None): if src_dir is None: src_dir = os.path.join(soc_directory, "software", name) @@ -135,6 +138,30 @@ class Builder: def add_software_library(self, name): self.software_libraries.append(name) + def add_json(self, filename, name="", origin=0): + self.jsons.append((filename, name, origin)) + + def _get_json_mem_regions(self): + mem_regions = {} + for filename, name, origin in self.jsons: + _, _, _mem_regions = export.load_csr_json(filename, name, origin) + mem_regions.update(_mem_regions) + return mem_regions + + def _get_json_constants(self): + constants = {} + for filename, name, origin in self.jsons: + _, _constants, _ = export.load_csr_json(filename, name, origin) + constants.update(_constants) + return constants + + def _get_json_csr_regions(self): + csr_regions = {} + for filename, name, origin in self.jsons: + _csr_regions, _, _ = export.load_csr_json(filename, name, origin) + csr_regions.update(_csr_regions) + return csr_regions + def _get_variables_contents(self): # Helper. variables_contents = [] @@ -147,7 +174,7 @@ class Builder: raise e # Define packages and libraries. - define("PACKAGES", " ".join(name for name, src_dir in self.software_packages)) + define("PACKAGES", " ".join(name for name, src_dir in self.software_packages)) define("PACKAGE_DIRS", " ".join(src_dir for name, src_dir in self.software_packages)) define("LIBS", " ".join(self.software_libraries)) @@ -180,6 +207,11 @@ class Builder: _create_dir(self.include_dir) _create_dir(self.generated_dir) + # Integrate JSON files. + self.soc.mem_regions.update(self._get_json_mem_regions()) + self.soc.constants.update( self._get_json_constants()) + self.soc.csr_regions.update(self._get_json_csr_regions()) + # Generate BIOS files when the SoC uses it. if with_bios: # Generate Variables to variables.mak. diff --git a/litex/soc/integration/export.py b/litex/soc/integration/export.py index 3a00b88f7..487a36041 100644 --- a/litex/soc/integration/export.py +++ b/litex/soc/integration/export.py @@ -2,7 +2,7 @@ # This file is part of LiteX. # # This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq -# This file is Copyright (c) 2014-2019 Florent Kermarrec +# This file is Copyright (c) 2014-2024 Florent Kermarrec # This file is Copyright (c) 2018 Dolu1990 # This file is Copyright (c) 2019 Gabriel L. Somlo # This file is Copyright (c) 2018 Jean-François Nguyen @@ -29,6 +29,7 @@ from sysconfig import get_platform from migen import * from litex.soc.interconnect.csr import CSRStatus +from litex.soc.integration.soc import SoCRegion from litex.build.tools import generated_banner @@ -149,7 +150,7 @@ def get_mem_header(regions): for name, region in regions.items(): r += f"#ifndef {name.upper()}_BASE\n" r += f"#define {name.upper()}_BASE 0x{region.origin:08x}L\n" - r += f"#define {name.upper()}_SIZE 0x{region.length:08x}\n" + r += f"#define {name.upper()}_SIZE 0x{region.size:08x}\n" r += "#endif\n\n" r += "#ifndef MEM_REGIONS\n" @@ -370,7 +371,7 @@ def get_i2c_header(i2c_init_values): r += "\n#endif\n" return r -# JSON Export -------------------------------------------------------------------------------------- +# JSON Export / Import ---------------------------------------------------------------------------- def get_csr_json(csr_regions={}, constants={}, mem_regions={}): alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32) @@ -382,6 +383,7 @@ def get_csr_json(csr_regions={}, constants={}, mem_regions={}): "memories": {}, } + # Get CSR Regions. for name, region in csr_regions.items(): d["csr_bases"][name] = region.origin region_origin = region.origin @@ -398,18 +400,64 @@ def get_csr_json(csr_regions={}, constants={}, mem_regions={}): } region_origin += alignment//8*_size + # Get Constants. for name, value in constants.items(): d["constants"][name.lower()] = value.lower() if isinstance(value, str) else value + # Get Mem Regions. for name, region in mem_regions.items(): d["memories"][name.lower()] = { "base": region.origin, - "size": region.length, + "size": region.size, "type": region.type, } + # Return JSON Dump. return json.dumps(d, indent=4) +class MockCSR: + def __init__(self, name, size, type): + self.name = name + self.size = size + self.type = type + +class MockCSRRegion: + def __init__(self, origin, obj): + self.origin = origin + self.obj = obj + self.busword = 32 + +def load_csr_json(filename, origin=0, name=""): + if len(name): + name += "_" + # Read File. + with open(filename, 'r') as json_file: + config_data = json.load(json_file) + + # Load CSR Regions. + csr_regions = {} + for region_name, addr in config_data.get("csr_bases", {}).items(): + csrs = [] + for csr_name, info in config_data.get("csr_registers", {}).items(): + region_prefix, _, csr_suffix = csr_name.rpartition("_") + if region_prefix.startswith(region_name): + if region_prefix == region_name: + final_name = csr_suffix + else: + final_name = f"{region_prefix[len(region_name) + 1:]}_{csr_suffix}" + csrs.append(MockCSR(final_name, info["size"], info["type"])) + csr_regions[name + region_name] = MockCSRRegion(origin + addr, csrs) + + # Load Constants. + constants = {(name + const_name).upper(): value for const_name, value in config_data.get("constants", {}).items()} + + # Load Memory Regions. + mem_regions = {} + for mem_name, info in config_data.get("memories", {}).items(): + mem_regions[name + mem_name.lower()] = SoCRegion(origin + info["base"], info["size"], info["type"]) + + # Return CSR Regions, Constants, Mem Regions. + return csr_regions, constants, mem_regions # CSV Export -------------------------------------------------------------------------------------- diff --git a/litex/soc/integration/soc.py b/litex/soc/integration/soc.py index 17fe98f79..c5c43aa7f 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 @@ -40,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): @@ -68,6 +81,7 @@ class SoCRegion: self.mode = mode self.cached = cached self.linker = linker + self.type = "" def decoder(self, bus): origin = self.origin @@ -649,9 +663,9 @@ class SoCLocHandler(LiteXModule): 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 = [0x800*2**i for i in range(4)] + supported_paging = [0x400, 0x800, 0x1000, 0x2000, 0x4000] supported_ordering = ["big", "little"] # Creation ------------------------------------------------------------------------------------- @@ -1246,7 +1260,7 @@ class SoC(LiteXModule, SoCCoreCompat): 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)) @@ -1651,9 +1665,9 @@ class LiteXSoC(SoC): 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, @@ -1726,7 +1740,9 @@ class LiteXSoC(SoC): 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 +1780,15 @@ class LiteXSoC(SoC): # Dynamic IP (if enabled). if dynamic_ip: + assert local_ip is None self.add_constant("ETH_DYNAMIC_IP") + # Local/Remote IP Configuration (optional). + if local_ip: + add_ip_address_constants(self, "LOCALIP", local_ip) + if remote_ip: + add_ip_address_constants(self, "REMOTEIP", remote_ip) + # Software Debug if software_debug: self.add_constant("ETH_UDP_TX_DEBUG") @@ -1792,7 +1815,11 @@ class LiteXSoC(SoC): 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 @@ -1819,7 +1846,8 @@ class LiteXSoC(SoC): ethcore = ClockDomainsRenamer({ "eth_tx": phy_cd + "_tx", "eth_rx": phy_cd + "_rx", - "sys": phy_cd + "_rx"})(ethcore) + "sys" : {True: "sys", False: phy_cd + "_rx"}[with_ethmac], + })(ethcore) self.add_module(name=f"ethcore_{name}", module=ethcore) etherbone_cd = "sys" @@ -1850,6 +1878,9 @@ class LiteXSoC(SoC): # Ethernet MAC (CPU). if with_ethmac: + assert mac_address != ethmac_address + assert ip_address != ethmac_local_ip + self.check_if_exists("ethmac") ethcore.autocsr_exclude = {"mac"} # Software Interface. @@ -1863,8 +1894,12 @@ class LiteXSoC(SoC): self.add_constant("ETH_PHY_NO_RESET") # Disable reset from BIOS to avoid disabling Hardware Interface. + 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=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 @@ -1872,14 +1907,15 @@ class LiteXSoC(SoC): # Checks/Parameters. assert mode in ["1x", "4x"] - if clk_freq is None: clk_freq = self.sys_clk_freq + 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 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. @@ -1890,14 +1926,14 @@ class LiteXSoC(SoC): 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_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 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") diff --git a/litex/soc/interconnect/ahb.py b/litex/soc/interconnect/ahb.py index a39d3d2e2..178eeb346 100644 --- a/litex/soc/interconnect/ahb.py +++ b/litex/soc/interconnect/ahb.py @@ -15,38 +15,37 @@ from litex.gen import * # Helpers ------------------------------------------------------------------------------------------ -class TransferType(IntEnum): +class AHBTransferType(IntEnum): """Defines types of AHB transfers.""" IDLE = 0 BUSY = 1 NONSEQUENTIAL = 2 SEQUENTIAL = 3 -# AHB Interface ------------------------------------------------------------------------------------ +# AHB Definition ----------------------------------------------------------------------------------- -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), - ("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 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): + 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,32 +61,83 @@ class AHB2Wishbone(LiteXModule): "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 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): + 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() - fsm.act("IDLE", + fsm.act("ADDRESS-PHASE", ahb.readyout.eq(1), If(ahb.sel & - (ahb.size == wishbone_adr_shift) & - (ahb.trans == TransferType.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"), + (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), + NextValue(wishbone.sel, wishbone_sel_decoder(ahb.size, ahb.addr)), + NextState("DATA-PHASE"), ) ) - fsm.act("ACT", + fsm.act("DATA-PHASE", wishbone.stb.eq(1), wishbone.cyc.eq(1), + wishbone.dat_w.eq(ahb.wdata), + 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) 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}; 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)); } diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 69fbd22af..67ca3d590 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 @@ -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, diff --git a/litex/soc/software/liblitespi/spiflash.c b/litex/soc/software/liblitespi/spiflash.c index 410c43948..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 @@ -25,6 +26,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,19 +43,21 @@ 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); #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 @@ -63,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 } @@ -107,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); @@ -170,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); } diff --git a/setup.py b/setup.py index 08af7085f..a52575a62 100755 --- a/setup.py +++ b/setup.py @@ -4,30 +4,30 @@ from setuptools import setup 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() 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.12", + 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.7", + install_requires = [ "migen", "packaging", "pyserial", "requests", ], - extras_require={ + extras_require = { "develop": [ "meson" "pexpect" @@ -35,14 +35,14 @@ setup( "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=[ + platforms = ["Any"], + keywords = "HDL ASIC FPGA hardware design", + classifiers = [ "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", "Environment :: Console", "Development Status :: 3 - Alpha", @@ -51,7 +51,7 @@ setup( "Operating System :: OS Independent", "Programming Language :: Python", ], - entry_points={ + entry_points = { "console_scripts": [ # Terminal/Server/Client. "litex_term = litex.tools.litex_term:main",