From: Ryan <> Date: Tue, 23 Sep 2025 16:17:12 +0000 (-0500) Subject: Add Wisbhone register bridge X-Git-Url: https://git.the-white-hart.net/?a=commitdiff_plain;h=33930a5f62dc516b858e323db0966e35cc09be8e;p=vhdl Add Wisbhone register bridge --- diff --git a/libraries/utility/tests/test_wb_bridge.vhd b/libraries/utility/tests/test_wb_bridge.vhd new file mode 100644 index 0000000..6c9afde --- /dev/null +++ b/libraries/utility/tests/test_wb_bridge.vhd @@ -0,0 +1,102 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; + + +entity test_wb_bridge is +end test_wb_bridge; + + +architecture behavior of test_wb_bridge is + + constant CLK_PERIOD: time := 10 ns; + + signal rst: std_logic; + signal clk: std_logic; + + signal a_cyc: std_logic; + signal a_stb: std_logic; + signal a_we: std_logic; + signal a_ack: std_logic; + signal a_adr: std_logic_vector(7 downto 0); + signal a_mosi: std_logic_vector(7 downto 0); + signal a_miso: std_logic_vector(7 downto 0); + + signal b_cyc: std_logic; + signal b_stb: std_logic; + signal b_we: std_logic; + signal b_ack: std_logic; + signal b_adr: std_logic_vector(7 downto 0); + signal b_mosi: std_logic_vector(7 downto 0); + signal b_miso: std_logic_vector(7 downto 0); + +begin + + p_test: process + begin + -- Initial values + a_cyc <= '0'; + a_stb <= '0'; + a_we <= '0'; + a_adr <= (others => '0'); + a_mosi <= (others => '0'); + + -- Reset + rst <= '1'; + wait for CLK_PERIOD*2; + rst <= '0'; + wait for CLK_PERIOD*2; + + -- Make a request + a_cyc <= '1'; + a_stb <= '1'; + wait until a_ack = '1'; + a_cyc <= '0'; + a_stb <= '0'; + + wait; + end process; + + + e_uut: entity work.wb_bridge + generic map (A_WIDTH => 8, D_WIDTH => 8) + port map ( + rst_i => rst, + clk_i => clk, + + a_cyc_i => a_cyc, + a_stb_i => a_stb, + a_we_i => a_we, + a_ack_o => a_ack, + a_adr_i => a_adr, + a_dat_i => a_mosi, + a_dat_o => a_miso, + + b_cyc_o => b_cyc, + b_stb_o => b_stb, + b_we_o => b_we, + b_ack_i => b_ack, + b_adr_o => b_adr, + b_dat_o => b_mosi, + b_dat_i => b_miso + ); + + + p_device: process (rst, clk, b_cyc, b_stb, b_we, b_adr, b_mosi) + begin + b_ack <= not rst; + b_miso <= x"a5"; + end process; + + + p_clk: process + begin + clk <= '0'; + wait for CLK_PERIOD/2; + clk <= '1'; + wait for CLK_PERIOD/2; + end process; + +end; diff --git a/libraries/utility/wb_bridge.vhd b/libraries/utility/wb_bridge.vhd new file mode 100644 index 0000000..c96e14b --- /dev/null +++ b/libraries/utility/wb_bridge.vhd @@ -0,0 +1,94 @@ +library ieee; +use ieee.std_logic_1164.all; + + +entity wb_bridge is + generic ( + A_WIDTH: natural := 32; + D_WIDTH: natural := 8 + ); + port ( + rst_i: in std_logic; + clk_i: in std_logic; + + a_cyc_i: in std_logic; + a_stb_i: in std_logic; + a_we_i: in std_logic; + a_ack_o: out std_logic; + a_adr_i: in std_logic_vector(A_WIDTH-1 downto 0); + a_dat_i: in std_logic_vector(D_WIDTH-1 downto 0); + a_dat_o: out std_logic_vector(D_WIDTH-1 downto 0); + + b_cyc_o: out std_logic; + b_stb_o: out std_logic; + b_we_o: out std_logic; + b_ack_i: in std_logic; + b_adr_o: out std_logic_vector(A_WIDTH-1 downto 0); + b_dat_o: out std_logic_vector(D_WIDTH-1 downto 0); + b_dat_i: in std_logic_vector(D_WIDTH-1 downto 0) + ); +end wb_bridge; + +architecture behavioral of wb_bridge is + + signal cyc_reg: std_logic; + signal stb_reg: std_logic; + 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) + 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; + +end behavioral;