Commit 9e8ba342 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

eca2: conflict chaining works

parent 1f70cfe0
......@@ -303,6 +303,7 @@ package eca_internals_pkg is
time_i : in t_time;
-- Write port
wen_i : in std_logic;
stall_o : out std_logic;
deadline_i : in t_time;
idx_i : in std_logic_vector(g_log_size-1 downto 0);
ext_i : in std_logic_vector(g_ext_size-1 downto 0);
......
......@@ -30,8 +30,8 @@ library work;
use work.eca_internals_pkg.all;
-- Async logic applied inputs. Async outputs.
-- When x_en_i='1' and x_ack_o='1' the address on x_addr_i will be read with
-- output available on x_data_o the next cycle. Whatever is fed into x_data_i
-- When x_en_i='1' the address on x_addr_i will be read with output available
-- (based on x_ack_o) on x_data_o the next cycle. Whatever is fed into x_data_i
-- on that cycle will be written back to the same address.
-- The core guarantees read-new-data ordering between and within both ports.
entity eca_rmw is
......@@ -42,7 +42,7 @@ entity eca_rmw is
clk_i : in std_logic;
rst_n_i : in std_logic;
a_en_i : in std_logic;
a_ack_o : out std_logic; -- a has priority, so a_ack_o=a_en_i
a_ack_o : out std_logic; -- a has priority, so a_ack_o is a_en_i one cycle delayed
a_addr_i : in std_logic_vector(g_addr_bits-1 downto 0);
a_data_o : out std_logic_vector(g_data_bits-1 downto 0);
a_data_i : in std_logic_vector(g_data_bits-1 downto 0);
......@@ -120,9 +120,6 @@ begin
s_b_q1 <= b_en_i and b_addr_i(0);
-- Port A always wins, port B only if A does not use it
a_ack_o <= a_en_i;
b_ack_o <= b_en_i and (not a_en_i or (a_addr_i(0) xor b_addr_i(0)));
-- Is the bank used this cycle?
s_q0_ren <= s_a_q0 or s_b_q0;
s_q1_ren <= s_a_q1 or s_b_q1;
......@@ -148,9 +145,13 @@ begin
control : process(clk_i, rst_n_i) is
begin
if rst_n_i = '0' then
a_ack_o <= '0';
b_ack_o <= '0';
r_q0_wen <= '0';
r_q1_wen <= '0';
elsif rising_edge(clk_i) then
a_ack_o <= a_en_i;
b_ack_o <= b_en_i and (not a_en_i or (a_addr_i(0) xor b_addr_i(0)));
r_q0_wen <= s_q0_ren;
r_q1_wen <= s_q1_ren;
end if;
......
......@@ -53,6 +53,11 @@ architecture rtl of eca_rmw_tb is
signal b_data_o : std_logic_vector(c_data_bits-1 downto 0);
signal b_data_i : std_logic_vector(c_data_bits-1 downto 0);
signal r_a_en : std_logic;
signal r_b_en : std_logic;
signal r_a_addr : std_logic_vector(c_addr_bits-1 downto 0);
signal r_b_addr : std_logic_vector(c_addr_bits-1 downto 0);
begin
rmw : eca_rmw
......@@ -74,68 +79,67 @@ begin
b_data_i => b_data_i);
test : process(clk_i, rst_n_i) is
type t_memory is array(c_depth-1 downto 0) of std_logic_vector(c_data_bits-1 downto 0);
variable s1, s2 : positive := 42;
variable v_memory : t_memory := (others => (others => '0'));
variable a_en0 : std_logic;
variable a_en1 : std_logic;
variable a_addr0 : std_logic_vector(c_addr_bits-1 downto 0);
variable a_addr1 : std_logic_vector(c_addr_bits-1 downto 0);
type t_memory is array(c_depth-1 downto 0) of std_logic_vector(c_data_bits-1 downto 0);
variable v_memory : t_memory := (others => (others => '-'));
variable a_en : std_logic;
variable a_addr : std_logic_vector(c_addr_bits-1 downto 0);
variable a_data : std_logic_vector(c_data_bits-1 downto 0);
variable b_en : std_logic;
variable b_addr : std_logic_vector(c_addr_bits-1 downto 0);
variable b_data : std_logic_vector(c_data_bits-1 downto 0);
variable a_data : std_logic_vector(c_data_bits-1 downto 0);
variable b_en0 : std_logic;
variable b_en1 : std_logic;
variable b_addr0 : std_logic_vector(c_addr_bits-1 downto 0);
variable b_addr1 : std_logic_vector(c_addr_bits-1 downto 0);
variable b_data : std_logic_vector(c_data_bits-1 downto 0);
begin
if rst_n_i = '0' then
a_en1 := '0';
b_en1 := '0';
a_en_i <= '0';
b_en_i <= '0';
elsif falling_edge(clk_i) then
r_a_en <= '0';
r_b_en <= '0';
elsif rising_edge(clk_i) then
-- Check output
assert a_ack_o = a_en_i report "Port A did not get priority" severity failure;
assert a_addr1 /= b_addr1 or a_en1 = '0' or b_en1 = '0' report "Unblocked A-B data race" severity failure;
assert a_ack_o = r_a_en report "Port A did not get priority" severity failure;
assert (b_ack_o and not r_b_en) = '0' report "Port B got priority without asking" severity failure;
assert r_a_addr /= r_b_addr or a_ack_o = '0' or b_ack_o = '0' report "Unblocked A-B data race" severity failure;
-- Correct behaviour is: write-before-read both within and between ports
if a_en1 = '1' then
v_memory(to_integer(unsigned(a_addr1))) := a_data_i;
-- Check read-outs
if a_ack_o = '1' then
assert a_data_o = v_memory(to_integer(unsigned(r_a_addr))) report "unexpected A readout" severity failure;
end if;
if b_en1 = '1' then
v_memory(to_integer(unsigned(b_addr1))) := b_data_i;
if b_ack_o = '1' then
assert b_data_o = v_memory(to_integer(unsigned(r_b_addr))) report "unexpected B readout" severity failure;
end if;
-- Check read-outs
-- Update write-back
if a_ack_o = '1' then
assert a_data_o = v_memory(to_integer(unsigned(a_addr0))) report "unexpected A readout" severity failure;
v_memory(to_integer(unsigned(r_a_addr))) := a_data_i;
end if;
if b_ack_o = '1' then
assert b_data_o = v_memory(to_integer(unsigned(b_addr0))) report "unexpected B readout" severity failure;
v_memory(to_integer(unsigned(r_b_addr))) := b_data_i;
end if;
-- Pick random values
a_en1 := a_ack_o;
b_en1 := b_ack_o;
a_addr1 := a_addr_i;
b_addr1 := b_addr_i;
p_eca_uniform(s1, s2, a_en0);
p_eca_uniform(s1, s2, b_en0);
p_eca_uniform(s1, s2, a_addr0);
p_eca_uniform(s1, s2, b_addr0);
p_eca_uniform(s1, s2, a_en);
p_eca_uniform(s1, s2, b_en);
p_eca_uniform(s1, s2, a_addr);
p_eca_uniform(s1, s2, b_addr);
p_eca_uniform(s1, s2, a_data);
p_eca_uniform(s1, s2, b_data);
-- Control the tested unit
a_en_i <= a_en0;
b_en_i <= b_en0;
a_addr_i <= a_addr0;
b_addr_i <= b_addr0;
a_en_i <= a_en;
b_en_i <= b_en;
a_addr_i <= a_addr;
b_addr_i <= b_addr;
a_data_i <= a_data;
b_data_i <= b_data;
r_a_en <= a_en_i;
r_b_en <= b_en_i;
r_a_addr <= a_addr_i;
r_b_addr <= b_addr_i;
end if;
end process;
......
......@@ -44,6 +44,7 @@ entity eca_scan is
time_i : in t_time;
-- Write port
wen_i : in std_logic;
stall_o : out std_logic;
deadline_i : in t_time;
idx_i : in std_logic_vector(g_log_size-1 downto 0);
ext_i : in std_logic_vector(g_ext_size-1 downto 0);
......@@ -109,6 +110,9 @@ architecture rtl of eca_scan is
signal r_wen2 : std_logic := '0';
signal r_wen3 : std_logic := '0';
signal s_ready : std_logic;
signal r_reset : std_logic_vector(g_log_size downto 0) := (others => '0');
signal r_deadline1 : std_logic_vector(t_time'length downto 0);
signal r_output2 : std_logic_vector(t_time'length downto 0);
signal r_count3 : std_logic_vector(t_time'length downto 0);
......@@ -131,6 +135,8 @@ architecture rtl of eca_scan is
signal r_stb : std_logic := '0';
signal s_weno : std_logic;
signal s_b_wen : std_logic;
signal s_b_addr : std_logic_vector(g_log_size-1 downto 0);
signal s_idxo : std_logic_vector(g_log_size-1 downto 0);
signal r_idxo : std_logic_vector(g_log_size-1 downto 0) := (others => '0');
signal s_valido : std_logic;
......@@ -153,6 +159,17 @@ begin
report "g_log_size does not match target latency"
severity failure;
-- Reset wipes memory
s_ready <= r_reset(r_reset'high);
reset : process(rst_n_i, clk_i) is
begin
if rst_n_i = '0' then
r_reset <= (others => '0');
elsif rising_edge(clk_i) then
r_reset <= f_eca_add(r_reset, not s_ready);
end if;
end process;
-- Compensate for pipeline delay with an adjusted clock
time : process(rst_n_i, clk_i) is
begin
......@@ -167,6 +184,7 @@ begin
end if;
end process;
-- Clear the write-enable registers
input_wen : process(clk_i, rst_n_i) is
begin
if rst_n_i = '0' then
......@@ -174,12 +192,13 @@ begin
r_wen2 <= '0';
r_wen3 <= '0';
elsif rising_edge(clk_i) then
r_wen1 <= wen_i;
r_wen1 <= wen_i and s_ready;
r_wen2 <= r_wen1;
r_wen3 <= r_wen2;
end if;
end process;
-- Calculate number of times to count-down until we output the value
input_deadline : process(clk_i) is
begin
if rising_edge(clk_i) then
......@@ -222,12 +241,15 @@ begin
a_addr_i => r_idx3,
a_data_i => s_ai,
a_data_o => open,
b_wen_i => s_weno,
b_addr_i => s_idxo,
b_wen_i => s_b_wen,
b_addr_i => s_b_addr,
b_data_i => s_bi,
b_data_o => s_bo_raw);
-- !!! clear on reset?, using port a (will wipe faster than free)
-- Inject writes during reset
s_b_wen <= not s_ready or s_weno;
s_b_addr <= f_eca_mux(s_ready, s_idxo, r_reset(g_log_size-1 downto 0));
s_ai(c_valid) <= '1';
s_ai(c_late) <= s_late3;
s_ai(c_early) <= s_early3;
......@@ -239,8 +261,13 @@ begin
bypass : process(clk_i) is
begin
if rising_edge(clk_i) then
r_bypass <= r_wen3 and f_eca_eq(r_idx3, s_idxo);
r_ai <= s_ai;
if s_ready = '1' then
r_bypass <= r_wen3 and f_eca_eq(r_idx3, s_idxo);
r_ai <= s_ai;
else
r_bypass <= '1';
r_ai <= (others => '0');
end if;
end if;
end process;
s_bo <= f_eca_mux(r_bypass, r_ai, s_bo_raw);
......@@ -289,4 +316,6 @@ begin
end if;
end process;
stall_o <= not s_ready;
end rtl;
......@@ -44,6 +44,7 @@ architecture rtl of eca_scan_tb is
signal r_time : t_time := (others => '0');
signal r_wen : std_logic := '0';
signal s_stall : std_logic;
signal r_deadline : t_time;
signal r_idx : std_logic_vector(c_log_size-1 downto 0);
signal r_ext : std_logic_vector(c_ext_size-1 downto 0);
......@@ -68,6 +69,7 @@ begin
rst_n_i => rst_n_i,
time_i => r_time,
wen_i => r_wen,
stall_o => s_stall,
deadline_i => r_deadline,
idx_i => r_idx,
ext_i => r_ext,
......@@ -100,13 +102,13 @@ begin
p_eca_uniform(s1, s2, ext);
p_eca_uniform(s1, s2, index);
-- !!! insert a few that are with less added => s_late
deadline := f_eca_add(f_eca_add(r_time, offset), 2**c_log_latency + 6*(2**c_log_multiplier));
wen := f_eca_and(deadlines(to_integer(unsigned(index))));
if wen = '1' then
deadlines(to_integer(unsigned(index))) := deadline;
-- Record deadline
if r_wen = '1' and s_stall = '0' then
deadlines(to_integer(unsigned(r_idx))) := r_deadline;
end if;
deadline := f_eca_add(f_eca_add(r_time, offset), 2**c_log_latency + 6*(2**c_log_multiplier));
wen := f_eca_and(deadlines(to_integer(unsigned(index))));
r_time <= f_eca_add(r_time, 2**c_log_multiplier);
r_wen <= wen;
r_deadline <= deadline;
......
......@@ -54,7 +54,7 @@ architecture rtl of eca_sdp is
constant c_undef : std_logic_vector(g_data_bits-1 downto 0) := (others => 'X');
type t_memory is array(c_depth-1 downto 0) of std_logic_vector(g_data_bits-1 downto 0);
signal r_memory : t_memory := (others => (others => '0')); -- !!!
signal r_memory : t_memory := (others => (others => '-'));
signal r_bypass : std_logic := '0';
signal w_data : std_logic_vector(g_data_bits-1 downto 0);
signal r_data : std_logic_vector(g_data_bits-1 downto 0);
......
This diff is collapsed.
......@@ -39,9 +39,11 @@ architecture rtl of eca_tag_channel_tb is
constant c_log_size : natural := 1 + g_case; -- smaller => tests edge cases better
constant c_log_multiplier : natural := g_case mod 3;
constant c_log_latency : natural := c_log_size + c_log_multiplier + 1;
constant c_log_latency : natural := c_log_size + c_log_multiplier; -- !!! test: +1,0,-1
constant c_ticks : natural := 2**c_log_multiplier;
signal r_time : t_time := (others => '0');
signal r_stall : std_logic;
signal r_channel : t_channel := c_idle_channel;
signal s_channel : t_channel;
......@@ -57,7 +59,7 @@ begin
rst_n_i => rst_n_i,
time_i => r_time,
channel_i => r_channel,
stall_i => '0',
stall_i => r_stall,
channel_o => s_channel,
overflow_o => open);
......@@ -66,28 +68,35 @@ begin
variable s1, s2 : positive := 42;
variable valid : std_logic;
variable stall : std_logic;
variable ignore : std_logic;
variable event : t_event;
variable param : t_param;
variable tag : t_tag;
variable tef : t_tef;
variable time : t_time;
variable seq : t_time;
begin
if rst_n_i = '0' then
r_time <= (others => '0');
-- r_time(r_time'high) <= '1'; -- test for overflow
r_channel <= c_idle_channel;
r_stall <= '0';
seq := (others => '0');
ignore := '0';
elsif rising_edge(clk_i) then
r_time <= f_eca_add(r_time, 2**c_log_multiplier);
p_eca_uniform(s1, s2, valid);
p_eca_uniform(s1, s2, stall);
p_eca_uniform(s1, s2, event);
p_eca_uniform(s1, s2, param);
p_eca_uniform(s1, s2, tag);
p_eca_uniform(s1, s2, tef);
p_eca_uniform(s1, s2, time);
time(time'high downto 8) := (others => '0');
time(time'high downto c_log_latency+3) := (others => '0');
time := f_eca_add(time, r_time);
r_channel.valid <= valid;
......@@ -100,12 +109,41 @@ begin
r_channel.tag <= tag;
r_channel.tef <= tef;
r_channel.time <= time;
r_stall <= stall;
if s_channel.valid = '1' then
assert unsigned(s_channel.time) >= unsigned(r_time)-24 report "Too late" severity failure;
assert unsigned(s_channel.time) < unsigned(r_time)-20 report "Too early" severity failure;
-- On time; timestamp must fall within one clock tick
if s_channel.valid = '1' and ignore = '0' then
assert unsigned(r_time) <= unsigned(s_channel.time) report "Valid too late" severity failure;
assert unsigned(s_channel.time) < unsigned(r_time)+c_ticks report "Valid too early" severity failure;
end if;
-- At worst delayed; times increase strictly monotone
if (s_channel.valid or s_channel.delayed) = '1' and ignore = '0' then
assert unsigned(s_channel.time) > unsigned(seq) report "Action timestamps not monotonic" severity failure;
seq := s_channel.time;
end if;
-- Conflicts must have the same timestamp as the last action
if s_channel.conflict = '1' then
assert unsigned(s_channel.time) = unsigned(seq) report "Conflict does not have same timestamp" severity failure;
end if;
-- If the channel claims this is late, it should be late!
if (s_channel.delayed or s_channel.late) = '1' then
assert unsigned(r_time) > unsigned(s_channel.time) report "Late action was early" severity failure;
end if;
-- If the channel claims this is early, it should be early!
if s_channel.early = '1' then
assert unsigned(s_channel.time) >= unsigned(r_time)+c_ticks report "Early action was late" severity failure;
end if;
-- Confirm function of stall line
assert ignore = '0' or s_channel.valid = '1' report "Valid went low while stalled" severity failure;
ignore := s_channel.valid and r_stall;
-- !!! include a way to ensure actions come out exactly once
end if;
end process;
......
......@@ -53,7 +53,7 @@ architecture rtl of eca_tdp is
constant c_depth : natural := 2**g_addr_bits;
type t_memory is array(c_depth-1 downto 0) of std_logic_vector(g_data_bits-1 downto 0);
shared variable v_memory : t_memory := (others => (others => '0')); -- !!!
shared variable v_memory : t_memory := (others => (others => '-'));
begin
......
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