📄 read_ch_arbiter.vhd
字号:
-------------------------------------------------------------------------------
-- read_ch_arbiter.vhd
-------------------------------------------------------------------------------
-- This arbiter, arbitrates the next channel to read from. Each channel that has a pn_lock
-- will increment by 1 for each read cycle which it is not the channel read from. If it is
-- the channel that is read it will be reset to 0. Whichever channel has the highest count
-- and maintains a pn_lock will be the next channel to be read. In this way, at the most,
-- each channel will be read every 4th read cycle. Channel A has the highest priority, then B,
-- then C, and finally channel D. If a channel loses lock, its count will be reset to 0.
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use work.correlate_and_accumulate_pack.all;
entity read_ch_arbiter is
port (
clk : in std_logic;
reset : in std_logic;
waiting_cntr_en : in std_logic;
next_ch_en : in std_logic;
almost_full : in std_logic_vector (3 downto 0);
almost_empty : in std_logic_vector (3 downto 0);
full : in std_logic_vector (3 downto 0);
empty : in std_logic_vector (3 downto 0);
pn_lock_rd_clk : in std_logic_vector (3 downto 0);
next_ch : out std_logic_vector (3 downto 0));
end read_ch_arbiter;
architecture rtl of read_ch_arbiter is
signal cha_waiting_cntr, chb_waiting_cntr, chc_waiting_cntr, chd_waiting_cntr : std_logic_vector (2 downto 0);
signal next_cha, next_chb, next_chc, next_chd : std_logic;
signal priority : std_logic_vector (3 downto 0);
signal cha_weight, chb_weight, chc_weight, chd_weight : std_logic_vector (2 downto 0);
begin -- rtl
next_ch <= next_chd & next_chc & next_chb & next_cha;
---------------------------------------------------------------------------
-- Counts the number of cycles that each channel has been locked and waiting to output data.
---------------------------------------------------------------------------
locked_ch_wait_cntr : process (clk)
begin
if rising_edge(clk) then
if reset = '1' then
cha_waiting_cntr <= (others => '0');
chb_waiting_cntr <= (others => '0');
chc_waiting_cntr <= (others => '0');
chd_waiting_cntr <= (others => '0');
else
if ((not pn_lock_rd_clk(0) or next_cha) = '1') then
cha_waiting_cntr <= (others => '0');
elsif ((waiting_cntr_en and pn_lock_rd_clk(0)) = '1') then -- clock enable waiting_cntr_en => Only enabled every 8 clock cycles
cha_waiting_cntr <= cha_waiting_cntr + 1;
end if;
if ((not pn_lock_rd_clk(1) or next_chb) = '1') then
chb_waiting_cntr <= (others => '0');
elsif ((waiting_cntr_en and pn_lock_rd_clk(1)) = '1') then -- clock enable waiting_cntr_en => Only enabled every 8 clock cycles
chb_waiting_cntr <= chb_waiting_cntr + 1;
end if;
if ((not pn_lock_rd_clk(2) or next_chc) = '1') then
chc_waiting_cntr <= (others => '0');
elsif ((waiting_cntr_en and pn_lock_rd_clk(2)) = '1') then -- clock enable waiting_cntr_en => Only enabled every 8 clock cycles
chc_waiting_cntr <= chc_waiting_cntr + 1;
end if;
if ((not pn_lock_rd_clk(3) or next_chd) = '1') then
chd_waiting_cntr <= (others => '0');
elsif ((waiting_cntr_en and pn_lock_rd_clk(3)) = '1') then -- clock enable waiting_cntr_en => Only enabled every 8 clock cycles
chd_waiting_cntr <= chd_waiting_cntr + 1;
end if;
end if;
end if;
end process;
--_____________________________________________________________________________________
-- Assigns priority to those channels that are almost_full. If no channel is almost_full,
-- priority is assigned to those channels that are NOT almost_empty. Finally, if there
-- is no priority, then the read is based on the waiting counters.
--_____________________________________________________________________________________
process (clk)
variable priority_v : std_logic_vector (3 downto 0);
begin -- process
if rising_edge(clk) then
if (reset = '1') then
priority <= (others => '0');
else
-- default
priority_v := (others => '0');
if (or_reduce(full) = '1') then -- highest priority given to those channels that are full
priority_v := full;
elsif (or_reduce(almost_full) = '1') then -- priority is given to those channels that are almost_full
priority_v := almost_full;
elsif (or_reduce(almost_empty) = '1') then -- if no channels are almost full, priority is given to the channels that
priority_v := not almost_empty; -- are not almost_empty if locked channels are the same as the almost_empty channelss
end if;
if (or_reduce(priority_v) = '0' or ((priority_v and pn_lock_rd_clk) = "0000")) then -- if there isn't any priority, the priority
-- will go to the highest waiting period
priority_v := pn_lock_rd_clk;
else
priority_v := priority_v and pn_lock_rd_clk;
end if;
priority <= priority_v and not empty; -- give the highest priority to those channels that are NOT empty
end if;
end if;
end process;
cha_weight <= cha_waiting_cntr + 1 when (priority(0) = '1') else (others => '0');
chb_weight <= chb_waiting_cntr + 1 when (priority(1) = '1') else (others => '0');
chc_weight <= chc_waiting_cntr + 1 when (priority(2) = '1') else (others => '0');
chd_weight <= chd_waiting_cntr + 1 when (priority(3) = '1') else (others => '0');
--_____________________________________________________________________________________
-- Read channel Arbiter. Which ever channel is locked and has the highest "weight"
-- will be the next channel that is read.
--_____________________________________________________________________________________
next_ch_read_arbiter : process (clk)
begin
if rising_edge(clk) then
if (reset = '1') then
next_cha <= '0';
next_chb <= '0';
next_chc <= '0';
next_chd <= '0';
else
if (next_ch_en = '1') then
-- defaults
next_cha <= '0';
next_chb <= '0';
next_chc <= '0';
next_chd <= '0';
case priority is
when "0000" =>
next_cha <= '0';
next_chb <= '0';
next_chc <= '0';
next_chd <= '0';
when others =>
if ((cha_weight >= chb_weight) and (cha_weight >= chc_weight) and (cha_weight >= chd_weight)) then
next_cha <= '1';
end if;
if ((chb_weight > cha_weight) and (chb_weight >= chc_weight) and (chb_weight >= chd_weight)) then
next_chb <= '1';
end if;
if ((chc_weight > cha_weight) and (chc_weight > chb_weight) and (chc_weight >= chd_weight)) then
next_chc <= '1';
end if;
if ((chd_weight > cha_weight) and (chd_weight > chb_weight) and (chd_weight > chc_weight)) then
next_chd <= '1';
end if;
end case;
end if;
end if;
end if;
end process;
end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -