Commit 1a552c5f authored by Ille, Ondrej, Ing.'s avatar Ille, Ondrej, Ing.

Merge branch '181-rx-buffer-ram-pipeline' into 'master'

Resolve "RX Buffer RAM pipeline"

Closes #181

See merge request illeondr/CAN_FD_IP_Core!159
parents 66f5c65b f66d25f9
--------------------------------------------------------------------------------
--
-- CTU CAN FD IP Core
-- Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com>
--
-- Project advisors and co-authors:
-- Jiri Novak <jnovak@fel.cvut.cz>
-- Pavel Pisa <pisa@cmp.felk.cvut.cz>
-- Martin Jerabek <jerabma7@fel.cvut.cz>
-- Department of Measurement (http://meas.fel.cvut.cz/)
-- Faculty of Electrical Engineering (http://www.fel.cvut.cz)
-- Czech Technical University (http://www.cvut.cz/)
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this VHDL component and associated documentation files (the "Component"),
-- to deal in the Component without restriction, including without limitation
-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
-- and/or sell copies of the Component, and to permit persons to whom the
-- Component is furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Component.
--
-- THE COMPONENT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHTHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- FROM, OUT OF OR IN CONNECTION WITH THE COMPONENT OR THE USE OR OTHER DEALINGS
-- IN THE COMPONENT.
--
-- The CAN protocol is developed by Robert Bosch GmbH and protected by patents.
-- Anybody who wants to implement this IP core on silicon has to obtain a CAN
-- protocol license from Bosch.
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Purpose:
-- RAM memory wrapper intended for use with inferred memories in FPGA
-- technologies. Supports RAM inference in Xilinx and Intel FPGAs.
-- Synchronous dual port memory with shared clock. Port A is used for
-- writes. Port B is used for reads!
--------------------------------------------------------------------------------
-- Revision History:
-- 27.9.2018 Created file
--------------------------------------------------------------------------------
Library ieee;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.ALL;
entity inf_RAM_wrapper is
generic(
-- Width of memory word (in bits)
constant word_width : natural := 32;
-- Memory depth (in words)
constant depth : natural := 32;
-- Address width (in bits)
constant address_width : natural := 8;
-- Polarity of reset
constant reset_polarity : std_logic := '1';
-- RAM content reset upon reset
constant simulation_reset : boolean := true;
-- Synchronous read
constant sync_read : boolean := true
);
port(
------------------------------------------------------------------------
-- Clock and reset
------------------------------------------------------------------------
signal clk_sys :in std_logic;
signal res_n :in std_logic;
------------------------------------------------------------------------
-- Port A - Data input
------------------------------------------------------------------------
signal addr_A :in std_logic_vector(address_width -1
downto 0);
signal write :in std_logic;
signal data_in :in std_logic_vector(word_width - 1
downto 0);
------------------------------------------------------------------------
-- Port B - Data output
------------------------------------------------------------------------
signal addr_B :in std_logic_vector(address_width - 1
downto 0);
signal data_out :out std_logic_vector(word_width - 1
downto 0)
);
end entity;
architecture rtl of inf_RAM_wrapper is
----------------------------------------------------------------------------
-- Memory definition
----------------------------------------------------------------------------
type memory_type is array(0 to depth - 1) of
std_logic_vector(word_width - 1 downto 0);
signal ram_memory : memory_type;
signal int_read_data : std_logic_vector(word_width - 1
downto 0);
begin
----------------------------------------------------------------------------
-- Memory Write access process
----------------------------------------------------------------------------
ram_write_process : process(res_n, clk_sys)
begin
if (res_n = reset_polarity) then
-- pragma translate_off
if (simulation_reset) then
ram_memory <= (OTHERS => (OTHERS => '0'));
end if;
-- pragma translate_on
elsif (rising_edge(clk_sys)) then
-- Store the data into the RAM memory
if (write = '1') then
ram_memory(to_integer(unsigned(addr_A))) <= data_in;
end if;
end if;
end process;
----------------------------------------------------------------------------
-- Memory read access
----------------------------------------------------------------------------
int_read_data <= ram_memory(to_integer(unsigned(addr_B)));
-- Synchronous read
sync_read_gen : if (sync_read) generate
ram_read_process : process(res_n, clk_sys)
begin
if (res_n = reset_polarity) then
data_out <= (OTHERS => '0');
elsif (rising_edge(clk_sys)) then
data_out <= int_read_data;
end if;
end process;
end generate;
-- Asynchronous read
async_read_gen : if (not sync_read) generate
data_out <= int_read_data;
end generate;
----------------------------------------------------------------------------
-- Assertions on size
----------------------------------------------------------------------------
assert ((word_width = 8) or
(word_width = 16) or
(word_width = 32) or
(word_width = 64) or
(word_width = 128))
report "Unsupported inferred RAM word width! " &
"Only 8, 16, 32, 64 and 128 are allowed!"
severity failure;
end architecture;
......@@ -148,6 +148,9 @@
-- 10.7.2018 Changed decoding of RWCNT field. Added exception for CAN
-- frames with DLC higher than 8, to store only 8 bytes (2 data
-- words).
-- 31.8.2018 Changed reading of RAM to be synchronous to achieve BRAM
-- inferrence on Xilinx! Added register "read_mem_word" to which
-- RAM word is read.
--------------------------------------------------------------------------------
Library ieee;
......@@ -156,6 +159,7 @@ use IEEE.numeric_std.ALL;
use work.CANconstants.all;
use work.CAN_FD_frame_format.all;
use work.CAN_FD_register_map.all;
use work.CANcomponents.all;
entity rxBuffer is
generic(
......@@ -313,6 +317,9 @@ entity rxBuffer is
-- Read Pointer (access from SW)
signal read_pointer : natural range 0 to buff_size - 1;
-- Read pointer incremented by 1 (combinationally)
signal read_pointer_inc_1 : natural range 0 to buff_size - 1;
-- Write pointer (committed, available to SW, after frame was stored)
signal write_pointer : natural range 0 to buff_size - 1;
......@@ -413,6 +420,8 @@ entity rxBuffer is
-- frame to the memory.
signal write_extra_ts : boolean;
-- RX Buffer RAM read memory word
signal read_mem_word : std_logic_vector(31 downto 0);
----------------------------------------------------------------------------
----------------------------------------------------------------------------
......@@ -434,6 +443,26 @@ entity rxBuffer is
-- beginning or end of frame.
signal timestamp_capture : std_logic_vector(63 downto 0);
----------------------------------------------------------------------------
----------------------------------------------------------------------------
-- RAM wrapper signals
----------------------------------------------------------------------------
---------------------------------------------------------------------------
-- Write control signal
signal RAM_write : std_logic;
-- Data output from port B
signal RAM_data_out : std_logic_vector(31 downto 0);
-- Write address (connected to write pointer)
signal RAM_write_address : std_logic_vector(11 downto 0);
-- Read address (connected to read pointer)
signal RAM_read_address : std_logic_vector(11 downto 0);
end entity;
......@@ -540,8 +569,8 @@ begin
-- When buffer is empty the word on address of read pointer is not valid,
-- provide zeroes instead
----------------------------------------------------------------------------
rx_read_buff <= memory(read_pointer) when (rx_empty_int = '0')
else
rx_read_buff <= RAM_data_out when (rx_empty_int = '0')
else
(OTHERS => '0');
......@@ -673,8 +702,8 @@ begin
----------------------------------------------------------------
if (read_frame_counter = 0) then
read_frame_counter <=
to_integer(unsigned(memory(read_pointer)
(RWCNT_H downto RWCNT_L)));
to_integer(unsigned(RAM_data_out(RWCNT_H downto
RWCNT_L)));
else
read_frame_counter <= read_frame_counter - 1;
......@@ -862,7 +891,7 @@ begin
-- Moving to next word by reading (if there is sth to read).
--------------------------------------------------------------------
if (read_increment) then
read_pointer <= (read_pointer + 1) mod buff_size;
read_pointer <= read_pointer_inc_1;
end if;
--------------------------------------------------------------------
......@@ -945,6 +974,17 @@ begin
end process;
----------------------------------------------------------------------------
-- Calculation of Incremented Read Pointer combinationally. This is used
-- for two things:
-- 1. Actual Increment of Read pointer during read of RX_DATA.
-- 2. Adressing RX Buffer RAM read side by incremented value to avoid one
-- clock cycle delay on "read_pointer" and thus allow bursts on read
-- from RX_DATA register!
----------------------------------------------------------------------------
read_pointer_inc_1 <= (read_pointer + 1) mod buff_size;
----------------------------------------------------------------------------
-- Calculation of data overrun flag. If FSM would like to write to the
-- memory, and there is not enough free space, data overrun flag will be
......@@ -987,28 +1027,48 @@ begin
----------------------------------------------------------------------------
-- Memory access process
----------------------------------------------------------------------------
mem_acc_proc : process(res_n, clk_sys)
begin
if (res_n = ACT_RESET) then
-- Memory is initialized to zeroes in simulation!
-- pragma translate_off
memory <= (OTHERS => (OTHERS => '0'));
-- pragma translate_on
-- RAM Memory of RX Buffer
----------------------------------------------------------------------------
rx_buf_RAM : inf_RAM_wrapper
generic map (
word_width => 32,
depth => buff_size,
address_width => RAM_write_address'length,
reset_polarity => ACT_RESET,
simulation_reset => true,
sync_read => true
)
port map(
clk_sys => clk_sys,
res_n => res_n,
addr_A => RAM_write_address,
write => RAM_write,
data_in => memory_write_data,
addr_B => RAM_read_address,
data_out => RAM_data_out
);
elsif (rising_edge(clk_sys)) then
-- Write to memory either by regular pointer or by "extra timestamp"
-- pointer.
if (write_raw_OK or write_extra_ts) then
memory(memory_write_pointer) <= memory_write_data;
end if;
-- Memory written either on regular write or Extra timestamp write
RAM_write <= '1' when (write_raw_OK or write_extra_ts) else
'0';
end if;
end process;
-- Write address is given by write pointer
RAM_write_address <= std_logic_vector(to_unsigned(
memory_write_pointer, RAM_write_address'length));
----------------------------------------------------------------------------
-- RAM read address is given by read pointers. If no transaction for read
-- of RX DATA is in progress, read pointer is given by its real value.
-- During transaction, Incremented Read pointer is chosen to avoid one clock
-- cycle delay caused by increment on read pointer!
----------------------------------------------------------------------------
RAM_read_address <= std_logic_vector(to_unsigned(
read_pointer_inc_1, RAM_read_address'length))
when (read_increment) else
std_logic_vector(to_unsigned(
read_pointer, RAM_read_address'length));
----------------------------------------------------------------------------
----------------------------------------------------------------------------
......@@ -1031,7 +1091,7 @@ begin
(buff_size = 2048) or
(buff_size = 4096))
report "Unsupported RX Buffer size! RX Buffer must be power of 2!"
severity failure;
severity failure;
----------------------------------------------------------------------------
......
......@@ -49,6 +49,7 @@
-- replaced with rec_dram_word and
-- rec_dram_addr as part of resource optimization.
-- 30.11.2017 Updated "txt_buffer" for direct access to buffer
-- 29.9.2018 Added "inf_RAM_wrapper".
--------------------------------------------------------------------------------
library ieee;
......@@ -213,6 +214,34 @@ package CANcomponents is
end component;
----------------------------------------------------------------------------
-- Inferred RAM wrapper
----------------------------------------------------------------------------
component inf_RAM_wrapper is
generic(
constant word_width : natural := 32;
constant depth : natural := 32;
constant address_width : natural := 8;
constant reset_polarity : std_logic := '1';
constant simulation_reset : boolean := true;
constant sync_read : boolean := true
);
port(
signal clk_sys :in std_logic;
signal res_n :in std_logic;
signal addr_A :in std_logic_vector(address_width -1
downto 0);
signal write :in std_logic;
signal data_in :in std_logic_vector(word_width - 1
downto 0);
signal addr_B :in std_logic_vector(address_width - 1
downto 0);
signal data_out :out std_logic_vector(word_width - 1
downto 0)
);
end component;
----------------------------------------------------------------------------
-- TXT Buffer module
----------------------------------------------------------------------------
......
......@@ -111,6 +111,10 @@
-- 21.02.2018 Removed "txt_frame_swap" since it is not needed with new,
-- priority based implementation of TX Buffers.
-- 2.6.2018 Removed "tx_time_suport".
-- 29.7.2018 Removed "RX_buff_read_first" to have only single clock
-- Avalon cycles available. Thus now there is no register
-- remaining which would require gap cycle between two cycles!
-- Burst reads are now supported!
--------------------------------------------------------------------------------
Library ieee;
......@@ -352,7 +356,6 @@ entity canfd_registers is
signal PC_state_reg_vect : std_logic_vector(6 downto 0);
-- Reading from RX buffer, detection of first cycle to move the pointer
signal RX_buff_read_first : boolean;
signal aux_data : std_logic_Vector(31 downto 0);
-- Receive Timestamp options
......@@ -742,7 +745,6 @@ begin
clr_err_ctrs
);
RX_buff_read_first <= false;
aux_data <= (OTHERS => '0');
elsif rising_edge(clk_sys) then
......@@ -784,7 +786,6 @@ begin
mode_reg ,rtsopt ,clr_err_ctrs
);
RX_buff_read_first <= false;
aux_data <= (OTHERS => '0');
else
......@@ -852,7 +853,6 @@ begin
data_out_int <= (OTHERS=>'0');
log_cmd <= (OTHERS =>'0');
RX_buff_read_first <= false;
aux_data <= (OTHERS=>'0');
sbe_reg <= sbe;
......@@ -1473,16 +1473,9 @@ begin
-- RX_DATA register
--------------------------------------------------------
when RX_DATA_ADR =>
if (RX_buff_read_first = false) then
data_out_int(RX_DATA_H downto RX_DATA_L) <=
data_out_int(RX_DATA_H downto RX_DATA_L) <=
rx_read_buff;
else
data_out_int(RX_DATA_H downto RX_DATA_L) <=
aux_data;
end if;
RX_buff_read_first <= true;
--------------------------------------------------------
-- Transciever delay adress
--------------------------------------------------------
......@@ -1733,8 +1726,7 @@ begin
COMP_TYPE_ADRESS_LOWER) = compType and
adress(ID_ADRESS_HIGHER downto ID_ADRESS_LOWER) =
std_logic_vector(to_unsigned(ID, 4)) and
adress(11 downto 0) = RX_DATA_ADR and
RX_buff_read_first = false)
adress(11 downto 0) = RX_DATA_ADR)
else
'0';
......
......@@ -75,6 +75,12 @@ set_parameter -name sup_filtC true
set_parameter -name sup_range true
set_parameter -name tx_time_sup true
set_parameter -name logger_size 64
set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT"
set_global_assignment -name STATE_MACHINE_PROCESSING "ONE-HOT"
set_global_assignment -name REMOVE_REDUNDANT_LOGIC_CELLS ON
set_global_assignment -name AUTO_RESOURCE_SHARING ON
set_global_assignment -name VHDL_FILE ../../src/Libraries/reduce_lib.vhd
set_global_assignment -name VHDL_FILE ../../src/Buffers_Message_Handling/inf_RAM_wrapper.vhd
set_global_assignment -name VHDL_FILE ../../src/endian_swap.vhd
set_global_assignment -name VHDL_FILE ../../src/Buffers_Message_Handling/priorityDecoder.vhd
set_global_assignment -name VHDL_FILE ../../src/Libraries/CANconstants.vhd
......@@ -104,8 +110,4 @@ set_global_assignment -name VHDL_FILE ../../src/Buffers_Message_Handling/message
set_global_assignment -name VHDL_FILE ../../src/ID_transfer.vhd
set_global_assignment -name VHDL_FILE ../../src/CAN_top_level.vhd
set_global_assignment -name TCL_SCRIPT_FILE ../../scripts/resource_benchmark.tcl
set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT"
set_global_assignment -name STATE_MACHINE_PROCESSING "ONE-HOT"
set_global_assignment -name REMOVE_REDUNDANT_LOGIC_CELLS ON
set_global_assignment -name AUTO_RESOURCE_SHARING ON
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
\ No newline at end of file
......@@ -67,6 +67,8 @@
-- 7.6.2018 Added "CAN_insert_TX_frame" procedure.
-- 18.6.2018 Added optimized clock_gen_proc, timestamp_gen_proc procedures.
-- 15.9.2018 Added support for message filter manipulation!
-- 27.9.2018 Added burst support for avalon access. Added option to read
-- frame from RX Buffer via burst partially!
--------------------------------------------------------------------------------
Library ieee;
......@@ -886,9 +888,50 @@ package CANtestLib is
);
----------------------------------------------------------------------------
-- Execute write access on Avalon memory bus via Avalon burst.
-- Does not support unaligned accesses. Size of the burst is given by
-- length of "w_data".
--
-- Arguments:
-- w_data Data to write (Little endian)
-- w_address Address where to start write burst.
-- stat_burst True for "stationary" burst where address should not
-- be incremented during the burst!
-- mem_bus Avalon memory bus to execute the access on.
----------------------------------------------------------------------------
procedure aval_write_burst(
constant w_data : in std_logic_vector;
constant w_address : in std_logic_vector(23 downto 0);
constant stat_burst : in boolean := false;
signal mem_bus : inout Avalon_mem_type
);
----------------------------------------------------------------------------
-- Execute read access on Avalon memory bus via Avalon burst.
-- Does not support unaligned accesses. Size of the burst is given by
-- length of "r_data".
--
-- Arguments:
-- r_data Data to be read(Little endian)
-- w_address Address where to start write burst.
-- stat_burst True for "stationary" burst where address should not
-- be incremented during the burst!
-- mem_bus Avalon memory bus to execute the access on.
----------------------------------------------------------------------------
procedure aval_read_burst(
variable r_data : out std_logic_vector;
constant r_address : in std_logic_vector(23 downto 0);
constant stat_burst : in boolean := false;
signal mem_bus : inout Avalon_mem_type
);
----------------------------------------------------------------------------
-- Execute write access to CTU CAN FD Core over Avalon Bus. If size is not
-- specified, 32 bit access is executed.
-- specified, 32 bit access is executed. If input data size is other than
-- 32 bits, burst access is executed.
--
-- Address bits meaning is following:
-- [19:16] Component type (always CAN_COMPONENT_TYPE)
......@@ -901,19 +944,23 @@ package CANtestLib is
-- w_offset Register or buffer offset (bits 11:0).
-- ID Index of CTU CAN FD Core instance (bits 15:12)
-- mem_bus Avalon memory bus to execute the access on.
-- stat_burst If Burst access is executed, address should not be
-- incremented during the burst.
----------------------------------------------------------------------------
procedure CAN_write(
constant w_data : in std_logic_vector(31 downto 0);
constant w_data : in std_logic_vector;
constant w_offset : in std_logic_vector(11 downto 0);
constant ID : in natural range 0 to 15;
signal mem_bus : inout Avalon_mem_type;
constant w_size : in aval_access_size := BIT_32
constant w_size : in aval_access_size := BIT_32;
constant stat_burst : in boolean := false
);
----------------------------------------------------------------------------
-- Execute read access from CTU CAN FD Core over Avalon Bus. If size is not
-- specified, 32 bit access is executed.
-- specified, 32 bit access is executed. If input data size is other than
-- 32 bits, burst access is executed.
--
-- Address bits meaning is following:
-- [19:16] Component type (always CAN_COMPONENT_TYPE)
......@@ -926,13 +973,16 @@ package CANtestLib is
-- r_offset Register or buffer offset (bits 11:0).
-- ID Index of CTU CAN FD Core instance (bits 15:12)
-- mem_bus Avalon memory bus to execute the access on.
-- stat_burst If Burst access is executed, address should not be
-- incremented during the burst.
----------------------------------------------------------------------------
procedure CAN_read(
variable r_data : out std_logic_vector(31 downto 0);
variable r_data : out std_logic_vector;
constant r_offset : in std_logic_vector(11 downto 0);
constant ID : in natural range 0 to 15;
signal mem_bus : inout Avalon_mem_type;
constant r_size : in aval_access_size := BIT_32
constant r_size : in aval_access_size := BIT_32;
constant stat_burst : in boolean := false
);
......@@ -2253,7 +2303,7 @@ package body CANtestLib is
function aval_is_aligned(
constant address : in std_logic_vector(23 downto 0);
constant address : in std_logic_vector;
constant size : in aval_access_size
)return boolean is
begin
......@@ -2380,35 +2430,180 @@ package body CANtestLib is
end procedure;
function aval_is_invalid_burst_size(
constant data_length : natural
) return boolean
is
begin