-------------------------------------------------------------------------------
---Circular Memory to save sensor data
+-- Circular Memory to buffer sensor data
+-- Maximum address width is limited by used amount of block memory
-- Note that writing into a full buffer will overwrite parts of the old data
---T. Weber, University Mainz
+-- T. Weber, University Mainz
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
);
port(
clk : in std_logic; -- clock input
- rst : in std_logic; -- reset
+ rst : in std_logic; -- reset
wr_en : in std_logic; -- write enable
data_in : in std_logic_vector(g_datawidth - 1 downto 0); -- input word
rd_en : in std_logic; --read enable
empty : out std_logic; --empty flag
full : out std_logic; --full flag
almost_empty : out std_logic; --one more word remaining in buffer
- almost_full : out std_logic; --one more word to write before buffer overflow
- fillcnt : out std_logic_vector(g_addresswidth downto 0); -- number of words in circular buffer
+ fillcnt : out std_logic_vector(g_addresswidth - 1 downto 0); -- number of words in circular buffer
inword_freq : out std_logic_vector(31 downto 0); -- number of input words per second
outword_freq : out std_logic_vector(31 downto 0) -- number of output words per second
);
component RAM_DP_8192_32 is
port (
- WrAddress : in std_logic_vector(11 downto 0);
- RdAddress : in std_logic_vector(11 downto 0);
+ WrAddress : in std_logic_vector(12 downto 0);
+ RdAddress : in std_logic_vector(12 downto 0);
Data : in std_logic_vector(31 downto 0);
WE : in std_logic;
RdClock : in std_logic;
signal inword_counter, outword_counter : unsigned(31 downto 0) := (others => '0');
--read and write pointers
- constant c_high_address : integer := 2**g_addresswidth;
- signal readpointer : integer range 0 to c_high_address - 1 := 0;
- signal writepointer : integer range 0 to c_high_address - 1 := 0;
- signal words_in_buffer : integer range 0 to c_high_address := 0;
- signal read_write_pointer_offset : integer range -(c_high_address - 1) to c_high_address - 1 := 0;
+ constant c_ram_addresswidth : integer := 13;
+ constant c_capacity : integer := 2**g_addresswidth;
+ constant c_capacity2 : integer := 2**g_addresswidth - 2;
+ constant zeros : std_logic_vector(c_ram_addresswidth - 1 downto 0) := (others => '0');
+ signal readpointer : unsigned(g_addresswidth - 1 downto 0) := (others => '0');
+ signal writepointer : unsigned(g_addresswidth - 1 downto 0) := (others => '0');
+ signal fill_cnt_i : unsigned(g_addresswidth - 1 downto 0) := (others => '0');
+ signal read_write_pointer_offset : integer range -(c_capacity - 1) to c_capacity - 1 := 0;
--wires to block memory
signal WrEn_mem : std_logic;
- signal WrAddr_mem : std_logic_vector(g_addresswidth - 1 downto 0);
- signal Din_mem : std_logic_vector(g_datawidth - 1 downto 0);
- signal ReAddr_mem : std_logic_vector(g_addresswidth - 1 downto 0);
- signal Dout_mem : std_logic_vector(g_datawidth - 1 downto 0);
-
- signal empty_i : std_logic;
- signal full_i : std_logic;
- signal rd_en_i : std_logic;
- signal wr_en_i : std_logic;
+ signal WrAddr_mem : std_logic_vector(12 downto 0);
+ signal Din_mem : std_logic_vector(31 downto 0);
+ signal ReAddr_mem : std_logic_vector(12 downto 0);
+ signal Dout_mem : std_logic_vector(31 downto 0);
+ signal fallthrough_en : std_logic;
+ signal Dout_fall : std_logic_vector(31 downto 0);
+
+ signal empty_i : std_logic := '0';
+ signal almost_empty_i : std_logic := '0';
+ signal full_i : std_logic := '0';
+ signal rd_en_i : std_logic := '0';
+ signal wr_en_i : std_logic := '0';
signal increment_wd_cnt : std_logic := '0';
- signal decrement_wd_cnt : std_logic := '0';
+ signal decrement_wd_cnt : std_logic_vector(1 downto 0) := "00";
+ signal read_last : std_logic := '0';
begin
- RAM_DP_4096_32_1: entity work.RAM_DP_8192_32
- port map (
- WrAddress => WrAddr_mem,
- RdAddress => ReAddr_mem,
- Data => Din_mem,
- WE => WrEn_mem,
- RdClock => clk,
- RdClockEn => '1',
- Reset => rst,
- WrClock => clk,
- WrClockEn => '1',
- Q => Dout_mem);
-
- write_proc : process(clk) is
- begin
- if rising_edge(clk) then
- if rst = '1' then
- writepointer <= 0;
- increment_wd_cnt <= '0';
- else
- if wr_en_i = '1' then
- increment_wd_cnt <= '1';
- if writepointer = c_high_address - 1 then
- writepointer <= 0;
- else
- writepointer <= writepointer + 1;
- end if;
- else
- writepointer <= writepointer;
- increment_wd_cnt <= '0';
- end if;
- end if;
- end if;
- end process write_proc;
+ assert g_addresswidth < 14 report "address width of circular buffer has to be smaller than 14" severity failure;
+ assert g_datawidth = 32 report "data width of trb is 32 bit" severity failure;
- WrAddr_mem <= std_logic_vector(to_unsigned(writepointer, g_addresswidth));
+ rd_en_i <= not empty_i and rd_en;
+ wr_en_i <= (wr_en and not full_i) when g_boundedbuf = true else wr_en;
+
+RAM_DP_4096_32_1: entity work.RAM_DP_8192_32
+ port map (
+ WrAddress => WrAddr_mem,
+ RdAddress => ReAddr_mem,
+ Data => Din_mem,
+ WE => WrEn_mem,
+ RdClock => clk,
+ RdClockEn => '1',
+ Reset => rst,
+ WrClock => clk,
+ WrClockEn => '1',
+ Q => Dout_mem);
+
+ n_gen: if g_addresswidth = c_ram_addresswidth generate
+ WrAddr_mem <= std_logic_vector(writepointer);
+ ReAddr_mem <= std_logic_vector(readpointer);
+ end generate n_gen;
+ sim_gen: if g_addresswidth < c_ram_addresswidth generate
+ -- below is when simulating with smaller ram addresses
+ WrAddr_mem <= zeros(c_ram_addresswidth - 1 downto writepointer'length) & std_logic_vector(writepointer);
+ ReAddr_mem <= zeros(c_ram_addresswidth - 1 downto readpointer'length) & std_logic_vector(readpointer);
+ end generate sim_gen;
Din_mem <= data_in;
WrEn_mem <= wr_en_i;
+ -- precompute
read_write_offset_proc : process(offset, writepointer) is
begin
- read_write_pointer_offset <= writepointer - to_integer(unsigned(offset)) after 2 ns;
+ read_write_pointer_offset <= to_integer(writepointer) - to_integer(unsigned(offset)) after 2 ns;
end process read_write_offset_proc;
- read_proc : process(clk) is
+ -- update pointers to memory locations
+ pointer_proc : process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
- readpointer <= 0;
- decrement_wd_cnt <= '0';
+ writepointer <= (others => '0');
+ readpointer <= (others => '0');
else
- if offset_en = '1' then
- if read_write_pointer_offset >= 0 then
- readpointer <= read_write_pointer_offset;
- else
- readpointer <= c_high_address + read_write_pointer_offset;
+ if full_i = '0' then
+ readpointer <= readpointer;
+ writepointer <= writepointer;
+ if wr_en_i = '1' then -- update write pointer
+ writepointer <= writepointer + 1;
end if;
- elsif rd_en_i = '1' then
- decrement_wd_cnt <= '1';
- if readpointer = c_high_address - 1 then
- readpointer <= 0;
- else
+ if rd_en_i = '1' then -- update read pointer
readpointer <= readpointer + 1;
end if;
else
- decrement_wd_cnt <= '0';
- readpointer <= readpointer;
+ if wr_en_i = '1' then -- update read and write counter
+ writepointer <= writepointer + 1;
+ readpointer <= readpointer + 1;
+ elsif rd_en_i = '1' then -- update read counter
+ readpointer <= readpointer + 1;
+ else -- do nothing
+ readpointer <= readpointer;
+ writepointer <= writepointer;
+ end if;
+ end if; -- end full
+ -- react on offset enable
+ if offset_en = '1' then
+ if read_write_pointer_offset >= 0 then
+ readpointer <= to_unsigned(read_write_pointer_offset, g_addresswidth);
+ else
+ readpointer <= to_unsigned(c_capacity + read_write_pointer_offset, g_addresswidth);
+ end if;
end if;
- end if;
- end if;
- end process read_proc;
+ end if; -- end rst
+ end if; -- end clk
+ end process;
- ReAddr_mem <= std_logic_vector(to_unsigned(readpointer, g_addresswidth));
-
- word_counter_proc : process(clk) is
+ -- word fall through for equal write and read pointer
+ fallthrough_proc : process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
- words_in_buffer <= 0;
- elsif offset_en = '1' then
- words_in_buffer <= to_integer(unsigned(offset));
+ Dout_fall <= (others => '0');
+ fallthrough_en <= '0';
else
- words_in_buffer <= words_in_buffer;
- if increment_wd_cnt = '1' and decrement_wd_cnt = '0' then
- if words_in_buffer < c_high_address then
- words_in_buffer <= words_in_buffer + 1;
- else
- words_in_buffer <= words_in_buffer;
- end if;
- elsif increment_wd_cnt = '0' and decrement_wd_cnt = '1' then
- if words_in_buffer > 0 then
- words_in_buffer <= words_in_buffer - 1;
- else
- words_in_buffer <= 0;
- end if;
+ fallthrough_en <= '0';
+ if wr_en_i = '1' and readpointer = writepointer then
+ Dout_fall <= data_in;
+ fallthrough_en <= '1';
end if;
end if;
end if;
- end process word_counter_proc;
+ end process;
+ -- compute number of data elements in buffer
+ fill_cnt_proc : process(readpointer, writepointer)
+ begin
+ if writepointer > readpointer then
+ fill_cnt_i <= writepointer - readpointer;
+ elsif writepointer < readpointer then
+ fill_cnt_i <= c_capacity - (readpointer - writepointer);
+ else
+ fill_cnt_i <= (others => '0');
+ end if;
+ end process fill_cnt_proc;
+
+ -- count read/write frequency
throughput_proc : process (clk) is
begin
if rising_edge(clk) then
end if;
end process throughput_proc;
- empty_i <= '1' when words_in_buffer = 0 else '0';
- full_i <= '1' when words_in_buffer = c_high_address else '0';
- rd_en_i <= not empty_i and rd_en;
- wr_en_i <= (wr_en and not full_i) when g_boundedbuf = true else wr_en;
+ empty_i <= '1' when readpointer = writepointer else '0';
+ full_i <= '1' when to_integer(fill_cnt_i) = c_capacity2 else '0';
+ -- outputs
empty <= empty_i;
- almost_empty <= '1' when (words_in_buffer < 3) else '0';
full <= full_i;
- almost_full <= '1' when words_in_buffer >= c_high_address - 1 else '0';
- fillcnt <= std_logic_vector(to_unsigned(words_in_buffer, g_addresswidth + 1));
- data_out <= Dout_mem;
+ almost_empty <= '1' when fill_cnt_i < 2 else '0';
+ fillcnt <= std_logic_vector(fill_cnt_i);
+ data_out <= Dout_mem when fallthrough_en = '0' else Dout_fall;
end architecture RTL;
-- Readout Controller for Circular Memory
-- Tobias Weber
-- Ruhr Unversitaet Bochum
-------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-----------------------------------------------------------------------------
--- mode = 0: read single word from buffer, return 0x0 if empty
+-- mode = 0: read single word from buffer, return 0x0 if empty
-- the frame header and trailer are missing in this mode
-- mode = 1: read until buffer empty or maximum of words to read
-- mode = 2: wait for words after trigger, set read offset and start reading
);
port(
clk : in std_logic; -- clock input
- rst : in std_logic; -- reset input
+ rst : in std_logic; -- reset input
start : in std_logic; -- start reading
mode : in std_logic_vector(1 downto 0); -- readout mode
writes_after_trig : in std_logic_vector(g_addresswidth - 1 downto 0); -- clock cycles after trigger before starting readout (needs to be at least two)
constant c_frame_start : std_logic_vector(g_datawidth - 1 downto 0) := x"FABEABBA";
constant c_frame_end : std_logic_vector(g_datawidth - 1 downto 0) := x"BEEFBEEF";
- --readout state type, in mode 1, 2 a header and trailer will be put
+ --readout state type, in mode 1, 2 a header and trailer will be put
--at beginning and end of readout frame
type t_readout_state_type is (idle, header, read_single, read, wait_memory, wait_trigger, trailer);
signal readout_fsm : t_readout_state_type := idle;
when header =>
busy <= '1';
data_valid <= '1';
- headercounter <= headercounter + 1;
case headercounter is
when 0 =>
- data_out <= c_frame_start;
+ data_out <= c_frame_start;
+ headercounter <= 1;
when 1 =>
- data_out <= sensor_id;
+ data_out <= sensor_id;
+ headercounter <= 2;
when 2 =>
data_out <= std_logic_vector(framecounter);
framecounter <= framecounter + 1;
busy <= '1';
data_valid <= '1';
readout_fsm <= trailer;
- trailercounter <= trailercounter + 1;
if trailercounter = 0 then
+ trailercounter <= 1;
data_out(g_addresswidth - 1 downto 0) <= std_logic_vector(wordcounter);
else
data_out <= c_frame_end;