Merge branch 'master' into jtag
# Conflicts: # litex/soc/cores/cpu/vexriscv_smp/core.py
This commit is contained in:
commit
0a315cda2d
38
CHANGES.md
38
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
|
||||
-------------------------------------------
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from litex.soc.cores.cpu.gowin_ae350.core import GowinAE350
|
|
@ -0,0 +1,4 @@
|
|||
.section .text, "ax", @progbits
|
||||
.global boot_helper
|
||||
boot_helper:
|
||||
jr x13
|
|
@ -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)
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef __IRQ_H
|
||||
#define __IRQ_H
|
||||
|
||||
#endif /* __IRQ_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 */
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 :")
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"):
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 --------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
44
setup.py
44
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",
|
||||
|
|
Loading…
Reference in New Issue