--------------------------------------------------------------------------- -- (c) 2020 mark watson -- I am happy for anyone to use this for non-commercial use. -- If my vhdl files are used commercially or otherwise sold, -- please contact me for explicit permission at scrameta (gmail). -- This applies for source and binary form and derived works. --------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.all; use ieee.numeric_std.all; USE IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.STD_LOGIC_MISC.all; LIBRARY work; -- takes about 5-6 cycles per read (depending on family) -- So at 116MHz can service all 8 clients at >2MHz - if they all request at once ENTITY flash_controller IS GENERIC ( addr_bits: integer := 16 ); PORT ( CLK : IN STD_LOGIC; CLK_SLOW : IN STD_LOGIC; RESET_N : IN STD_LOGIC; -- Request from device 1 (cpu) flash_req1_addr_config : IN STD_LOGIC; -- 1 access config, 0 access main flash flash_req1_data_in : IN STD_LOGIC_VECTOR(31 downto 0); flash_req1_write_n: IN STD_LOGIC; flash_req_request : IN STD_LOGIC_VECTOR(7 downto 0); flash_req_complete : OUT STD_LOGIC_VECTOR(7 downto 0); flash_req_complete_slow : OUT STD_LOGIC_VECTOR(7 downto 0); flash_req1_addr : IN STD_LOGIC_VECTOR(addr_bits-1 downto 0) := (others=>'0'); flash_req2_addr : IN STD_LOGIC_VECTOR(12 downto 0) := (others=>'0'); flash_req3_addr : IN STD_LOGIC_VECTOR(12 downto 0) := (others=>'0'); flash_req4_addr : IN STD_LOGIC_VECTOR(addr_bits-1 downto 0) := (others=>'0'); flash_req5_addr : IN STD_LOGIC_VECTOR(addr_bits-1 downto 0) := (others=>'0'); flash_req6_addr : IN STD_LOGIC_VECTOR(12 downto 0) := (others=>'0'); flash_req7_addr : IN STD_LOGIC_VECTOR(12 downto 0) := (others=>'0'); flash_req8_addr : IN STD_LOGIC_VECTOR(12 downto 0) := (others=>'0'); -- Output flash_data_out : OUT STD_LOGIC_VECTOR(31 downto 0); flash_data_out_slow : OUT STD_LOGIC_VECTOR(31 downto 0) ); END flash_controller; ARCHITECTURE vhdl OF flash_controller IS component flash is port ( clock : in std_logic := '0'; -- clk.clk avmm_csr_addr : in std_logic := '0'; -- csr.address avmm_csr_read : in std_logic := '0'; -- .read avmm_csr_writedata : in std_logic_vector(31 downto 0) := (others => '0'); -- .writedata avmm_csr_write : in std_logic := '0'; -- .write avmm_csr_readdata : out std_logic_vector(31 downto 0); -- .readdata avmm_data_addr : in std_logic_vector(addr_bits-1 downto 0) := (others => '0'); -- data.address avmm_data_read : in std_logic := '0'; -- .read avmm_data_writedata : in std_logic_vector(31 downto 0) := (others => '0'); -- .writedata avmm_data_write : in std_logic := '0'; -- .write avmm_data_readdata : out std_logic_vector(31 downto 0); -- .readdata avmm_data_waitrequest : out std_logic; -- .waitrequest avmm_data_readdatavalid : out std_logic; -- .readdatavalid avmm_data_burstcount : in std_logic_vector(1 downto 0) := (others => '0'); -- .burstcount reset_n : in std_logic := '0' -- nreset.reset_n ); end component; signal flash_config_addr : std_logic; signal flash_config_read : std_logic; signal flash_config_di : std_logic_vector(31 downto 0); signal flash_config_write : std_logic; signal flash_config_do : std_logic_vector(31 downto 0); signal flash_data_addr : std_logic_vector(addr_bits-1 downto 0); signal flash_data_read : std_logic; signal flash_data_di : std_logic_vector(31 downto 0); signal flash_data_write : std_logic; signal flash_data_do : std_logic_vector(31 downto 0); signal flash_data_waitrequest : std_logic; signal flash_data_readvalid : std_logic; signal flash_data_burstcount : std_logic_vector(1 downto 0); signal state_reg : std_logic_vector(3 downto 0); signal state_next : std_logic_vector(3 downto 0); constant state_idle : std_logic_vector(3 downto 0) := "0000"; constant state_read : std_logic_vector(3 downto 0) := "0001"; constant state_write : std_logic_vector(3 downto 0) := "0010"; constant state_read_wait : std_logic_vector(3 downto 0) := "0011"; constant state_delay : std_logic_vector(3 downto 0) := "0100"; constant state_delay2 : std_logic_vector(3 downto 0) := "0101"; constant state_delay3 : std_logic_vector(3 downto 0) := "0110"; constant state_delay4 : std_logic_vector(3 downto 0) := "0111"; constant state_write_wait : std_logic_vector(3 downto 0) := "1000"; signal request_addr_reg : std_logic_vector(addr_bits-1 downto 0); signal request_addr_next : std_logic_vector(addr_bits-1 downto 0); signal request_di_reg : std_logic_vector(31 downto 0); signal request_di_next : std_logic_vector(31 downto 0); signal device_reg : std_logic; signal device_next : std_logic; signal output_reg : std_logic_vector(7 downto 0); signal output_next : std_logic_vector(7 downto 0); signal robin_reg : std_logic_vector(7 downto 0); signal robin_next : std_logic_vector(7 downto 0); signal complete : std_logic; signal update_robin : std_logic; signal flash_read_next : std_logic; signal flash_read_reg : std_logic; signal flash_readvalid : std_logic; signal flash_write_next : std_logic; signal flash_write_reg : std_logic; signal flash_waitrequest : std_logic; signal flash_do : std_logic_vector(31 downto 0); signal flash_do_next : std_logic_vector(31 downto 0); signal flash_do_reg : std_logic_vector(31 downto 0); signal flash_complete_next : std_logic_vector(7 downto 0); signal flash_complete_reg : std_logic_vector(7 downto 0); signal flash_do_slow_next : std_logic_vector(31 downto 0); signal flash_do_slow_reg : std_logic_vector(31 downto 0); signal flash_complete_slow_next : std_logic_vector(7 downto 0); signal flash_complete_slow_reg : std_logic_vector(7 downto 0); BEGIN flash1 : flash port map ( clock => clk, avmm_csr_addr => request_addr_reg(0), avmm_csr_read => flash_config_read, avmm_csr_writedata => request_di_reg, avmm_csr_write => flash_config_write, avmm_csr_readdata => flash_config_do, avmm_data_addr => request_addr_reg, avmm_data_read => flash_data_read, avmm_data_writedata => request_di_reg, avmm_data_write => flash_data_write, avmm_data_readdata => flash_data_do, avmm_data_waitrequest => flash_data_waitrequest, avmm_data_readdatavalid => flash_data_readvalid, --avmm_data_burstcount => "10", avmm_data_burstcount => "01", reset_n => reset_n ); process(clk,reset_n) begin if (reset_n='0') then state_reg <= state_idle; request_addr_reg <= (others=>'0'); request_di_reg <= (others=>'0'); device_reg <= '0'; output_reg <= (others=>'0'); robin_reg <= "10000000"; flash_do_reg <= (others=>'0'); flash_complete_reg <= (others=>'0'); flash_write_reg <= '0'; flash_read_reg <= '0'; elsif (clk'event and clk='1') then state_reg <= state_next; request_addr_reg <= request_addr_next; request_di_reg <= request_di_next; device_reg <= device_next; output_reg <= output_next; robin_reg <= robin_next; flash_do_reg <= flash_do_next; flash_complete_reg <= flash_complete_next; flash_write_reg <= flash_write_next; flash_read_reg <= flash_read_next; end if; end process; process(clk_slow,reset_n) begin if (reset_n='0') then flash_complete_slow_reg <= (others=>'0'); flash_do_slow_reg <= (others=>'0'); elsif (clk_slow'event and clk_slow='1') then flash_complete_slow_reg <= flash_complete_slow_next; flash_do_slow_reg <= flash_do_slow_next; end if; end process; -- state machine -- Requests handled round robin -- TODO burst! process(state_reg,request_addr_reg,request_di_reg,device_reg,output_reg, robin_reg, flash_req_request, flash_req1_addr, flash_req1_data_in, flash_req1_write_n, flash_req1_addr_config, flash_req2_addr, flash_req3_addr, flash_req4_addr, flash_req5_addr, flash_req6_addr, flash_req7_addr, flash_req8_addr, flash_readvalid, flash_waitrequest, flash_write_reg, flash_read_reg, complete, update_robin ) variable addr : std_logic_vector(addr_bits-1 downto 0); variable device : std_logic; variable request: std_logic; begin state_next <= state_reg; request_addr_next <= request_addr_reg; request_di_next <= request_di_reg; device_next <= device_reg; output_next <= output_reg; robin_next <= robin_reg; complete <= '0'; flash_read_next <= flash_read_reg; flash_write_next <= flash_write_reg; device := '0'; addr := (others=>'0'); case robin_reg is when x"01" => addr := flash_req1_addr; device := flash_req1_addr_config; when x"02" => addr(12 downto 0) := flash_req2_addr; when x"04" => addr(12 downto 0) := flash_req3_addr; when x"08" => addr := flash_req4_addr; when x"10" => addr := flash_req5_addr; when x"20" => addr(12 downto 0) := flash_req6_addr; when x"40" => addr(12 downto 0) := flash_req7_addr; when others => addr(12 downto 0) := flash_req8_addr; end case; update_robin <= complete; if (update_robin='1') then robin_next <= robin_reg(6 downto 0)&robin_reg(7); end if; case state_reg is when state_idle=> if (or_reduce(robin_reg and flash_req_request)='1') then request_addr_next <= addr; request_di_next <= flash_req1_data_in; if (robin_reg(0)='1' and flash_req1_write_n='0') then --write state_next <= state_write; else state_next <= state_read; end if; output_next <= robin_reg; device_next <= device; else update_robin <= '1'; end if; when state_read=> flash_read_next <= '1'; state_next <= state_read_wait; when state_read_wait => if (flash_waitrequest = '0') then flash_read_next <= '0'; end if; if (flash_readvalid = '1') then complete <= '1'; state_next <= state_delay; end if; when state_write=> flash_write_next <= '1'; state_next <= state_write_wait; when state_write_wait=> if (flash_waitrequest='0') then flash_write_next <= '0'; complete <= '1'; state_next <= state_delay; end if; when state_delay=> state_next <= state_delay2; -- client sees complete here, allow client to drop request line before we take next when state_delay2=> state_next <= state_delay3; -- without a 3rd delay we never get readdatavalid!! when state_delay3=> state_next <= state_delay4; when state_delay4=> if (flash_waitrequest='0') then state_next <= state_idle; end if; when others=> state_next <= state_idle; end case; end process; -- mux on selected device process(device_reg, flash_data_do, flash_config_do, flash_write_reg,flash_read_reg,flash_data_readvalid,flash_data_waitrequest) begin flash_do <= (others=>'0'); flash_config_read <= '0'; flash_config_write <= '0'; flash_data_read <= '0'; flash_data_write <= '0'; flash_readvalid <= '0'; flash_waitrequest <= '0'; if (device_reg='1') then --config flash_do <= flash_config_do; flash_config_read <= flash_read_reg; flash_config_write <= flash_write_reg; flash_readvalid <= '1'; elsif (device_reg='0') then --main flash_do <= flash_data_do; flash_data_read <= flash_read_reg; flash_data_write <= flash_write_reg; flash_readvalid <= flash_data_readvalid; flash_waitrequest <= flash_data_waitrequest; end if; end process; -- register complete flash_complete_next <= output_reg and (complete&complete&complete&complete&complete&complete&complete&complete); flash_complete_slow_next <= flash_complete_next or flash_complete_reg; process(flash_do_reg,flash_do,complete) begin flash_do_next <= flash_do_reg; flash_do_slow_next <= flash_do_reg; if (complete='1') then flash_do_next <= flash_do; flash_do_slow_next <= flash_do; end if; end process; -- mux on who requested flash_req_complete <= flash_complete_reg; flash_req_complete_slow <= flash_complete_slow_reg; -- outputs flash_data_out <= flash_do_reg; flash_data_out_slow <= flash_do_slow_reg; end vhdl;