Commit ed22c060 authored by Michael Munch's avatar Michael Munch
Browse files

cli_arb can handle two VME cores

parent 9bb97ba6
Pipeline #25473 failed with stage
in 32 seconds
......@@ -64,24 +64,46 @@ entity vme_cli_arb is
-- Signals to/from the VME core.
-- Directions inverted relative to the core.
signal vc_busy : in std_logic := '0';
-- Core 1
signal vc1_busy : in std_logic := '0';
signal vc_int_data_o : in vme_vec_64_t;
signal vc_int_data_strobe : in std_logic := c_DATA_CLEAR;
signal vc_int_go_consumed_strobe : in std_logic := '0';
signal vc_int_blt_decision_strobe : in std_logic := '0';
signal vc_int_err_code : in err_vec_t := C_ERR_OK;
signal vc1_int_data_o : in vme_vec_64_t;
signal vc1_int_data_strobe : in std_logic := c_DATA_CLEAR;
signal vc1_int_go_consumed_strobe : in std_logic := '0';
signal vc1_int_blt_decision_strobe : in std_logic := '0';
signal vc1_int_err_code : in err_vec_t := C_ERR_OK;
signal vc_int_addr : out vme_addr_t;
signal vc_int_data_i : out vme_vec_64_t;
signal vc_int_am_i : out am_vec_t;
signal vc_int_vme_rw : out std_logic;
signal vc_int_vme_go : out std_logic;
signal vc1_int_addr : out vme_addr_t;
signal vc1_int_data_i : out vme_vec_64_t;
signal vc1_int_am_i : out am_vec_t;
signal vc1_int_vme_rw : out std_logic;
signal vc1_int_vme_go : out std_logic;
signal vc_int_blt_decided : out std_logic;
signal vc_int_blt_continue : out std_logic;
signal vc1_int_blt_decided : out std_logic;
signal vc1_int_blt_continue : out std_logic;
signal vc_int_berr_ok : out std_logic
signal vc1_int_berr_ok : out std_logic;
-- Core 2
signal vc2_busy : in std_logic := '0';
signal vc2_int_data_o : in vme_vec_64_t;
signal vc2_int_data_strobe : in std_logic := c_DATA_CLEAR;
signal vc2_int_go_consumed_strobe : in std_logic := '0';
signal vc2_int_blt_decision_strobe : in std_logic := '0';
signal vc2_int_err_code : in err_vec_t := C_ERR_OK;
signal vc2_int_addr : out vme_addr_t;
signal vc2_int_data_i : out vme_vec_64_t;
signal vc2_int_am_i : out am_vec_t;
signal vc2_int_vme_rw : out std_logic;
signal vc2_int_vme_go : out std_logic;
signal vc2_int_blt_decided : out std_logic;
signal vc2_int_blt_continue : out std_logic;
signal vc2_int_berr_ok : out std_logic
-- -- Dropped signals (since they cannot be multiplexed /
-- -- span multiple access cycles).
......@@ -112,7 +134,6 @@ architecture rtl of vme_cli_arb is
-- In case we are not busy, which client would we like to
-- make active (if any).
signal cnt : integer range 0 to 256:= 0;
signal want_1 : boolean;
signal want_2 : boolean;
......@@ -128,6 +149,10 @@ architecture rtl of vme_cli_arb is
signal active_1 : boolean := false;
signal active_2 : boolean := false;
-- Which core is active
signal core_1 : boolean := true;
-- Who will we prefer when we can take the next client, i.e. are
-- no longer busy?
signal prefer_1 : boolean := false;
......@@ -137,32 +162,48 @@ architecture rtl of vme_cli_arb is
signal p1_int_err_code_latched : err_vec_t := C_ERR_OK;
signal p2_int_err_code_latched : err_vec_t := C_ERR_OK;
signal r_busy : std_logic := '0';
signal r_data_o : vme_vec_64_t;
signal r_data_strobe : std_logic := c_DATA_CLEAR;
signal r_go_consumed_strobe : std_logic := '0';
signal r_blt_decision_strobe : std_logic := '0';
signal r_err_code : err_vec_t := C_ERR_OK;
signal r_vme_go : std_logic := '0';
begin
-- Muxed version of all inputs from VME cores
r_busy <= vc1_busy when core_1 else vc2_busy;
r_data_o <= vc1_int_data_o when core_1 else vc2_int_data_o;
r_data_strobe <= vc1_int_data_strobe when core_1 else vc2_int_data_strobe;
r_go_consumed_strobe <= vc1_int_go_consumed_strobe when core_1 else vc2_int_go_consumed_strobe;
r_blt_decision_strobe <= vc1_int_blt_decision_strobe when core_1 else vc2_int_blt_decision_strobe;
r_err_code <= vc1_int_err_code when core_1 else vc2_int_err_code;
want_1 <= (p1_int_vme_go = '1' and p2_int_vme_go = '0') or (p1_int_vme_go = '1' and prefer_1);
want_2 <= (p2_int_vme_go = '1' and p1_int_vme_go = '0') or (p2_int_vme_go = '1' and not prefer_1);
start_1 <= vc_busy = '0' and want_1;
start_2 <= vc_busy = '0' and want_2;
-- start_1 <= r_busy = '0' and want_1;
-- start_2 <= r_busy = '0' and want_2;
start_1 <= vc1_busy = '0' and vc2_busy = '0' and want_1;
start_2 <= vc1_busy = '0' and vc2_busy = '0' and want_2;
-- We kill the live assignment as soon as busy is removed.
-- (Not really needed.)
live_1 <= (active_1 and vc_busy = '1') or start_1;
live_2 <= (active_2 and vc_busy = '1') or start_2;
live_1 <= (active_1 and r_busy = '1') or start_1;
live_2 <= (active_2 and r_busy = '1') or start_2;
process (clk)
begin
if (rising_edge(clk)) then
cnt <= cnt + 1;
if (vc_busy = '0') then
if (vc1_busy = '0') then
-- Latch error code when busy pulled
if (active_1) then
p1_int_err_code_latched <= vc_int_err_code;
p1_int_err_code_latched <= r_err_code;
end if;
if (active_2) then
p2_int_err_code_latched <= vc_int_err_code;
p2_int_err_code_latched <= r_err_code;
end if;
active_1 <= false;
active_2 <= false;
......@@ -172,20 +213,26 @@ begin
if (start_1) then
active_1 <= true;
prefer_1 <= false;
-- Only AM=0x19 are passed to core 2.
core_1 <= vc1_int_am_i /= X"19";
end if;
if (start_2) then
active_2 <= true;
prefer_1 <= true;
-- Only AM=0x19 are passed to core 2.
core_1 <= vc2_int_am_i /= X"19";
end if;
-- We select on active instead of live, since active is cheaper (comes
-- directly from a flip-flop, instead of logic), and
-- vc_int_data_strobe will not come on the first cycle.
if (active_1 and vc_int_data_strobe = '1') then
p1_int_data_o_latched <= vc_int_data_o;
-- vc1_int_data_strobe will not come on the first cycle.
if (active_1 and r_data_strobe = '1') then
p1_int_data_o_latched <= r_data_o;
end if;
if (active_2 and vc_int_data_strobe = '1') then
p2_int_data_o_latched <= vc_int_data_o;
if (active_2 and r_data_strobe = '1') then
p2_int_data_o_latched <= r_data_o;
end if;
end if;
......@@ -198,14 +245,28 @@ begin
-- client 2. This does not matter, since the VME core will
-- only react to anything if the 'go' signal is given.
vc_int_addr <= p1_int_addr when live_1 else p2_int_addr;
vc_int_data_i <= p1_int_data_i when live_1 else p2_int_data_i;
vc_int_am_i <= p1_int_am_i when live_1 else p2_int_am_i;
vc_int_vme_rw <= p1_int_vme_rw when live_1 else p2_int_vme_rw;
vc_int_vme_go <= p1_int_vme_go when live_1 else p2_int_vme_go;
vc_int_blt_decided <= p1_int_blt_decided when live_1 else p2_int_blt_decided;
vc_int_blt_continue <= p1_int_blt_continue when live_1 else p2_int_blt_continue;
vc_int_berr_ok <= p1_int_berr_ok when live_1 else p2_int_berr_ok;
-- We send all signals, except go, to both cores.
vc1_int_addr <= p1_int_addr when live_1 else p2_int_addr;
vc1_int_data_i <= p1_int_data_i when live_1 else p2_int_data_i;
vc1_int_am_i <= p1_int_am_i when live_1 else p2_int_am_i;
vc1_int_vme_rw <= p1_int_vme_rw when live_1 else p2_int_vme_rw;
vc1_int_blt_decided <= p1_int_blt_decided when live_1 else p2_int_blt_decided;
vc1_int_blt_continue <= p1_int_blt_continue when live_1 else p2_int_blt_continue;
vc1_int_berr_ok <= p1_int_berr_ok when live_1 else p2_int_berr_ok;
vc2_int_addr <= p1_int_addr when live_1 else p2_int_addr;
vc2_int_data_i <= p1_int_data_i when live_1 else p2_int_data_i;
vc2_int_am_i <= p1_int_am_i when live_1 else p2_int_am_i;
vc2_int_vme_rw <= p1_int_vme_rw when live_1 else p2_int_vme_rw;
vc2_int_blt_decided <= p1_int_blt_decided when live_1 else p2_int_blt_decided;
vc2_int_blt_continue <= p1_int_blt_continue when live_1 else p2_int_blt_continue;
vc2_int_berr_ok <= p1_int_berr_ok when live_1 else p2_int_berr_ok;
-- Go handling.
r_vme_go <= p1_int_vme_go when live_1 else p2_int_vme_go;
vc1_int_vme_go <= r_vme_go when core_1 else '0';
vc2_int_vme_go <= r_vme_go when not core_1 else '0';
-- Signals to the clients from the VME core:
......@@ -215,25 +276,25 @@ begin
-- Data is passed directly through on the cycle they have been latched.
-- Otherwise, take the latched value:
p1_int_data_o <= vc_int_data_o when (live_1 and vc_int_data_strobe = '1') else
p1_int_data_o <= r_data_o when (live_1 and r_data_strobe = '1') else
p1_int_data_o_latched;
p2_int_data_o <= vc_int_data_o when (live_2 and vc_int_data_strobe = '1') else
p2_int_data_o <= r_data_o when (live_2 and r_data_strobe = '1') else
p2_int_data_o_latched;
-- The error code follows the data.
p1_int_err_code <= vc_int_err_code when (live_1 and vc_int_data_strobe = '1') else
p1_int_err_code <= r_err_code when (live_1 and r_data_strobe = '1') else
p1_int_err_code_latched;
p2_int_err_code <= vc_int_err_code when (live_2 and vc_int_data_strobe = '1') else
p2_int_err_code <= r_err_code when (live_2 and r_data_strobe = '1') else
p2_int_err_code_latched;
-- The strobes always go to the live client.
p1_int_data_strobe <= vc_int_data_strobe when live_1 else '0';
p2_int_data_strobe <= vc_int_data_strobe when live_2 else '0';
p1_int_data_strobe <= r_data_strobe when live_1 else '0';
p2_int_data_strobe <= r_data_strobe when live_2 else '0';
p1_int_go_consumed_strobe <= vc_int_go_consumed_strobe when live_1 else '0';
p2_int_go_consumed_strobe <= vc_int_go_consumed_strobe when live_2 else '0';
p1_int_go_consumed_strobe <= r_go_consumed_strobe when live_1 else '0';
p2_int_go_consumed_strobe <= r_go_consumed_strobe when live_2 else '0';
p1_int_blt_decision_strobe <= vc_int_blt_decision_strobe when live_1 else '0';
p2_int_blt_decision_strobe <= vc_int_blt_decision_strobe when live_2 else '0';
p1_int_blt_decision_strobe <= r_blt_decision_strobe when live_1 else '0';
p2_int_blt_decision_strobe <= r_blt_decision_strobe when live_2 else '0';
-- The busy of a client is simply while it is live.
-- This actually means that we will report busy some cycles
......@@ -258,8 +319,8 @@ begin
process (clk)
begin
if (rising_edge(clk)) then
l_data <= vc_int_data_o;
l_err_code <= vc_int_err_code;
l_data <= vc1_int_data_o;
l_err_code <= vc1_int_err_code;
end if;
end process;
......@@ -272,8 +333,8 @@ begin
-- psl not_two_busy: assert not (p1_busy and p2_busy);
-- -- Don't start clients when VME core is busy
-- psl busy_dont_start_1: assert always {vc_busy = '1'} |-> not start_1 until vc_busy = '0';
-- psl busy_dont_start_2: assert always {vc_busy = '1'} |-> not start_1 until vc_busy = '0';
-- psl busy_dont_start_1: assert always {vc1_busy = '1'} |-> not start_1 until vc1_busy = '0';
-- psl busy_dont_start_2: assert always {vc1_busy = '1'} |-> not start_1 until vc1_busy = '0';
-- -- When we have started client 1 then prefer 2 until it runs
-- psl if_start_1_pref_2: assert always {start_1} |=> not prefer_1 until start_2;
......@@ -282,102 +343,102 @@ begin
-- -- If both clients request access then we pick our favourite
-- psl pick_pref_client_1: assert always
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and not prefer_1 and vc_busy = '0'}
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and not prefer_1 and vc1_busy = '0'}
-- |=> start_2 until active_2;
-- psl pick_pref_client_2: assert always
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and prefer_1 and vc_busy = '0'}
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and prefer_1 and vc1_busy = '0'}
-- |=> start_1 until active_1;
-- -- While client is live it data output tracks live data
-- psl live_track_1:
-- assert always {active_1; vc_int_data_strobe = '1'}
-- |=> p1_int_data_o = vc_int_data_o
-- until vc_int_data_strobe = '0' or not live_1;
-- assert always {active_1; vc1_int_data_strobe = '1'}
-- |=> p1_int_data_o = vc1_int_data_o
-- until vc1_int_data_strobe = '0' or not live_1;
-- psl live_track_2:
-- assert always {active_2; vc_int_data_strobe = '1'}
-- |=> p2_int_data_o = vc_int_data_o
-- until vc_int_data_strobe = '0' or not live_2;
-- assert always {active_2; vc1_int_data_strobe = '1'}
-- |=> p2_int_data_o = vc1_int_data_o
-- until vc1_int_data_strobe = '0' or not live_2;
-- -- If we sent p1_int_vme_go then the VME core will eventually receive it
-- psl p1_vme_addr: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_addr = p1_int_addr ;
-- |=> eventually! vc1_int_addr = p1_int_addr ;
-- psl p1_vme_data_i: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_data_i = p1_int_data_i ;
-- |=> eventually! vc1_int_data_i = p1_int_data_i ;
-- psl p1_vme_am_i: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_am_i = p1_int_am_i ;
-- |=> eventually! vc1_int_am_i = p1_int_am_i ;
-- psl p1_vme_rw: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_vme_rw = p1_int_vme_rw ;
-- |=> eventually! vc1_int_vme_rw = p1_int_vme_rw ;
-- psl p1_vme_go: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_vme_go = p1_int_vme_go ;
-- |=> eventually! vc1_int_vme_go = p1_int_vme_go ;
-- psl p1_vme_blt_deci: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_blt_decided = p1_int_blt_decided ;
-- |=> eventually! vc1_int_blt_decided = p1_int_blt_decided ;
-- psl p1_vme_blt_cont: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_blt_continue = p1_int_blt_continue ;
-- |=> eventually! vc1_int_blt_continue = p1_int_blt_continue ;
-- psl p1_vme_berr_ok: assert always {p1_int_vme_go}
-- |=> eventually! vc_int_berr_ok = p1_int_berr_ok ;
-- |=> eventually! vc1_int_berr_ok = p1_int_berr_ok ;
-- -- If we sent p2_int_vme_go then the VME core will eventually receive it
-- psl p2_vme_addr: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_addr = p2_int_addr ;
-- |=> eventually! vc1_int_addr = p2_int_addr ;
-- psl p2_vme_data_i: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_data_i = p2_int_data_i ;
-- |=> eventually! vc1_int_data_i = p2_int_data_i ;
-- psl p2_vme_am_i: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_am_i = p2_int_am_i ;
-- |=> eventually! vc1_int_am_i = p2_int_am_i ;
-- psl p2_vme_rw: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_vme_rw = p2_int_vme_rw ;
-- |=> eventually! vc1_int_vme_rw = p2_int_vme_rw ;
-- psl p2_vme_go: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_vme_go = p2_int_vme_go ;
-- |=> eventually! vc1_int_vme_go = p2_int_vme_go ;
-- psl p2_vme_blt_deci: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_blt_decided = p2_int_blt_decided ;
-- |=> eventually! vc1_int_blt_decided = p2_int_blt_decided ;
-- psl p2_vme_blt_cont: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_blt_continue = p2_int_blt_continue ;
-- |=> eventually! vc1_int_blt_continue = p2_int_blt_continue ;
-- psl p2_vme_berr_ok: assert always {p2_int_vme_go}
-- |=> eventually! vc_int_berr_ok = p2_int_berr_ok ;
-- |=> eventually! vc1_int_berr_ok = p2_int_berr_ok ;
-- -- Data strobes are routed to live client
-- psl p1_get_d_strobe: assert always {live_1}
-- |=> p1_int_data_strobe = vc_int_data_strobe until not live_1;
-- |=> p1_int_data_strobe = vc1_int_data_strobe until not live_1;
-- psl p2_get_d_strobe: assert always {live_2}
-- |=> p2_int_data_strobe = vc_int_data_strobe until not live_2;
-- |=> p2_int_data_strobe = vc1_int_data_strobe until not live_2;
-- -- Go strobes are routed to live client
-- psl p1_get_go_strobe: assert always {live_1}
-- |=> p1_int_go_consumed_strobe = vc_int_go_consumed_strobe until not live_1;
-- |=> p1_int_go_consumed_strobe = vc1_int_go_consumed_strobe until not live_1;
-- psl p2_get_go_strobe: assert always {live_2}
-- |=> p2_int_go_consumed_strobe = vc_int_go_consumed_strobe until not live_2;
-- |=> p2_int_go_consumed_strobe = vc1_int_go_consumed_strobe until not live_2;
-- -- BLT decision strobes are routed to live client
-- psl p1_get_blt_strobe: assert always {live_1}
-- |=> p1_int_blt_decision_strobe = vc_int_blt_decision_strobe until not live_1;
-- |=> p1_int_blt_decision_strobe = vc1_int_blt_decision_strobe until not live_1;
-- psl p2_get_blt_strobe: assert always {live_2}
-- |=> p2_int_blt_decision_strobe = vc_int_blt_decision_strobe until not live_2;
-- |=> p2_int_blt_decision_strobe = vc1_int_blt_decision_strobe until not live_2;
-- -- Latched data tracks input while active and strobed
-- psl p1_tracks_data: assert always
-- {active_1 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- {active_1 and vc1_busy = '1' and vc1_int_data_strobe = '1'}
-- |=> p1_int_data_o_latched = l_data
-- until vc_int_data_strobe = '0' or not active_1;
-- until vc1_int_data_strobe = '0' or not active_1;
-- psl p2_tracks_data: assert always
-- {active_2 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- {active_2 and vc1_busy = '1' and vc1_int_data_strobe = '1'}
-- |=> p2_int_data_o_latched = l_data
-- until vc_int_data_strobe = '0' or not active_2;
-- until vc1_int_data_strobe = '0' or not active_2;
-- -- Latched error tracks input while active and strobed
-- psl p1_tracks_err: assert always
-- {active_1 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- {active_1 and vc1_busy = '1' and vc1_int_data_strobe = '1'}
-- |=> p1_int_err_code_latched = l_err_code
-- until vc_int_data_strobe = '0' or not active_1;
-- until vc1_int_data_strobe = '0' or not active_1;
-- psl p2_tracks_err: assert always
-- {active_2 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- {active_2 and vc1_busy = '1' and vc1_int_data_strobe = '1'}
-- |=> p2_int_err_code_latched = l_err_code
-- until vc_int_data_strobe = '0' or not active_2;
-- until vc1_int_data_strobe = '0' or not active_2;
end generate FormalG;
end architecture;
......
Supports Markdown
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