Skip to content
Snippets Groups Projects
Commit 0bcf6830 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra
Browse files

eb2: appease modelsim and fine-tune flow control logic

parent 8516e717
Branches
Tags
No related merge requests found
......@@ -6,5 +6,6 @@ files = [
"eb_tag_fifo.vhd",
"eb_wbm_fifo.vhd",
"eb_internals_pkg.vhd",
"eb_hdr_pkg.vhd",
"eb_slave.vhd"
]
......@@ -7,12 +7,12 @@ use IEEE.numeric_std.all;
library work;
--! Additional packages
use work.eb_internals_pkg.all;
use work.eb_hdr_pkg.all;
use work.wishbone_pkg.all;
entity eb_rx_fsm is
port (
clk_i : in std_logic;
port(
clk_i : in std_logic;
rstn_i : in std_logic;
rx_cyc_i : in std_logic;
......@@ -40,35 +40,28 @@ end entity;
architecture behavioral of eb_rx_fsm is
signal rx_dat_i : std_logic_vector(31 downto 0);
signal r_rx_stall_o : std_logic;
signal r_tag_stb_o : std_logic;
signal r_tag_dat_o : t_tag;
signal r_pass_stb_o : std_logic;
signal r_pass_dat_o : std_logic;
signal r_cfg_o : t_wishbone_master_out;
signal r_wb_o : t_wishbone_master_out;
signal s_state : t_state_RX;
impure function f_reset is
begin
r_rx_stall_o <= '0';
r_tag_stb_o <= '0';
r_tag_dat_o <= (others => '0');
r_pass_stb_o <= '0';
r_pass_dat_o <= (others => '0');
r_cfg_o <= cc_dummy_master_out;
r_wb_o <= cc_dummy_master_out;
r_state <= EB_HDR;
r_wait_mux <= '0';
end f_reset;
function reply(rx_cyc_hdr : EB_CYC)
return EB_CYC is
variable tx_cyc_hdr : EB_CYC;
begin
type t_state_RX is (S_EB_HDR, S_PROBE_ID, s_CYC_HDR, S_WR_ADR, S_WRITE, S_RD_ADR, S_READ, S_ERRORS);
signal r_tx_cyc_o : std_logic;
signal r_tag_stb_o : std_logic;
signal r_tag_dat_o : t_tag;
signal r_pass_stb_o : std_logic;
signal r_pass_dat_o : t_wishbone_data;
signal r_cfg_stb_o : std_logic;
signal r_wbm_stb_o : std_logic;
signal r_adr_o : t_wishbone_address;
signal r_we_o : std_logic;
signal r_wr_adr : unsigned(31 downto 0);
signal r_wait_mux : std_logic;
signal r_rx_cyc_hdr : EB_CYC;
signal r_tx_cyc_hdr : EB_CYC;
signal r_state : t_state_RX;
signal s_stall : std_logic;
function reply(rx_cyc_hdr : EB_CYC)
return EB_CYC is
variable tx_cyc_hdr : EB_CYC;
begin
tx_cyc_hdr := INIT_EB_CYC;
tx_cyc_hdr.WCA_CFG := rx_cyc_hdr.BCA_CFG;
tx_cyc_hdr.RD_FIFO := '0';
......@@ -76,211 +69,226 @@ begin
tx_cyc_hdr.WR_FIFO := rx_cyc_hdr.RD_FIFO;
tx_cyc_hdr.WR_CNT := rx_cyc_hdr.RD_CNT;
tx_cyc_hdr.SEL := rx_cyc_hdr.SEL;
tx_cyc_hdr.DROP_CYC := rx_cyc_hdr.DROP_CYC;
tx_cyc_hdr.DROP_CYC := rx_cyc_hdr.DROP_CYC;
return tx_cyc_hdr;
end function reply;
end function;
impure function pass_on(data : std_logic_vector) is
return boolean is
variable result : boolean := false;
begin
s_pass_dat_o <= data;
s_tag_dat_o <= c_tag_pass_on;
if(pass_full_i = '0' AND tag_full_i = '0') then
s_tag_stb_o <= '1';
s_pass_stb_o <= '1';
s_rx_stall_o <= '0';
result := true;
else
s_tag_stb_o <= '0';
s_pass_stb_o <= '0';
s_rx_stall_o <= '1';
result := false;
end if;
return result;
end pass_on;
impure function wb_write(adr : std_logic_vector; data : std_logic_vector) is
begin
s_pass_dat_o <= data;
s_tag_dat_o <= c_tag_pass_on;
if(pass_full_i = '0' AND tag_full_i = '0') then
s_tag_stb_o <= '1';
s_pass_stb_o <= '1';
s_rx_stall_o <= '0';
result := true;
else
s_tag_stb_o <= '0';
s_pass_stb_o <= '0';
s_rx_stall_o <= '1';
result := false;
end if;
end pass_on;
impure function wb_read((adr : std_logic_vector) is
begin
s_pass_dat_o <= data;
s_tag_dat_o <= c_tag_pass_on;
rx_stall_o <= s_stall;
tx_cyc_o <= r_tx_cyc_o;
tag_stb_o <= r_tag_stb_o;
tag_dat_o <= r_tag_dat_o;
pass_stb_o <= r_pass_stb_o;
pass_dat_o <= r_pass_dat_o;
cfg_wb_o.cyc <= '1';
cfg_wb_o.stb <= r_cfg_stb_o;
cfg_wb_o.adr <= r_adr_o;
cfg_wb_o.we <= r_we_o;
cfg_wb_o.sel <= r_rx_cyc_hdr.sel;
cfg_wb_o.dat <= rx_dat_i;
if(pass_full_i = '0' AND tag_full_i = '0') then
s_tag_stb_o <= '1';
s_pass_stb_o <= '1';
s_rx_stall_o <= '0';
result := true;
else
s_tag_stb_o <= '0';
s_pass_stb_o <= '0';
s_rx_stall_o <= '1';
result := false;
end if;
end pass_on;
wbm_wb_o.cyc <= not r_wait_mux or not mux_empty_i; -- Lower when mux is drained
wbm_wb_o.stb <= r_wbm_stb_o;
wbm_wb_o.adr <= r_adr_o;
wbm_wb_o.we <= r_we_o;
wbm_wb_o.sel <= r_rx_cyc_hdr.sel;
wbm_wb_o.dat <= rx_dat_i;
type t_state_RX is (EB_HDR, PROBE_ID, CYC_HDR, WR_ADR, WRITE, RD_ADR, READ, CYC_DONE, EB_DONE, ERRORS);
signal stall : std_logic;
signal r_rx_cyc_hdr : EB_CYC;
signal r_tx_cyc_hdr : EB_CYC;
begin
stall <= pass_full_i OR tag_full_i OR wbm_full_i OR (r_wait_mux and not mux_empty_i);
fsm : process(clk_i, rstn_i)
-- Stall if FIFOs full or we are trying to quiet the bus
s_stall <= pass_full_i OR tag_full_i OR wbm_full_i OR (r_wait_mux and not mux_empty_i);
variable rx_frame_hdr : EB_HDR;
variable tx_frame_hdr : EB_HDR;
fsm : process(clk_i, rstn_i) is
variable rx_frame_hdr : EB_HDR;
variable tx_frame_hdr : EB_HDR;
variable rx_cyc_hdr : EB_CYC;
variable tx_cyc_hdr : EB_CYC;
variable rx_cyc_hdr : EB_CYC;
variable tx_cyc_hdr : EB_CYC;
begin
if (rstn_i = '0') then
f_reset;
r_tx_cyc_o <= '0';
r_tag_stb_o <= '0';
r_tag_dat_o <= (others => '0');
r_pass_stb_o <= '0';
r_pass_dat_o <= (others => '0');
r_cfg_stb_o <= '0';
r_wbm_stb_o <= '0';
r_adr_o <= (others => '0');
r_we_o <= '0';
r_wr_adr <= (others => '0');
r_wait_mux <= '0';
r_rx_cyc_hdr <= INIT_EB_CYC;
r_tx_cyc_hdr <= INIT_EB_CYC;
r_state <= S_EB_HDR;
elsif rising_edge(clk_i) then
if(rx_cyc_i = '1') then
if(rx_stb_i '1' and stall = '0') then
-- By default, write nowhere in particular
r_tag_stb_o <= '0';
r_pass_stb_o <= '0';
r_cfg_stb_o <= '0';
r_wbm_stb_o <= '0';
if(rx_cyc_i = '0') then
r_wait_mux <= '1'; -- stop next request until mux has drained
r_state <= S_EB_HDR;
r_tx_cyc_o <= not mux_empty_i; -- !!! might combine packets
elsif(rx_stb_i = '1' and s_stall = '0') then
-- Every non-error state must write something
case r_state is
when s_EB_HDR =>
rx_frame_hdr := TO_EB_HDR(rx_dat_i);
if( (rx_frame_hdr.EB_MAGIC = c_EB_MAGIC_WORD) and
((rx_frame_hdr.ADDR_SIZE and c_MY_EB_ADDR_SIZE) /= x"0") and
((rx_frame_hdr.PORT_SIZE and c_MY_EB_PORT_SIZE) /= x"0") and
(rx_frame_hdr.VER = c_EB_VER)
) then --header valid ?
-- Raise TX cycle line if this needs to be sent
r_tx_cyc_o <= NOT rx_frame_hdr.NO_RESPONSE;
-- Create output header
tx_frame_hdr := init_EB_hdr;
tx_frame_hdr.PROBE_RES := rx_frame_hdr.PROBE;
-- Write the header using pass fifo
r_tag_stb_o <= '1';
r_tag_dat_o <= c_tag_pass_on;
r_pass_stb_o <= '1';
r_pass_dat_o <= to_std_logic_vector(tx_frame_hdr);
if(tx_frame_hdr.PROBE_RES = '1') then
r_state <= S_PROBE_ID;
else
r_state <= S_CYC_HDR;
end if;
else --bad eb header. drop all til cycle line is lowered again
r_state <= S_ERRORS;
end if;
r_pass_stb_o <= '0';
r_wb_o.stb <= '0';
r_cfg_o.stb <= '0';
when S_PROBE_ID =>
-- Write the probe-id using pass fifo
r_tag_stb_o <= '1';
r_tag_dat_o <= c_tag_pass_on;
r_pass_stb_o <= '1';
r_pass_dat_o <= rx_dat_i;
r_state <= s_CYC_HDR;
case s_state is
when EB_HDR => rx_frame_hdr := TO_EB_HDR(rx_dat_i);
if( (rx_frame_hdr.EB_MAGIC = c_EB_MAGIC_WORD)
((rx_frame_hdr.ADDR_SIZE and c_MY_EB_ADDR_SIZE) /= x"0")
((rx_frame_hdr.PORT_SIZE and c_MY_EB_PORT_SIZE) /= x"0")
(rx_frame_hdr.VER = c_EB_VER)
) then --header valid ?
tx_cyc_o <= NOT rx_frame_hdr.NO_RESPONSE;
tx_frame_hdr := init_EB_hdr;
tx_frame_hdr.PROBE_RES := rx_frame_hdr.PROBE;
pass_on(tx_frame_hdr);
--if pass on succesful, go to...
if(tx_frame_hdr.PROBE_RES = '1') then
--...get probe id
s_state <= PROBE_ID;
else
--...get record header
s_state <= CYC_HDR;
end if;
else
--bad eb header. drop all til cycle line is lowered again
s_state <= ERRORS;
end if;
when S_CYC_HDR =>
rx_cyc_hdr := TO_EB_CYC(rx_dat_i);
tx_cyc_hdr := reply(rx_cyc_hdr);
r_tx_cyc_hdr <= tx_cyc_hdr;
r_rx_cyc_hdr <= rx_cyc_hdr;
when PROBE_ID => pass_on(rx_dat_i);
s_state <= CYC_HDR;
when CYC_HDR => rx_cyc_hdr := TO_EB_HDR(rx_dat_i);
--check if record hdr is valid
tx_cyc_hdr := reply(rx_cyc_hdr);
r_wait_mux <= '0';
if (rx_cyc_hdr.WR_CNT > 0) then
--padding logic 1. insert padding instead of the header
pass_on(x"00000000");
s_state <= WR_ADR;
elsif (rx_cyc_hdr.RD_CNT > 0) then
--no writes, no padding. insert the header
pass_on(tx_cyc_hdr);
s_state <= RD_ADR;
else
--no writes, no padding. insert the header
pass_on(tx_cyc_hdr);
r_wait_mux <= rx_cyc_hdr.DROP_CYC;
s_state <= CYC_HDR;
end if;
r_tx_cyc_hdr <= tx_cyc_hdr;
r_rx_cyc_hdr <= rx_cyc_hdr;
when WR_ADR => wb_adr <= rx_dat_i;
pass_on(x"00000000");
s_state <= WRITE;
when WRITE => if(r_rx_cyc_hdr.WR_CNT > 0) then
r_rx_cyc_hdr.WR_CNT <= std_logic_vector(unsigned(r_rx_cyc_hdr.WR_CNT) -1);
if(r_rx_cyc_hdr.WR_FIFO = '0') then
wb_adr <= wb_adr +4;
end if;
wb_write(wr_adr, rx_dat_i);
--padding logic 2. insert the header as the last write padding
if(r_rx_cyc_hdr.WR_CNT > 1) then
pass_on(x"00000000");
else
pass_on(tx_cyc_hdr);
end if;
else
if (r_cyc_hdr.RD_CNT > 0) then
s_state <= RD_ADR;
else
r_wait_mux <= r_rx_cyc_hdr.DROP_CYC;
s_state <= CYC_HDR;
end if;
end if;
r_wait_mux <= '0'; -- Re-enable pipelining
-- Write padding/header using pass fifo
r_tag_stb_o <= '1';
r_tag_dat_o <= c_tag_pass_on;
r_pass_stb_o <= '1';
if (rx_cyc_hdr.WR_CNT /= 0) then
--padding logic 1. insert padding instead of the header
r_pass_dat_o <= x"00000000";
r_state <= S_WR_ADR;
elsif (rx_cyc_hdr.RD_CNT /= 0) then
--no writes, no padding. insert the header
r_pass_dat_o <= to_std_logic_vector(tx_cyc_hdr);
r_state <= S_RD_ADR;
else
--no writes, no padding. insert the header
r_pass_dat_o <= to_std_logic_vector(tx_cyc_hdr);
r_wait_mux <= rx_cyc_hdr.DROP_CYC;
r_state <= S_CYC_HDR;
end if;
when RD_ADR => pass_on(rx_dat_i); --pass the rx readback address as base write address to tx
s_state <= READ;
when READ => if(r_rx_cyc_hdr.RD_CNT > 0) then
r_rx_cyc_hdr.RD_CNT <= std_logic_vector(unsigned(r_rx_cyc_hdr.RD_CNT) -1);
wb_read(rx_dat_i);
else
r_wait_mux <= r_rx_cyc_hdr.DROP_CYC;
s_state <= CYC_HDR;
end if;
when ERRORS => null;
when S_WR_ADR =>
r_wr_adr <= unsigned(rx_dat_i);
-- Write padding using pass fifo
r_tag_stb_o <= '1';
r_tag_dat_o <= c_tag_pass_on;
r_pass_stb_o <= '1';
r_pass_dat_o <= x"00000000";
r_state <= S_WRITE;
when S_WRITE =>
-- Writes set to eb_wbm_fifo do not generate output
if r_rx_cyc_hdr.BCA_CFG = '1' then
r_cfg_stb_o <= '1';
else
r_wbm_stb_o <= '1';
end if;
r_adr_o <= std_logic_vector(r_wr_adr);
r_we_o <= '1';
if(r_rx_cyc_hdr.WR_FIFO = '0') then
r_wr_adr <= r_wr_adr + 4;
end if;
-- Write padding/header using pass fifo
r_tag_stb_o <= '1';
r_tag_dat_o <= c_tag_pass_on;
r_pass_stb_o <= '1';
if (r_rx_cyc_hdr.WR_CNT /= 1) then
r_pass_dat_o <= x"00000000";
else
r_pass_dat_o <= to_std_logic_vector(r_tx_cyc_hdr);
if (r_rx_cyc_hdr.RD_CNT /= 0) then
r_state <= S_RD_ADR;
else
r_wait_mux <= r_rx_cyc_hdr.DROP_CYC;
r_state <= S_CYC_HDR;
end if;
end if;
r_rx_cyc_hdr.WR_CNT <= r_rx_cyc_hdr.WR_CNT - 1;
when S_RD_ADR =>
-- Copy address using pass fifo
r_tag_stb_o <= '1';
r_tag_dat_o <= c_tag_pass_on;
r_pass_stb_o <= '1';
r_pass_dat_o <= rx_dat_i; --pass the rx readback address as base write address to tx
r_state <= S_READ;
when S_READ =>
-- Get data from either cfg or wbm fifos
r_tag_stb_o <= '1';
if r_rx_cyc_hdr.BCA_CFG = '1' then
r_cfg_stb_o <= '1';
r_tag_dat_o <= c_tag_cfg_req;
else
r_wbm_stb_o <= '1';
r_tag_dat_o <= c_tag_wbm_req;
end if;
r_adr_o <= rx_dat_i;
r_we_o <= '0';
if(r_rx_cyc_hdr.RD_CNT = 1) then
r_wait_mux <= r_rx_cyc_hdr.DROP_CYC;
r_state <= S_CYC_HDR;
end if;
r_rx_cyc_hdr.RD_CNT <= r_rx_cyc_hdr.RD_CNT - 1;
when S_ERRORS =>
null;
when others => s_state <= ERRORS;
end case;
when others =>
r_state <= S_ERRORS;
end if; --rx_stb_i
else
r_wait_mux <= '1';
s_state <= EB_HDR;
end if; --rx_cyc_i
end case;
end if; --rx_stb_i
end if; --clk edge
end process;
end process;
end architecture;
......@@ -192,9 +192,9 @@ begin
mux_empty <=
not wbm_busy and
wbm_mux_empty and
cfg_mux_empty and
pass_mux_empty and
-- wbm_mux_empty and -- redundant
-- cfg_mux_empty and
-- pass_mux_empty and
tag_mux_empty;
end rtl;
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