Merge pull request #2007 from enjoy-digital/ctu-can-fd
Add initial CTU-CAN-FD core support.
This commit is contained in:
commit
7ec35eb4c5
|
@ -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)
|
|
@ -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
|
|
@ -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"]:
|
||||||
|
|
Loading…
Reference in New Issue