]> git.the-white-hart.net Git - vhdl/commitdiff
Drive Wishbone bridge with state machine
authorRyan <>
Tue, 30 Sep 2025 07:39:18 +0000 (02:39 -0500)
committerRyan <>
Tue, 30 Sep 2025 07:39:18 +0000 (02:39 -0500)
libraries/utility/wb_bridge.vhd

index c96e14bb143a8d828207e91e6b3c4aec7394239e..fb0560ed24f3692869d8ab9c9f4677ab0cbb774d 100644 (file)
@@ -31,62 +31,71 @@ end wb_bridge;
 
 architecture behavioral of wb_bridge is
 
-       signal cyc_reg:  std_logic;
-       signal stb_reg:  std_logic;
+       type state_t is (S_IDLE, S_STB, S_ACK);
+       signal state_cur_reg: state_t;
+       signal state_next: state_t;
+
        signal we_reg:   std_logic;
-       signal ack_reg:  std_logic;
        signal adr_reg:  std_logic_vector(A_WIDTH-1 downto 0);
        signal mosi_reg: std_logic_vector(D_WIDTH-1 downto 0);
        signal miso_reg: std_logic_vector(D_WIDTH-1 downto 0);
 
 begin
 
-       process (rst_i, clk_i, stb_reg,
-                a_cyc_i, a_stb_i, a_we_i, a_adr_i, a_dat_i,
-                b_dat_i)
+       process (rst_i, clk_i)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               state_cur_reg <= S_IDLE;
+                       else
+                               state_cur_reg <= state_next;
+                       end if;
+               end if;
+       end process;
+
+       process (state_cur_reg, a_cyc_i, a_stb_i, b_ack_i)
+       begin
+               state_next <= state_cur_reg;
+               b_cyc_o <= '0';
+               b_stb_o <= '0';
+               a_ack_o <= '0';
+
+               case state_cur_reg is
+                       when S_IDLE =>
+                               if a_cyc_i = '1' and a_stb_i = '1' then
+                                       state_next <= S_STB;
+                               end if;
+
+                       when S_STB =>
+                               b_cyc_o <= '1';
+                               b_stb_o <= '1';
+                               if b_ack_i = '1' then
+                                       state_next <= S_ACK;
+                               end if;
+
+                       when S_ACK =>
+                               a_ack_o <= '1';
+                               state_next <= S_IDLE;
+
+                       when others =>
+                               state_next <= S_IDLE;
+               end case;
+       end process;
+
+       process (rst_i, clk_i, a_we_i, a_adr_i, a_dat_i, b_dat_i)
        begin
                if rising_edge(clk_i) then
                        -- Most signals just get registered
-                       cyc_reg  <= a_cyc_i;
                        we_reg   <= a_we_i;
                        adr_reg  <= a_adr_i;
                        mosi_reg <= a_dat_i;
                        miso_reg <= b_dat_i;
-
-                       -- The strobe input from side A will still be asserted when side B
-                       -- acknowledges because it will take another clock cycle for side A
-                       -- to get the adknowledgement, so we need to lower the strobe signal
-                       -- ourselves once side B acknowledges to prevent a second
-                       -- transaction from starting
-                       if stb_reg = '1' and b_ack_i = '1' then
-                               stb_reg <= '0';
-                       else
-                               stb_reg <= a_stb_i;
-                       end if;
-
-                       -- Some devices always assert ACK because they respond within a
-                       -- single clock cycle.  These should not be passed back to side A
-                       -- until after the strobe has been sent to side B
-                       if stb_reg = '0' then
-                               ack_reg <= '0';
-                       else
-                               ack_reg <= b_ack_i;
-                       end if;
-
-                       -- The CYC signal determines validity of all others, so only it
-                       -- needs to be reset to zero
-                       if rst_i = '1' then
-                               cyc_reg <= '0';
-                       end if;
                end if;
        end process;
 
        -- Outputs come from registers only
-       a_ack_o <= ack_reg;
        a_dat_o <= miso_reg;
 
-       b_cyc_o <= cyc_reg;
-       b_stb_o <= stb_reg;
        b_we_o  <= we_reg;
        b_adr_o <= adr_reg;
        b_dat_o <= mosi_reg;