Skip to content
Snippets Groups Projects
Commit 5f3392ec authored by Dimitris Lampridis's avatar Dimitris Lampridis
Browse files

wb_slave_adapter: in the P2C scenario, only strobe ACK/ERR/RTY for 1 cycle.

Although not mentioned in section 5.2 of Wishbone B4 specification, when interfacing a pipelined
master to a standard slave, it is also necessary to make sure that if the slave asserts ACK/ERR/RTY
for more than one clock cycle (which a standard slave could do since, according to Rule 3.50 of
Wishbone B4, "the slave deasserts ACK/ERR/RTY in response to the negation of STB"), the master will
still only see a one cycle wide pulse.
parent 8052c7b1
No related merge requests found
...@@ -105,15 +105,10 @@ architecture rtl of wb_slave_adapter is ...@@ -105,15 +105,10 @@ architecture rtl of wb_slave_adapter is
return std_logic_vector(to_unsigned(0, size)); return std_logic_vector(to_unsigned(0, size));
end f_zeros; end f_zeros;
type t_fsm_state is (IDLE, WAIT4ACK);
signal fsm_state : t_fsm_state := IDLE;
signal master_in : t_wishbone_master_in; signal master_in : t_wishbone_master_in;
signal master_out : t_wishbone_master_out; signal master_out : t_wishbone_master_out;
signal slave_in : t_wishbone_slave_in; signal slave_in : t_wishbone_slave_in;
signal slave_out : t_wishbone_slave_out; signal slave_out : t_wishbone_slave_out;
signal stored_we : std_logic;
begin -- rtl begin -- rtl
...@@ -170,17 +165,41 @@ begin -- rtl ...@@ -170,17 +165,41 @@ begin -- rtl
master_out.adr <= f_zeros(f_num_byte_address_bits) master_out.adr <= f_zeros(f_num_byte_address_bits)
& slave_in.adr(c_wishbone_address_width-1 downto f_num_byte_address_bits); & slave_in.adr(c_wishbone_address_width-1 downto f_num_byte_address_bits);
end if; end if;
end process; end process p_gen_address;
P2C : if (g_slave_mode = PIPELINED and g_master_mode = CLASSIC) generate P2C : if (g_slave_mode = PIPELINED and g_master_mode = CLASSIC) generate
signal master_in_ack_d1 : std_logic := '0';
signal master_in_err_d1 : std_logic := '0';
signal master_in_rty_d1 : std_logic := '0';
begin
-- we need delayed versions of of ack/err/rty to detect rising edges and
-- send a one clock cycle wide ack/err/rty to the pipelined side.
p_wb_term_d1: process (clk_sys_i) is
begin
if rising_edge(clk_sys_i) then
master_in_ack_d1 <= master_in.ack;
master_in_err_d1 <= master_in.err;
master_in_rty_d1 <= master_in.rty;
end if;
end process p_wb_term_d1;
master_out.stb <= slave_in.stb; master_out.stb <= slave_in.stb;
slave_out.stall <= not master_in.ack; slave_out.stall <= '0' when slave_in.cyc = '0' else not master_in.ack;
end generate; slave_out.ack <= master_in.ack and not master_in_ack_d1;
slave_out.err <= master_in.err and not master_in_err_d1;
slave_out.rty <= master_in.rty and not master_in_rty_d1;
end generate P2C;
C2P : if (g_slave_mode = CLASSIC and g_master_mode = PIPELINED) generate C2P : if (g_slave_mode = CLASSIC and g_master_mode = PIPELINED) generate
type t_fsm_state is (IDLE, WAIT4ACK);
signal fsm_state : t_fsm_state := IDLE;
begin
master_out.stb <= slave_in.stb when fsm_state=IDLE else '0'; master_out.stb <= slave_in.stb when fsm_state=IDLE else '0';
slave_out.ack <= master_in.ack;
slave_out.err <= master_in.err;
slave_out.rty <= master_in.rty;
slave_out.stall <= '0'; -- classic will ignore this anyway slave_out.stall <= '0'; -- classic will ignore this anyway
state_machine : process(clk_sys_i) is state_machine : process(clk_sys_i) is
begin begin
if rising_edge(clk_sys_i) then if rising_edge(clk_sys_i) then
...@@ -188,32 +207,34 @@ begin -- rtl ...@@ -188,32 +207,34 @@ begin -- rtl
fsm_state <= IDLE; fsm_state <= IDLE;
else else
case fsm_state is case fsm_state is
when IDLE => when IDLE =>
if slave_in.stb ='1' and slave_in.cyc = '1' and master_in.stall='0' and master_in.ack='0' then if (slave_in.stb = '1' and slave_in.cyc = '1') and
(master_in.stall = '0' and master_in.ack = '0' and master_in.rty = '0') then
fsm_state <= WAIT4ACK; fsm_state <= WAIT4ACK;
end if; end if;
when WAIT4ACK => when WAIT4ACK =>
if (slave_in.stb = '0' and slave_in.cyc = '0') or master_in.ack='1' or master_in.err='1' then if (slave_in.stb = '0' and slave_in.cyc = '0') or
(master_in.ack = '1' or master_in.err = '1' or master_in.rty = '1') then
fsm_state <= IDLE; fsm_state <= IDLE;
end if; end if;
end case; end case;
end if; end if;
end if; end if;
end process; end process state_machine;
end generate; end generate C2P;
X2X : if (g_slave_mode = g_master_mode) generate X2X : if (g_slave_mode = g_master_mode) generate
master_out.stb <= slave_in.stb; master_out.stb <= slave_in.stb;
slave_out.stall <= master_in.stall; slave_out.stall <= master_in.stall;
end generate; slave_out.ack <= master_in.ack;
slave_out.err <= master_in.err;
slave_out.rty <= master_in.rty;
end generate X2X;
master_out.dat <= slave_in.dat; master_out.dat <= slave_in.dat;
master_out.cyc <= slave_in.cyc; master_out.cyc <= slave_in.cyc;
master_out.sel <= slave_in.sel; master_out.sel <= slave_in.sel;
master_out.we <= slave_in.we; master_out.we <= slave_in.we;
slave_out.ack <= master_in.ack;
slave_out.err <= master_in.err;
slave_out.rty <= master_in.rty;
slave_out.dat <= master_in.dat; slave_out.dat <= master_in.dat;
end rtl; 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