Merge pull request #2007 from enjoy-digital/ctu-can-fd

Add initial CTU-CAN-FD core support.
This commit is contained in:
enjoy-digital 2024-07-05 09:16:21 +02:00 committed by GitHub
commit 7ec35eb4c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 284 additions and 0 deletions

View File

View File

@ -0,0 +1,177 @@
#
# CTU CAN-FD Core Wrapper for LiteX.
#
# Copyright (c) 2021 Andrew Dennison <andrew@motec.com.au>
# Copyright (c) 2021-2024 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2024 Gwenhael Goavec-Merou <gwenhael@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
# Documentation at https://canbus.pages.fel.cvut.cz/
import os
import subprocess
from migen import *
from litex.gen import *
from litex.build import tools
from litex.build.vhd2v_converter import VHD2VConverter
from litex.soc.interconnect import wishbone
from litex.soc.interconnect.csr_eventmanager import *
# CTU CAN-FD ---------------------------------------------------------------------------------------
class CTUCANFD(LiteXModule, EventManager):
def __init__(self, platform, pads, timestamp=0, force_convert=False):
# Parameters.
self.platform = platform
self.pads = pads
self._force_convert = force_convert
# Wishbone Bus.
self.bus = wishbone.Interface(data_width=32)
# CSRs.
self.control = CSRStorage(32, fields=[
CSRField("reset", size=1, values=[
("``0b0``", "Normal Operation."),
("``0b1`", "Hold the Core in Reset."),
], reset=0b0),
CSRField("reserved",size=31),
])
self.status = CSRStatus(32, fields=[
CSRField("ready", size=1, values=[
("``0b0``", "Core in Reset."),
("``0b1`", "Core Ready."),
]),
])
# IRQs.
self.irq = Signal()
# CTU CAN-FD Instance ----------------------------------------------------------------------
self.core_params = dict()
# Wishbone to CTU CAN-FD Memory Bus adaptation.
self.mem_scs = mem_scs = Signal()
self.mem_srd = mem_srd = Signal()
self.mem_swr = mem_swr = Signal()
self.mem_sbe = mem_sbe = Signal(4)
self.mem_adress = mem_adress = Signal(16)
self.mem_data_in = mem_data_in = Signal(32)
self.mem_data_out = mem_data_out = Signal(32)
self.comb += [
# On Wishbone Access cycle...
mem_scs.eq(self.bus.cyc & self.bus.stb),
mem_srd.eq(mem_scs & ~self.bus.we & ~self.bus.ack),
mem_swr.eq(mem_scs & self.bus.we),
mem_sbe.eq(self.bus.sel),
# Connect data_in/out.
mem_data_in.eq(self.bus.dat_w),
self.bus.dat_r.eq(mem_data_out),
# Convert 32-bit word addressing to bytes addressing.
mem_adress.eq(Cat(Signal(2), self.bus.adr)),
]
self.sync += [
self.bus.ack.eq(0),
If(mem_scs & ~self.bus.ack, self.bus.ack.eq(1)),
]
# CTU CAN-FD Parameters.
self.core_params.update(
# Target technology (ASIC or FPGA)
#p_target_technology = C_TECH_FPGA
# TX/RX Buffers.
p_txt_buffer_count = 4, # Number of TX Buffers.
p_rx_buffer_size = 32, # RX Buffer size (in 32-bit words).
# Filter A-C.
p_sup_filtA = False,
p_sup_filtB = False,
p_sup_filtC = False,
# Range Filter.
#p_sup_filtV = False,
# Synthesize Range Filter
p_sup_range = False,
# Test registers.
p_sup_test_registers = True, # True to have access to 0x9XX Tests registers
# Traffic counters.
p_sup_traffic_ctrs = False,
# Add parity bit to TXT Buffer and RX Buffer RAMs
p_sup_parity = False,
# Number of active timestamp bits
p_active_timestamp_bits = 63,
# Reset TXT / RX Buffer RAMs
p_reset_buffer_rams = False,
)
# CTU CAN-FD Signals.
self.core_params.update(
# Clk / Rst.
i_clk_sys = ClockSignal("sys"),
i_res_n = ~(ResetSignal("sys") | self.control.fields.reset),
o_res_n_out = self.status.fields.ready,
# DFT support (ASIC only).
i_scan_enable = 0,
# Timestamp (For time based transmission / reception).
i_timestamp = timestamp,
# Memory interface.
i_scs = mem_scs,
i_srd = mem_srd,
i_swr = mem_swr,
i_sbe = mem_sbe,
i_adress = mem_adress,
i_data_in = mem_data_in,
o_data_out = mem_data_out,
# Interrupt.
o_int = self.irq,
# CAN Bus.
o_can_tx = pads.tx,
i_can_rx = pads.rx,
# Debug.
#o_test_probe = ,
)
self.comb += pads.irq.eq(self.irq)
def add_sources(self, platform):
sources = []
sdir = "CTU-CAN-FD"
cdir = os.path.dirname(__file__)
if not os.path.exists(sdir):
os.system(f"git clone https://github.com/enjoy-digital/CTU-CAN-FD")
with open(os.path.join(cdir, 'rtl_lst.txt')) as f:
for line in f:
srcfile = os.path.join(sdir, line.strip().replace('rtl', 'src'))
self.vhd2v_converter.add_source(srcfile)
def do_finalize(self):
# CAN Core instance
self.vhd2v_converter = VHD2VConverter(self.platform,
top_entity = "can_top_level",
build_dir = os.path.abspath(os.path.dirname(__file__)),
work_package = "ctu_can_fd_rtl",
force_convert = self._force_convert,
params = self.core_params,
add_instance = True,
)
# Add Sources.
self.add_sources(self.platform)

View File

@ -0,0 +1,88 @@
rtl/packages/unary_ops_pkg.vhd
rtl/packages/can_fd_register_map.vhd
rtl/packages/can_fd_frame_format.vhd
rtl/packages/id_transfer_pkg.vhd
rtl/packages/can_constants_pkg.vhd
rtl/packages/can_config_pkg.vhd
rtl/packages/can_types_pkg.vhd
rtl/txt_buffer/txt_buffer_fsm.vhd
rtl/tx_arbitrator/tx_arbitrator_fsm.vhd
rtl/tx_arbitrator/priority_decoder.vhd
rtl/tx_arbitrator/tx_arbitrator.vhd
rtl/rx_buffer/rx_buffer_pointers.vhd
rtl/rx_buffer/rx_buffer_fsm.vhd
rtl/prescaler/trigger_generator.vhd
rtl/prescaler/synchronisation_checker.vhd
rtl/prescaler/segment_end_detector.vhd
rtl/prescaler/bit_time_fsm.vhd
rtl/prescaler/bit_time_counters.vhd
rtl/prescaler/bit_time_cfg_capture.vhd
rtl/prescaler/bit_segment_meter.vhd
rtl/prescaler/prescaler.vhd
rtl/memory_registers/generated/memory_reg_rw_lock.vhd
rtl/memory_registers/generated/memory_reg_rw.vhd
rtl/memory_registers/generated/memory_reg_os_lock.vhd
rtl/memory_registers/generated/memory_reg_os.vhd
rtl/memory_registers/generated/memory_bus.vhd
rtl/memory_registers/generated/data_mux.vhd
rtl/memory_registers/generated/cmn_reg_map_pkg.vhd
rtl/memory_registers/generated/can_registers_pkg.vhd
rtl/memory_registers/generated/test_registers_reg_map.vhd
rtl/memory_registers/generated/control_registers_reg_map.vhd
rtl/memory_registers/generated/address_decoder.vhd
rtl/memory_registers/generated/access_signaler.vhd
rtl/interrupt_manager/int_module.vhd
rtl/interface/apb_ifc.vhd
rtl/interface/ahb_ifc.vhd
rtl/frame_filters/range_filter.vhd
rtl/frame_filters/bit_filter.vhd
rtl/frame_filters/frame_filters.vhd
rtl/common_blocks/sig_sync.vhd
rtl/common_blocks/shift_reg_preload.vhd
rtl/common_blocks/shift_reg_byte.vhd
rtl/common_blocks/shift_reg.vhd
rtl/common_blocks/parity_calculator.vhd
rtl/common_blocks/rst_sync.vhd
rtl/common_blocks/rst_reg.vhd
rtl/common_blocks/mux2.vhd
rtl/common_blocks/majority_decoder_3.vhd
rtl/common_blocks/inf_ram_wrapper.vhd
rtl/txt_buffer/txt_buffer_ram.vhd
rtl/rx_buffer/rx_buffer_ram.vhd
rtl/common_blocks/endian_swapper.vhd
rtl/common_blocks/dlc_decoder.vhd
rtl/common_blocks/dff_arst_ce.vhd
rtl/common_blocks/dff_arst.vhd
rtl/interrupt_manager/int_manager.vhd
rtl/common_blocks/clk_gate.vhd
rtl/txt_buffer/txt_buffer.vhd
rtl/rx_buffer/rx_buffer.vhd
rtl/memory_registers/memory_registers.vhd
rtl/can_core/tx_shift_reg.vhd
rtl/can_core/trigger_mux.vhd
rtl/can_core/rx_shift_reg.vhd
rtl/can_core/retransmitt_counter.vhd
rtl/can_core/reintegration_counter.vhd
rtl/can_core/protocol_control_fsm.vhd
rtl/can_core/operation_control.vhd
rtl/can_core/fault_confinement_rules.vhd
rtl/can_core/fault_confinement_fsm.vhd
rtl/can_core/err_detector.vhd
rtl/can_core/err_counters.vhd
rtl/can_core/fault_confinement.vhd
rtl/can_core/crc_calc.vhd
rtl/can_core/control_counter.vhd
rtl/can_core/protocol_control.vhd
rtl/can_core/can_crc.vhd
rtl/can_core/bus_traffic_counters.vhd
rtl/can_core/bit_stuffing.vhd
rtl/can_core/bit_destuffing.vhd
rtl/can_core/can_core.vhd
rtl/bus_sampling/tx_data_cache.vhd
rtl/bus_sampling/trv_delay_meas.vhd
rtl/bus_sampling/ssp_generator.vhd
rtl/bus_sampling/sample_mux.vhd
rtl/bus_sampling/data_edge_detector.vhd
rtl/bus_sampling/bit_err_detector.vhd
rtl/bus_sampling/bus_sampling.vhd
rtl/can_top_level.vhd

View File

@ -633,6 +633,25 @@ def generate_dts(d, initrd_start=None, initrd_size=None, initrd=None, root_devic
}}; }};
""".format(xadc_csr_base=d["csr_bases"]["xadc"]) """.format(xadc_csr_base=d["csr_bases"]["xadc"])
# CAN ------------------------------------------------------------------------------------------
for mem in d["memories"]:
if "can" in mem:
dts += """
{name}: can@{can_mem_base:x} {{
compatible = "ctu,ctucanfd";
reg = <0x{can_mem_base:x} 0x{can_mem_size:x}>;
interrupt-parent = <&intc0>;
interrupts = <{can_interrupt}>;
clocks = <&sys_clk>;
status = "okay";
}};
""".format(name=mem,
can_mem_base=d["memories"][mem]["base"],
can_mem_size=d["memories"][mem]["size"],
can_interrupt = int(d["constants"][f"{mem}_interrupt"]),
)
# Framebuffer ---------------------------------------------------------------------------------- # Framebuffer ----------------------------------------------------------------------------------
if "video_framebuffer" in d["csr_bases"]: if "video_framebuffer" in d["csr_bases"]: