From 5f3392ec282cac3748cbab41bc86299c49694a97 Mon Sep 17 00:00:00 2001
From: Dimitris Lampridis <dimitris.lampridis@cern.ch>
Date: Wed, 21 Nov 2018 16:12:57 +0100
Subject: [PATCH] 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.
---
 .../wb_slave_adapter/wb_slave_adapter.vhd     | 59 +++++++++++++------
 1 file changed, 40 insertions(+), 19 deletions(-)

diff --git a/modules/wishbone/wb_slave_adapter/wb_slave_adapter.vhd b/modules/wishbone/wb_slave_adapter/wb_slave_adapter.vhd
index 47ffd5e1..dcf9207d 100644
--- a/modules/wishbone/wb_slave_adapter/wb_slave_adapter.vhd
+++ b/modules/wishbone/wb_slave_adapter/wb_slave_adapter.vhd
@@ -105,15 +105,10 @@ architecture rtl of wb_slave_adapter is
     return std_logic_vector(to_unsigned(0, size));
   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_out : t_wishbone_master_out;
   signal slave_in   : t_wishbone_slave_in;
   signal slave_out  : t_wishbone_slave_out;
-  signal stored_we  : std_logic;
   
 begin  -- rtl
 
@@ -170,17 +165,41 @@ begin  -- rtl
       master_out.adr <= f_zeros(f_num_byte_address_bits)
                         & slave_in.adr(c_wishbone_address_width-1 downto f_num_byte_address_bits);
     end if;
-  end process;
+  end process p_gen_address;
   
   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;
-    slave_out.stall <= not master_in.ack;
-  end generate;
+    slave_out.stall <= '0' when slave_in.cyc = '0' else not master_in.ack;
+    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
+    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';
+    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
-    
+
     state_machine : process(clk_sys_i) is
     begin
       if rising_edge(clk_sys_i) then
@@ -188,32 +207,34 @@ begin  -- rtl
           fsm_state <= IDLE;
         else
           case fsm_state is
-            when IDLE => 
-              if slave_in.stb ='1' and slave_in.cyc = '1' and master_in.stall='0' and master_in.ack='0' then
+            when IDLE =>
+              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;
               end if;
-            when WAIT4ACK => 
-              if (slave_in.stb = '0' and slave_in.cyc = '0') or master_in.ack='1' or master_in.err='1' then 
+            when WAIT4ACK =>
+              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;
               end if;
           end case;
         end if;
       end if;
-    end process;
-  end generate;
+    end process state_machine;
+  end generate C2P;
   
   X2X : if (g_slave_mode = g_master_mode) generate
     master_out.stb  <= slave_in.stb;
     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.cyc <= slave_in.cyc;
   master_out.sel <= slave_in.sel;
   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;
 end rtl;
-- 
GitLab