---------------------------------------------------------------------- -- Leaf project -- developed by: Daniel Santos -- module: wishbone master control -- 2026 ---------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use work.leaf_pkg.all; entity wb_ctrl is port ( clk_i : in std_logic; rst_i : in std_logic; imrd_en_i : in std_logic; dmrd_en_i : in std_logic; dmwr_en_i : in std_logic; ack_i : in std_logic; err_i : in std_logic; dat_i : in std_logic_vector(XLEN-1 downto 0); dmwr_be_i : in std_logic_vector(3 downto 0); imrd_addr_i : in std_logic_vector(XLEN-1 downto 0); dmrw_addr_i : in std_logic_vector(XLEN-1 downto 0); dmwr_data_i : in std_logic_vector(XLEN-1 downto 0); cyc_o : out std_logic; stb_o : out std_logic; we_o : out std_logic; clk_en_o : out std_logic; reset_o : out std_logic; imrd_err_o : out std_logic; dmrd_err_o : out std_logic; dmwr_err_o : out std_logic; sel_o : out std_logic_vector(3 downto 0); adr_o : out std_logic_vector(XLEN-1 downto 0); dat_o : out std_logic_vector(XLEN-1 downto 0); imrd_data_o : out std_logic_vector(XLEN-1 downto 0); dmrd_data_o : out std_logic_vector(XLEN-1 downto 0) ); end entity wb_ctrl; architecture rtl of wb_ctrl is type state is (START, IDLE, READ_INSTR, BRD_CYCLE, READ_DATA, RMW_CYCLE, WRITE_DATA, EXECUTE, ERROR); signal curr_state: state; signal next_state: state; begin fsm: process(clk_i) begin if rising_edge(clk_i) then if rst_i = '1' then curr_state <= START; else curr_state <= next_state; end if; end if; end process fsm; fsm_next_state: process(curr_state, ack_i, err_i, imrd_en_i, dmrd_en_i, dmwr_en_i) begin case curr_state is when START => next_state <= IDLE; when IDLE => if imrd_en_i = '1' then next_state <= READ_INSTR; else next_state <= IDLE; end if; when READ_INSTR => if ack_i = '1' then if dmrd_en_i = '1' then next_state <= BRD_CYCLE; elsif dmwr_en_i = '1' then next_state <= RMW_CYCLE; else next_state <= EXECUTE; end if; elsif err_i = '1' then next_state <= ERROR; else next_state <= READ_INSTR; end if; when BRD_CYCLE => next_state <= READ_DATA; when READ_DATA => if ack_i = '1' then next_state <= EXECUTE; elsif err_i = '1' then next_state <= ERROR; else next_state <= READ_DATA; end if; when RMW_CYCLE => next_state <= WRITE_DATA; when WRITE_DATA => if ack_i = '1' then next_state <= EXECUTE; elsif err_i = '1' then next_state <= ERROR; else next_state <= WRITE_DATA; end if; when EXECUTE => next_state <= IDLE; when ERROR => next_state <= IDLE; end case; end process fsm_next_state; cyc_o <= '0' when curr_state = EXECUTE or curr_state = START or curr_state = ERROR else '1'; stb_o <= '1' when curr_state = READ_INSTR or curr_state = READ_DATA or curr_state = WRITE_DATA else '0'; we_o <= '1' when curr_state = WRITE_DATA else '0'; sel_o <= dmwr_be_i when curr_state = WRITE_DATA else (others => '1'); adr_o <= dmrw_addr_i when curr_state = READ_DATA or curr_state = WRITE_DATA else imrd_addr_i; dat_o <= dmwr_data_i; clk_en_o <= '1' when curr_state = START or curr_state = EXECUTE or curr_state = ERROR else '0'; reset_o <= '1' when curr_state = START else '0'; imrd_err_o <= imrd_en_i when curr_state = ERROR else '0'; dmrd_err_o <= dmrd_en_i when curr_state = ERROR else '0'; dmwr_err_o <= dmwr_en_i when curr_state = ERROR else '0'; wr_imrd_data: process(clk_i) begin if rising_edge(clk_i) then if rst_i = '1' then imrd_data_o <= (others => '0'); elsif curr_state = READ_INSTR and next_state /= READ_INSTR then imrd_data_o <= dat_i; end if; end if; end process wr_imrd_data; wr_dmrd_data: process(clk_i) begin if rising_edge(clk_i) then if rst_i = '1' then dmrd_data_o <= (others => '0'); elsif curr_state = READ_DATA and next_state /= READ_DATA then dmrd_data_o <= dat_i; end if; end if; end process wr_dmrd_data; end architecture rtl;