Merge branch 'master' into jtag

# Conflicts:
#	litex/soc/cores/cpu/vexriscv_smp/core.py
This commit is contained in:
Dolu1990 2024-02-13 10:41:26 +01:00
commit 0a315cda2d
33 changed files with 1120 additions and 338 deletions

View File

@ -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
-------------------------------------------

View File

@ -1,7 +1,7 @@
<p align="center"><img src="https://raw.githubusercontent.com/enjoy-digital/litex/master/doc/litex.png"></p>
```
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)

View File

@ -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.")

View File

@ -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

View File

@ -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:

View File

@ -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):

View File

@ -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:

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -5,8 +5,6 @@
# Copyright (c) 2022 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import os
from migen import *
from litex.gen import *

View File

@ -0,0 +1 @@
from litex.soc.cores.cpu.gowin_ae350.core import GowinAE350

View File

@ -0,0 +1,4 @@
.section .text, "ax", @progbits
.global boot_helper
boot_helper:
jr x13

View File

@ -0,0 +1,308 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2024 Gwenhael Goavec-Merou <gwenhael@enjoy-digital.fr>
# Copyright (c) 2024 Florent Kermarrec <florent@enjoy-digital.fr>
# 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)

View File

@ -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

View File

@ -0,0 +1,4 @@
#ifndef __IRQ_H
#define __IRQ_H
#endif /* __IRQ_H */

View File

@ -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 */

View File

@ -2,52 +2,18 @@
# This file is part of LiteX.
#
# Copyright (c) 2021 Ilia Sergachev <ilia.sergachev@protonmail.ch>
# Copyright (c) 2024 Florent Kermarrec <florent@enjoy-digital.fr>
# 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,

View File

@ -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"
);

View File

@ -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 <stdint.h>
// 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

View File

@ -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 :")

View File

@ -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.

View File

@ -1,7 +1,7 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2019-2020 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2019-2024 Florent Kermarrec <florent@enjoy-digital.fr>
# 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"):

View File

@ -2,7 +2,7 @@
# This file is part of LiteX.
#
# This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
# This file is Copyright (c) 2015-2021 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2015-2024 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2018-2019 Antmicro <www.antmicro.com>
# This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
# This file is Copyright (c) 2016-2017 Tim 'mithro' Ansell <mithro@mithis.com>
@ -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.

View File

@ -2,7 +2,7 @@
# This file is part of LiteX.
#
# This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
# This file is Copyright (c) 2014-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2014-2024 Florent Kermarrec <florent@enjoy-digital.fr>
# This file is Copyright (c) 2018 Dolu1990 <charles.papon.90@gmail.com>
# This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
# This file is Copyright (c) 2018 Jean-François Nguyen <jf@lambdaconcept.fr>
@ -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 --------------------------------------------------------------------------------------

View File

@ -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")

View File

@ -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)

View File

@ -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};

View File

@ -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));
}

View File

@ -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,

View File

@ -1,6 +1,7 @@
// This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
// License: BSD
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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);
}

View File

@ -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",