Commit 37a37e2a authored by Ille, Ondrej, Ing.'s avatar Ille, Ondrej, Ing.

Added implementation of synchronous RX Buffer RAM read.

Added separate wrapper for inferred RAM memory.
parent 08ac9f45
--------------------------------------------------------------------------------
--
-- 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;
......@@ -159,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(
......@@ -316,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;
......@@ -439,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;
......@@ -545,8 +569,8 @@ begin
-- When buffer is empty the word on address of read pointer is not valid,
-- provide zeroes instead
----------------------------------------------------------------------------
rx_read_buff <= read_mem_word when (rx_empty_int = '0')
else
rx_read_buff <= RAM_data_out when (rx_empty_int = '0')
else
(OTHERS => '0');
......@@ -678,7 +702,7 @@ begin
----------------------------------------------------------------
if (read_frame_counter = 0) then
read_frame_counter <=
to_integer(unsigned(read_mem_word(RWCNT_H downto
to_integer(unsigned(RAM_data_out(RWCNT_H downto
RWCNT_L)));
else
......@@ -867,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;
--------------------------------------------------------------------
......@@ -950,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
......@@ -992,32 +1027,47 @@ 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
);
read_mem_word <= (OTHERS => '0');
-- Memory written either on regular write or Extra timestamp write
RAM_write <= '1' when (write_raw_OK or write_extra_ts) else
'0';
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;
-- Reading memory word
read_mem_word <= memory(read_pointer);
-- Write address is given by write pointer
RAM_write_address <= std_logic_vector(to_unsigned(
memory_write_pointer, RAM_write_address'length));
end if;
end process;
----------------------------------------------------------------------------
-- 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));
----------------------------------------------------------------------------
......@@ -1041,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
----------------------------------------------------------------------------
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment