Commit fbd496c1 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

eca: remove read-first memory dependency (not supported by arria5)

parent f3298f17
......@@ -7,7 +7,7 @@ files = [
"eca_pkg.vhd",
"eca_sdp.vhd",
"eca_search.vhd",
"eca_tdp.vhd",
"eca_flags.vhd",
"eca_walker.vhd",
"eca_wb_channel.vhd",
"eca_wb_event.vhd",
......
......@@ -103,12 +103,10 @@ architecture rtl of eca_channel is
subtype t_queue_index is std_logic_vector(c_queue_index_bits -1 downto 0);
subtype t_table_lo_index is std_logic_vector(c_table_lo_index_bits-1 downto 0);
subtype t_counter is std_logic_vector(c_counter_bits -1 downto 0);
subtype t_queue_data is std_logic_vector(c_table_lo_index_bits downto 0);
type t_table_index_array is array(natural range <>) of t_table_index;
type t_queue_index_array is array(natural range <>) of t_queue_index;
type t_table_lo_index_array is array(natural range <>) of t_table_lo_index;
type t_queue_data_array is array(natural range <>) of t_queue_data;
constant c_free_last_index : t_free_index := (others => '1');
constant c_last_time : t_time := (others => '1');
......@@ -145,11 +143,9 @@ architecture rtl of eca_channel is
signal q_scan_valid : std_logic_vector (c_scanners-1 downto 0);
signal q_scan_time : t_queue_index_array (c_scanners-1 downto 0);
signal q_scan_index : t_table_lo_index_array(c_scanners-1 downto 0);
signal q_scan_data : t_queue_data_array (c_scanners-1 downto 0);
signal q_dispatch_valid : std_logic_vector (c_scanners-1 downto 0);
signal q_dispatch_time : t_queue_index_array (c_scanners-1 downto 0);
signal q_dispatch_index : t_table_lo_index_array(c_scanners-1 downto 0);
signal q_dispatch_data : t_queue_data_array (c_scanners-1 downto 0);
-- TableS signals
signal ts_manage_write : std_logic_vector (c_scanners-1 downto 0);
......@@ -242,31 +238,23 @@ architecture rtl of eca_channel is
begin
-- Write conflicts can happen.
-- However, because c_table_lo_index_bits < c_queue_index_bits, any conflict
-- Write conflicts could happen, but we eliminate the race with a hazard guard.
-- Futhermore, because c_table_lo_index_bits < c_queue_index_bits, any conflict
-- will be rewritten before the Q rolls over.
Qx : for table_hi_idx in 0 to c_scanners-1 generate
q_scan_data(table_hi_idx)(t_table_lo_index'range) <= q_scan_index(table_hi_idx);
q_scan_data(table_hi_idx)(t_table_lo_index'length) <= '1';
q_dispatch_index(table_hi_idx) <= q_dispatch_data(table_hi_idx)(t_table_lo_index'range);
q_dispatch_valid(table_hi_idx) <= q_dispatch_data(table_hi_idx)(t_table_lo_index'length);
Q : eca_tdp
Q : eca_flags
generic map(
g_addr_bits => c_queue_index_bits,
g_data_bits => c_table_lo_index_bits+1)
g_data_bits => c_table_lo_index_bits)
port map(
a_clk_i => clk_i,
a_addr_i => q_scan_time (table_hi_idx),
aw_en_i => q_scan_valid (table_hi_idx),
aw_data_i => q_scan_data (table_hi_idx),
ar_data_o => open,
b_clk_i => clk_i,
b_addr_i => q_dispatch_time(table_hi_idx),
bw_en_i => '1',
bw_data_i => (others => '0'),
br_data_o => q_dispatch_data(table_hi_idx));
clk_i => clk_i,
a_addr_i => q_scan_time (table_hi_idx),
a_en_i => q_scan_valid(table_hi_idx),
a_data_i => q_scan_index(table_hi_idx),
b_addr_i => q_dispatch_time (table_hi_idx),
b_full_o => q_dispatch_valid(table_hi_idx),
b_data_o => q_dispatch_index(table_hi_idx));
end generate;
......@@ -510,7 +498,7 @@ begin
manage_index <= counter(manage_index'range);
elsif dispatch_manage_kill = '1' then
manage_index <= dispatch_manage_index;
elsif manage_free = '1' then -- new-data bypass for old-data memory
elsif manage_free = '1' then -- new-data bypass
manage_index <= manage_freed;
else
manage_index <= fr_manage_alloc;
......
--! @file eca_flags.vhd
--! @brief ECA Flag memory
--! @author Wesley W. Terpstra <w.terpstra@gsi.de>
--!
--! Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH
--!
--! Channels require a component with these operations:
--! Random access store (for scanner)
--! Sequential read+clear (for dispatcher)
--!
--! To implement read+clear requires a read+write port.
--! Thus we need 2 write ports and 1 read port, a costly component in general.
--! Fortunately, because the reads are (mostly) sequential, we can get by with
--! two dual ported RAMs. When the sequential reading hiccups, we opt to fail
--! to report data rather than fail to clear already read data. A hiccup in the
--! sequence correponds to a clock jump, where the ECA cannot guarantee timely
--! delivery anyway. Therefore, prefer to keep the free list correct instead.
--!
--------------------------------------------------------------------------------
--! This library is free software; you can redistribute it and/or
--! modify it under the terms of the GNU Lesser General Public
--! License as published by the Free Software Foundation; either
--! version 3 of the License, or (at your option) any later version.
--!
--! This library is distributed in the hope that it will be useful,
--! but WITHOUT ANY WARRANTY; without even the implied warranty of
--! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--! Lesser General Public License for more details.
--!
--! You should have received a copy of the GNU Lesser General Public
--! License along with this library. If not, see <http://www.gnu.org/licenses/>.
---------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.eca_pkg.all;
use work.genram_pkg.all;
-- Registers its inputs. Async outputs.
entity eca_flags is
generic(
g_addr_bits : natural := 8;
g_data_bits : natural := 8);
port(
clk_i : in std_logic;
-- Port A: random access store/fill
a_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
a_en_i : in std_logic;
a_data_i : in std_logic_vector(g_data_bits-1 downto 0);
-- Port B: sequential read/clear
b_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
b_full_o : out std_logic;
b_data_o : out std_logic_vector(g_data_bits-1 downto 0));
end eca_flags;
architecture rtl of eca_flags is
signal last_addr : std_logic_vector(g_addr_bits-1 downto 0);
signal execute : std_logic;
signal q0a_w, q1a_w, q0b_w, q1b_w : std_logic;
signal q0a_a, q1a_a, q0b_a, q1b_a : std_logic_vector(g_addr_bits-1 downto 1);
signal q0a_d, q1a_d, q0b_d, q1b_d : std_logic_vector(g_data_bits downto 0);
begin
Q0 : generic_dpram
generic map(
g_data_width => g_data_bits+1,
g_size => 2**(g_addr_bits-1),
g_with_byte_enable => false,
g_addr_conflict_resolution => "dont_care", -- this file's raison d'etre
g_dual_clock => false)
port map(
clka_i => clk_i,
bwea_i => (others => '1'),
wea_i => q0a_w,
aa_i => q0a_a,
da_i => q0a_d,
qa_o => open,
clkb_i => clk_i,
bweb_i => (others => '1'),
web_i => q0b_w,
ab_i => q0b_a,
db_i => (others => '0'),
qb_o => q0b_d);
Q1 : generic_dpram
generic map(
g_data_width => g_data_bits+1,
g_size => 2**(g_addr_bits-1),
g_with_byte_enable => false,
g_addr_conflict_resolution => "dont_care", -- this file's raison d'etre
g_dual_clock => false)
port map(
clka_i => clk_i,
bwea_i => (others => '1'),
wea_i => q1a_w,
aa_i => q1a_a,
da_i => q1a_d,
qa_o => open,
clkb_i => clk_i,
bweb_i => (others => '1'),
web_i => q1b_w,
ab_i => q1b_a,
db_i => (others => '0'),
qb_o => q1b_d);
-- Chip select based on random access low bit
q0a_w <= a_en_i and not a_addr_i(0);
q1a_w <= a_en_i and a_addr_i(0);
q0a_a <= a_addr_i(g_addr_bits-1 downto 1);
q1a_a <= a_addr_i(g_addr_bits-1 downto 1);
q0a_d <= '1' & a_data_i;
q1a_d <= '1' & a_data_i;
-- If the address switched banks (continuous clock), execute request
execute <= b_addr_i(0) xor last_addr(0);
main : process(clk_i) is
begin
if rising_edge(clk_i) then
q0b_w <= execute and not b_addr_i(0);
q1b_w <= execute and b_addr_i(0);
last_addr <= b_addr_i;
end if;
end process;
q0b_a <= last_addr(g_addr_bits-1 downto 1) when q0b_w='1' else b_addr_i(g_addr_bits-1 downto 1);
q1b_a <= last_addr(g_addr_bits-1 downto 1) when q1b_w='1' else b_addr_i(g_addr_bits-1 downto 1);
b_data_o <= q0b_d(g_data_bits-1 downto 0) when last_addr(0) = '0' else q1b_d(g_data_bits-1 downto 0);
b_full_o <= (q0b_d(g_data_bits) and q0b_w) or (q1b_d(g_data_bits) and q1b_w);
end rtl;
......@@ -201,30 +201,24 @@ package eca_pkg is
end component;
-- Registers its inputs. Async outputs.
-- When aw_en_i=1, ar_data_o returns old data (not aw_data_i).
-- When a_clk_i=b_clk_i, aw_en_i=1, bw_en_i=0, and a_addr_i=b_addr_i,
-- then br_data_o returns old data (not aw_data_i).
-- When a_clk_i /= b_clk_i, aw_en_i=1, bw_en_i=0, and a_addr_i=b_addr_i,
-- then br_data_o is undefined.
-- When aw_en_i=bw_en_i=1 and a_addr_i=b_addr_i, the cell is corrupted.
-- !!! unsupported by Arria5. Fuck. !!!
component eca_tdp is
component eca_flags is
generic(
g_addr_bits : natural := 8;
g_data_bits : natural := 8);
port(
a_clk_i : in std_logic;
a_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
aw_en_i : in std_logic;
aw_data_i : in std_logic_vector(g_data_bits-1 downto 0);
ar_data_o : out std_logic_vector(g_data_bits-1 downto 0);
clk_i : in std_logic;
b_clk_i : in std_logic;
b_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
bw_en_i : in std_logic;
bw_data_i : in std_logic_vector(g_data_bits-1 downto 0);
br_data_o : out std_logic_vector(g_data_bits-1 downto 0));
-- Port A: random access store/fill
a_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
a_en_i : in std_logic;
a_data_i : in std_logic_vector(g_data_bits-1 downto 0);
-- Port B: sequential read/clear
b_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
b_full_o : out std_logic;
b_data_o : out std_logic_vector(g_data_bits-1 downto 0));
end component;
-- Expects registers for inputs. Async outputs.
-- c1_o is available after 1 cycle (2 once registered)
......
--! @file eca_tdp.vhd
--! @brief ECA True dual-ported memory
--! @author Wesley W. Terpstra <w.terpstra@gsi.de>
--!
--! Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH
--!
--! Unfortunately, this requires Arria2 due to "old-data" behaviour.
--! Will replace this in the future.
--!
--------------------------------------------------------------------------------
--! This library is free software; you can redistribute it and/or
--! modify it under the terms of the GNU Lesser General Public
--! License as published by the Free Software Foundation; either
--! version 3 of the License, or (at your option) any later version.
--!
--! This library is distributed in the hope that it will be useful,
--! but WITHOUT ANY WARRANTY; without even the implied warranty of
--! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
--! Lesser General Public License for more details.
--!
--! You should have received a copy of the GNU Lesser General Public
--! License along with this library. If not, see <http://www.gnu.org/licenses/>.
---------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.eca_pkg.all;
-- Registers its inputs. Async outputs.
-- When aw_en_i=1, ar_data_o returns old data (not aw_data_i).
-- When a_clk_i=b_clk_i, aw_en_i=1, bw_en_i=0, and a_addr_i=b_addr_i,
-- then br_data_o returns old data (not aw_data_i).
-- When a_clk_i /= b_clk_i, aw_en_i=1, bw_en_i=0, and a_addr_i=b_addr_i,
-- then br_data_o is undefined.
-- When aw_en_i=bw_en_i=1 and a_addr_i=b_addr_i, the cell is corrupted.
entity eca_tdp is
generic(
g_addr_bits : natural := 8;
g_data_bits : natural := 8);
port(
a_clk_i : in std_logic;
a_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
aw_en_i : in std_logic;
aw_data_i : in std_logic_vector(g_data_bits-1 downto 0);
ar_data_o : out std_logic_vector(g_data_bits-1 downto 0);
b_clk_i : in std_logic;
b_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
bw_en_i : in std_logic;
bw_data_i : in std_logic_vector(g_data_bits-1 downto 0);
br_data_o : out std_logic_vector(g_data_bits-1 downto 0));
end eca_tdp;
architecture rtl of eca_tdp is
type ram_t is array(2**g_addr_bits-1 downto 0) of
std_logic_vector(g_data_bits-1 downto 0);
signal ram : ram_t := (others => (others => '0'));
begin
a : process(a_clk_i)
begin
if rising_edge(a_clk_i) then
ar_data_o <= ram(to_integer(unsigned(a_addr_i)));
if aw_en_i = '1' then
ram(to_integer(unsigned(a_addr_i))) <= aw_data_i;
end if;
end if;
end process;
b : process(b_clk_i)
begin
if rising_edge(b_clk_i) then
br_data_o <= ram(to_integer(unsigned(b_addr_i)));
if bw_en_i = '1' then
ram(to_integer(unsigned(b_addr_i))) <= bw_data_i;
end if;
end if;
end process;
end rtl;
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