From 7d60f0ae1b073b4a46eb042a7ab28f4733f9d6a1 Mon Sep 17 00:00:00 2001 From: tmeissner Date: Mon, 1 Dec 2014 23:22:31 +0100 Subject: [PATCH] add simple wishbone master and slave with support of classic single write and read as specified in the wishbone spec b4; add unit tests for wishbone m,aster & slave --- syn/WishBoneMasterE.vhd | 119 ++++++++++++++++++ syn/WishBoneSlaveE.vhd | 90 ++++++++++++++ test/Makefile | 8 ++ test/WishBoneT.vhd | 259 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 476 insertions(+) create mode 100644 syn/WishBoneMasterE.vhd create mode 100644 syn/WishBoneSlaveE.vhd create mode 100644 test/WishBoneT.vhd diff --git a/syn/WishBoneMasterE.vhd b/syn/WishBoneMasterE.vhd new file mode 100644 index 0000000..4d60b52 --- /dev/null +++ b/syn/WishBoneMasterE.vhd @@ -0,0 +1,119 @@ +library ieee; + use ieee.std_logic_1164.all; + + + +entity WishBoneMasterE is + generic ( + G_ADR_WIDTH : positive := 8; --* address bus width + G_DATA_WIDTH : positive := 8 --* data bus width + ); + port ( + --+ wishbone system if + WbRst_i : in std_logic; + WbClk_i : in std_logic; + --+ wishbone outputs + WbCyc_o : out std_logic; + WbStb_o : out std_logic; + WbWe_o : out std_logic; + WbAdr_o : out std_logic_vector(G_ADR_WIDTH-1 downto 0); + WbDat_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + --+ wishbone inputs + WbDat_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0); + WbAck_i : in std_logic; + WbErr_i : in std_logic; + --+ local register if + LocalWen_i : in std_logic; + LocalRen_i : in std_logic; + LocalAdress_i : in std_logic_vector(G_ADR_WIDTH-1 downto 0); + LocalData_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0); + LocalData_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + LocalAck_o : out std_logic; + LocalError_o : out std_logic + ); +end entity WishBoneMasterE; + + + +architecture rtl of WishBoneMasterE is + + + type t_wb_master_fsm is (IDLE, ADDRESS, DATA); + signal s_wb_master_fsm : t_wb_master_fsm; + + signal s_wb_wen : std_logic; + + +begin + + + --+ Wishbone master control state machine + WbMasterStatesP : process (WbClk_i) is + begin + if (rising_edge(WbClk_i)) then + if (WbRst_i = '1') then + s_wb_master_fsm <= IDLE; + else + WbReadC : case s_wb_master_fsm is + + when IDLE => + if (LocalWen_i = '1' or LocalRen_i = '1') then + s_wb_master_fsm <= ADDRESS; + end if; + + when ADDRESS => + if (WbErr_i = '0') then + s_wb_master_fsm <= DATA; + else + s_wb_master_fsm <= IDLE; + end if; + + when DATA => + if (WbErr_i = '1' or WbAck_i = '1') then + s_wb_master_fsm <= IDLE; + end if; + + when others => + s_wb_master_fsm <= IDLE; + + end case; + end if; + end if; + end process WbMasterStatesP; + + + --+ combinatoral local register if outputs + LocalData_o <= WbDat_i when s_wb_master_fsm = DATA else (others => '0'); + LocalError_o <= WbErr_i when s_wb_master_fsm /= IDLE else '0'; + LocalAck_o <= WbAck_i when s_wb_master_fsm = DATA and WbErr_i = '0' else '0'; + + --+ combinatoral wishbone if outputs + WbStb_o <= '1' when s_wb_master_fsm /= IDLE else '0'; + WbCyc_o <= '1' when s_wb_master_fsm /= IDLE else '0'; + WbWe_o <= s_wb_wen when s_wb_master_fsm /= IDLE else '0'; + + + --+ registered wishbone if outputs + OutRegsP : process (WbClk_i) is + begin + if(rising_edge(WbClk_i)) then + if(WbRst_i = '1') then + WbAdr_o <= (others => '0'); + WbDat_o <= (others => '0'); + s_wb_wen <= '0'; + else + if (s_wb_master_fsm = IDLE) then + if (LocalWen_i = '1' or LocalRen_i = '1') then + WbAdr_o <= LocalAdress_i; + s_wb_wen <= LocalWen_i; + end if; + if (LocalWen_i = '1') then + WbDat_o <= LocalData_i; + end if; + end if; + end if; + end if; + end process OutRegsP; + + +end architecture rtl; diff --git a/syn/WishBoneSlaveE.vhd b/syn/WishBoneSlaveE.vhd new file mode 100644 index 0000000..0dc1aa1 --- /dev/null +++ b/syn/WishBoneSlaveE.vhd @@ -0,0 +1,90 @@ +library ieee; + use ieee.std_logic_1164.all; + + + +entity WishBoneSlaveE is + generic ( + G_ADR_WIDTH : positive := 8; --* address bus width + G_DATA_WIDTH : positive := 8 --* data bus width + ); + port ( + --+ wishbone system if + WbRst_i : in std_logic; + WbClk_i : in std_logic; + --+ wishbone inputs + WbCyc_i : in std_logic; + WbStb_i : in std_logic; + WbWe_i : in std_logic; + WbAdr_i : in std_logic_vector(G_ADR_WIDTH-1 downto 0); + WbDat_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0); + --+ wishbone outputs + WbDat_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + WbAck_o : out std_logic; + WbErr_o : out std_logic; + --+ local register if + LocalWen_o : out std_logic; + LocalRen_o : out std_logic; + LocalAdress_o : out std_logic_vector(G_ADR_WIDTH-1 downto 0); + LocalData_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + LocalData_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0) + ); +end entity WishBoneSlaveE; + + + +architecture rtl of WishBoneSlaveE is + + + type t_wb_slave_fsm is (IDLE, ADDRESS, DATA); + signal s_wb_slave_fsm : t_wb_slave_fsm; + + signal s_wb_active : boolean; + + +begin + + + WbSlaveControlP : process (WbClk_i) is + begin + if (rising_edge(WbClk_i)) then + if (WbRst_i = '1') then + s_wb_slave_fsm <= IDLE; + else + WbReadC : case s_wb_slave_fsm is + + when IDLE => + s_wb_slave_fsm <= ADDRESS; + + when ADDRESS => + if s_wb_active then + s_wb_slave_fsm <= DATA; + end if; + + when DATA => + s_wb_slave_fsm <= ADDRESS; + + when others => + s_wb_slave_fsm <= IDLE; + + end case; + end if; + end if; + end process WbSlaveControlP; + + + s_wb_active <= true when s_wb_slave_fsm /= IDLE and WbCyc_i = '1' and WbStb_i = '1' else false; + + --+ local register if outputs + LocalWen_o <= WbWe_i when s_wb_slave_fsm = DATA and s_wb_active else '0'; + LocalRen_o <= not(WbWe_i) when s_wb_slave_fsm = ADDRESS and s_wb_active else '0'; + LocalAdress_o <= WbAdr_i when s_wb_slave_fsm /= IDLE and s_wb_active else (others => '0'); + LocalData_o <= WbDat_i when s_wb_slave_fsm = DATA and s_wb_active and WbWe_i = '1' else (others => '0'); + + --+ wishbone if outputs + WbDat_o <= LocalData_i when s_wb_slave_fsm = DATA and WbWe_i = '0' else (others => '0'); + WbAck_o <= '1' when s_wb_slave_fsm = DATA else '0'; + WbErr_o <= '0'; + + +end architecture rtl; \ No newline at end of file diff --git a/test/Makefile b/test/Makefile index 74a6ea7..8e62aa9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -36,6 +36,13 @@ spit : vhdl2008 osvvm SpiT.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd $(SIM_ ghdl -e --std=$(VHD_STD) --ieee=synopsys SpiT ghdl -r --std=$(VHD_STD) SpiT --wave=spit.ghw +wishbonet : vhdl2008 osvvm WishBoneT.vhd $(SYN_SRC)/WishBoneMasterE.vhd $(SYN_SRC)/WishBoneSlaveE.vhd + ghdl -a --std=$(VHD_STD) --work=libvhdl $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd $(SIM_SRC)/QueueP.vhd + ghdl -a --std=$(VHD_STD) -fpsl $(SYN_SRC)/WishBoneMasterE.vhd $(SYN_SRC)/WishBoneSlaveE.vhd + ghdl -a --std=$(VHD_STD) --ieee=synopsys WishBoneT.vhd + ghdl -e --std=$(VHD_STD) --ieee=synopsys WishBoneT + ghdl -r --std=$(VHD_STD) --ieee=synopsys WishBoneT --wave=wishbonet.ghw + .PHONY: clean clean: rm -f *.o @@ -45,6 +52,7 @@ clean: rm -f stringt rm -f simt rm -f spit + rm -f wishbonet .PHONY: distclean distclean: clean diff --git a/test/WishBoneT.vhd b/test/WishBoneT.vhd new file mode 100644 index 0000000..cce740b --- /dev/null +++ b/test/WishBoneT.vhd @@ -0,0 +1,259 @@ +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +--+ including vhdl 2008 libraries +--+ These lines can be commented out when using +--+ a simulator with built-in VHDL 2008 support +library ieee_proposed; + use ieee_proposed.standard_additions.all; + use ieee_proposed.std_logic_1164_additions.all; + use ieee_proposed.numeric_std_additions.all; + +library osvvm; + use osvvm.RandomPkg.all; + +library libvhdl; + use libvhdl.AssertP.all; + use libvhdl.SimP.all; + use libvhdl.QueueP.all; + + + +entity WishBoneT is +end entity WishBoneT; + + + +architecture sim of WishBoneT is + + + component WishBoneMasterE is + generic ( + G_ADR_WIDTH : positive := 8; --* address bus width + G_DATA_WIDTH : positive := 8 --* data bus width + ); + port ( + --+ wishbone system if + WbRst_i : in std_logic; + WbClk_i : in std_logic; + --+ wishbone outputs + WbCyc_o : out std_logic; + WbStb_o : out std_logic; + WbWe_o : out std_logic; + WbAdr_o : out std_logic_vector(G_ADR_WIDTH-1 downto 0); + WbDat_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + --+ wishbone inputs + WbDat_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0); + WbAck_i : in std_logic; + WbErr_i : in std_logic; + --+ local register if + LocalWen_i : in std_logic; + LocalRen_i : in std_logic; + LocalAdress_i : in std_logic_vector(G_ADR_WIDTH-1 downto 0); + LocalData_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0); + LocalData_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + LocalAck_o : out std_logic; + LocalError_o : out std_logic + ); + end component WishBoneMasterE; + + + component WishBoneSlaveE is + generic ( + G_ADR_WIDTH : positive := 8; --* address bus width + G_DATA_WIDTH : positive := 8 --* data bus width + ); + port ( + --+ wishbone system if + WbRst_i : in std_logic; + WbClk_i : in std_logic; + --+ wishbone inputs + WbCyc_i : in std_logic; + WbStb_i : in std_logic; + WbWe_i : in std_logic; + WbAdr_i : in std_logic_vector(G_ADR_WIDTH-1 downto 0); + WbDat_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0); + --* wishbone outputs + WbDat_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + WbAck_o : out std_logic; + WbErr_o : out std_logic; + --+ local register if + LocalWen_o : out std_logic; + LocalRen_o : out std_logic; + LocalAdress_o : out std_logic_vector(G_ADR_WIDTH-1 downto 0); + LocalData_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0); + LocalData_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0) + ); + end component WishBoneSlaveE; + + + --* testbench global clock period + constant C_PERIOD : time := 5 ns; + --* Wishbone data width + constant C_DATA_WIDTH : natural := 8; + --* Wishbone address width + constant C_ADDRESS_WIDTH : natural := 8; + + --* testbench global clock + signal s_wb_clk : std_logic := '1'; + --* testbench global reset + signal s_wb_reset : std_logic := '1'; + + --+ test done array with entry for each test + signal s_test_done : boolean; + + + signal s_wb_cyc : std_logic; + signal s_wb_stb : std_logic; + signal s_wb_we : std_logic; + signal s_wb_adr : std_logic_vector(C_ADDRESS_WIDTH-1 downto 0); + signal s_wb_master_data : std_logic_vector(C_DATA_WIDTH-1 downto 0); + signal s_wb_slave_data : std_logic_vector(C_DATA_WIDTH-1 downto 0); + signal s_wb_ack : std_logic; + signal s_wb_err : std_logic; + signal s_master_local_wen : std_logic; + signal s_master_local_ren : std_logic; + signal s_master_local_adress : std_logic_vector(C_ADDRESS_WIDTH-1 downto 0); + signal s_master_local_din : std_logic_vector(C_DATA_WIDTH-1 downto 0); + signal s_master_local_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0); + signal s_master_local_ack : std_logic; + signal s_master_local_error : std_logic; + signal s_slave_local_wen : std_logic; + signal s_slave_local_ren : std_logic; + signal s_slave_local_adress : std_logic_vector(C_ADDRESS_WIDTH-1 downto 0); + signal s_slave_local_dout : std_logic_vector(C_DATA_WIDTH-1 downto 0); + signal s_slave_local_din : std_logic_vector(C_DATA_WIDTH-1 downto 0); + + type t_register is array (0 to integer'(2**C_ADDRESS_WIDTH-1)) of std_logic_vector(C_DATA_WIDTH-1 downto 0); + + shared variable sv_wishbone_queue : t_list_queue; + + +begin + + + --* testbench global clock + s_wb_clk <= not(s_wb_clk) after C_PERIOD/2 when not(s_test_done) else '0'; + --* testbench global reset + s_wb_reset <= '0' after C_PERIOD * 5; + + + WbMasterLocalP : process is + variable v_random : RandomPType; + variable v_wbmaster_data : std_logic_vector(C_DATA_WIDTH-1 downto 0); + begin + v_random.InitSeed(v_random'instance_name); + v_wbmaster_data := (others => '0'); + s_master_local_din <= (others => '0'); + s_master_local_adress <= (others => '0'); + s_master_local_wen <= '0'; + s_master_local_ren <= '0'; + wait until s_wb_reset = '0'; + -- write the wishbone slave registers + for i in 0 to integer'(2**C_ADDRESS_WIDTH-1) loop + v_wbmaster_data := v_random.RandSlv(C_DATA_WIDTH); + s_master_local_din <= v_wbmaster_data; + s_master_local_adress <= std_logic_vector(to_unsigned(i, C_ADDRESS_WIDTH)); + s_master_local_wen <= '1'; + wait until rising_edge(s_wb_clk); + s_master_local_din <= (others => '0'); + s_master_local_adress <= (others => '0'); + s_master_local_wen <= '0'; + wait until rising_edge(s_wb_clk) and s_master_local_ack = '1'; + sv_wishbone_queue.push(v_wbmaster_data); + end loop; + -- read back and check the wishbone slave registers + for i in 0 to integer'(2**C_ADDRESS_WIDTH-1) loop + s_master_local_adress <= std_logic_vector(to_unsigned(i, C_ADDRESS_WIDTH)); + s_master_local_ren <= '1'; + wait until rising_edge(s_wb_clk); + s_master_local_adress <= (others => '0'); + s_master_local_ren <= '0'; + wait until rising_edge(s_wb_clk) and s_master_local_ack = '1'; + sv_wishbone_queue.pop(v_wbmaster_data); + assert_equal(s_master_local_dout, v_wbmaster_data); + end loop; + report "INFO: Test successfully finished!"; + s_test_done <= true; + wait; + end process WbMasterLocalP; + + + i_WishBoneMasterE : WishBoneMasterE + generic map ( + G_ADR_WIDTH => C_ADDRESS_WIDTH, + G_DATA_WIDTH => C_DATA_WIDTH + ) + port map ( + --+ wishbone system if + WbRst_i => s_wb_reset, + WbClk_i => s_wb_clk, + --+ wishbone outputs + WbCyc_o => s_wb_cyc, + WbStb_o => s_wb_stb, + WbWe_o => s_wb_we, + WbAdr_o => s_wb_adr, + WbDat_o => s_wb_master_data, + --+ wishbone inputs + WbDat_i => s_wb_slave_data, + WbAck_i => s_wb_ack, + WbErr_i => s_wb_err, + --+ local register if + LocalWen_i => s_master_local_wen, + LocalRen_i => s_master_local_ren, + LocalAdress_i => s_master_local_adress, + LocalData_i => s_master_local_din, + LocalData_o => s_master_local_dout, + LocalAck_o => s_master_local_ack, + LocalError_o => s_master_local_error + ); + + + i_WishBoneSlaveE : WishBoneSlaveE + generic map ( + G_ADR_WIDTH => C_ADDRESS_WIDTH, + G_DATA_WIDTH => C_DATA_WIDTH + ) + port map ( + --+ wishbone system if + WbRst_i => s_wb_reset, + WbClk_i => s_wb_clk, + --+ wishbone inputs + WbCyc_i => s_wb_cyc, + WbStb_i => s_wb_stb, + WbWe_i => s_wb_we, + WbAdr_i => s_wb_adr, + WbDat_i => s_wb_master_data, + --* wishbone outputs + WbDat_o => s_wb_slave_data, + WbAck_o => s_wb_ack, + WbErr_o => s_wb_err, + --+ local register if + LocalWen_o => s_slave_local_wen, + LocalRen_o => s_slave_local_ren, + LocalAdress_o => s_slave_local_adress, + LocalData_o => s_slave_local_dout, + LocalData_i => s_slave_local_din + ); + + + WbSlaveLocalP : process (s_wb_clk) is + variable v_register : t_register := (others => (others => '0')); + begin + if (rising_edge(s_wb_clk)) then + if (s_wb_reset = '1') then + v_register := (others => (others => '0')); + s_slave_local_din <= (others => '0'); + else + if (s_slave_local_wen = '1') then + v_register(to_integer(unsigned(s_slave_local_adress))) := s_slave_local_dout; + elsif (s_slave_local_ren = '1') then + s_slave_local_din <= v_register(to_integer(unsigned(s_slave_local_adress))); + end if; + end if; + end if; + end process WbSlaveLocalP; + + +end architecture sim; \ No newline at end of file