|
---------------------------------------------------------------------------
|
|
-- (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 : 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';
|
|
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;
|
|
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,
|
|
|
|
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 <= '0';
|
|
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 <= '1';
|
|
state_next <= state_read_wait;
|
|
when state_read_wait =>
|
|
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,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;
|
|
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;
|
|
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;
|