repo2/atari_chips/pokeyv2/flash_controller.vhd @ 1333
1103 | markw | ---------------------------------------------------------------------------
|
|
-- (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;
|
|||
1105 | markw | -- 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
|
|||
1103 | markw | ENTITY flash_controller IS
|
|
1251 | markw | GENERIC
|
|
(
|
|||
addr_bits: integer := 16
|
|||
);
|
|||
1103 | markw | PORT
|
|
(
|
|||
CLK : IN STD_LOGIC;
|
|||
1175 | markw | CLK_SLOW : IN STD_LOGIC;
|
|
1103 | markw | 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;
|
|||
1105 | markw | flash_req_request : IN STD_LOGIC_VECTOR(7 downto 0);
|
|
flash_req_complete : OUT STD_LOGIC_VECTOR(7 downto 0);
|
|||
1175 | markw | flash_req_complete_slow : OUT STD_LOGIC_VECTOR(7 downto 0);
|
|
1103 | markw | ||
1251 | markw | flash_req1_addr : IN STD_LOGIC_VECTOR(addr_bits-1 downto 0) := (others=>'0');
|
|
1105 | markw | flash_req2_addr : IN STD_LOGIC_VECTOR(12 downto 0) := (others=>'0');
|
|
flash_req3_addr : IN STD_LOGIC_VECTOR(12 downto 0) := (others=>'0');
|
|||
1251 | markw | 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');
|
|||
1105 | markw | 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');
|
|||
1103 | markw | ||
-- Output
|
|||
1175 | markw | flash_data_out : OUT STD_LOGIC_VECTOR(31 downto 0);
|
|
flash_data_out_slow : OUT STD_LOGIC_VECTOR(31 downto 0)
|
|||
1103 | markw | );
|
|
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
|
|||
1251 | markw | avmm_data_addr : in std_logic_vector(addr_bits-1 downto 0) := (others => '0'); -- data.address
|
|
1103 | markw | 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
|
|||
1105 | markw | avmm_data_burstcount : in std_logic_vector(1 downto 0) := (others => '0'); -- .burstcount
|
|
1103 | markw | 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);
|
|||
1251 | markw | signal flash_data_addr : std_logic_vector(addr_bits-1 downto 0);
|
|
1103 | markw | 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;
|
|||
1105 | markw | signal flash_data_burstcount : std_logic_vector(1 downto 0);
|
|
1103 | markw | ||
1333 | markw | 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";
|
|||
1103 | markw | ||
1251 | markw | signal request_addr_reg : std_logic_vector(addr_bits-1 downto 0);
|
|
signal request_addr_next : std_logic_vector(addr_bits-1 downto 0);
|
|||
1103 | markw | 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;
|
|||
1105 | markw | signal output_reg : std_logic_vector(7 downto 0);
|
|
signal output_next : std_logic_vector(7 downto 0);
|
|||
1103 | markw | ||
1105 | markw | signal robin_reg : std_logic_vector(7 downto 0);
|
|
signal robin_next : std_logic_vector(7 downto 0);
|
|||
1103 | markw | signal complete : std_logic;
|
|
1205 | markw | signal update_robin : std_logic;
|
|
1103 | markw | signal flash_read : std_logic;
|
|
signal flash_readvalid : std_logic;
|
|||
1333 | markw | signal flash_write_next : std_logic;
|
|
signal flash_write_reg : std_logic;
|
|||
1103 | markw | signal flash_waitrequest : std_logic;
|
|
signal flash_do : std_logic_vector(31 downto 0);
|
|||
1109 | markw | ||
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);
|
|||
1103 | markw | ||
1175 | markw | 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);
|
|||
1103 | markw | 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,
|
|||
1310 | markw | --avmm_data_burstcount => "10",
|
|
1293 | markw | avmm_data_burstcount => "01",
|
|
1103 | markw | ||
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');
|
|||
1105 | markw | robin_reg <= "10000000";
|
|
1109 | markw | flash_do_reg <= (others=>'0');
|
|
flash_complete_reg <= (others=>'0');
|
|||
1333 | markw | flash_write_reg <= '0';
|
|
1103 | markw | 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;
|
|||
1105 | markw | robin_reg <= robin_next;
|
|
1109 | markw | flash_do_reg <= flash_do_next;
|
|
flash_complete_reg <= flash_complete_next;
|
|||
1333 | markw | flash_write_reg <= flash_write_next;
|
|
1103 | markw | end if;
|
|
end process;
|
|||
1175 | markw | 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;
|
|||
1103 | markw | -- state machine
|
|
1105 | markw | -- Requests handled round robin
|
|
1103 | markw | -- TODO burst!
|
|
process(state_reg,request_addr_reg,request_di_reg,device_reg,output_reg,
|
|||
1105 | markw | robin_reg,
|
|
flash_req_request,
|
|||
1103 | markw | ||
flash_req1_addr, flash_req1_data_in, flash_req1_write_n, flash_req1_addr_config,
|
|||
1105 | markw | flash_req2_addr, flash_req3_addr, flash_req4_addr,
|
|
flash_req5_addr, flash_req6_addr, flash_req7_addr, flash_req8_addr,
|
|||
1103 | markw | ||
1205 | markw | flash_readvalid, flash_waitrequest,
|
|
1333 | markw | flash_write_reg,
|
|
1205 | markw | complete,
|
|
update_robin
|
|||
1103 | markw | )
|
|
1251 | markw | variable addr : std_logic_vector(addr_bits-1 downto 0);
|
|
1105 | markw | variable device : std_logic;
|
|
variable request: std_logic;
|
|||
1103 | markw | 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;
|
|||
1205 | markw | robin_next <= robin_reg;
|
|
1103 | markw | ||
complete <= '0';
|
|||
flash_read <= '0';
|
|||
1333 | markw | flash_write_next <= flash_write_reg;
|
|
1103 | markw | ||
1105 | markw | device := '0';
|
|
addr := (others=>'0');
|
|||
case robin_reg is
|
|||
when x"01" =>
|
|||
addr := flash_req1_addr;
|
|||
device := flash_req1_addr_config;
|
|||
when x"02" =>
|
|||
1112 | markw | addr(12 downto 0) := flash_req2_addr;
|
|
1105 | markw | when x"04" =>
|
|
1112 | markw | addr(12 downto 0) := flash_req3_addr;
|
|
1105 | markw | when x"08" =>
|
|
1213 | markw | addr := flash_req4_addr;
|
|
1105 | markw | when x"10" =>
|
|
1213 | markw | addr := flash_req5_addr;
|
|
1105 | markw | when x"20" =>
|
|
1112 | markw | addr(12 downto 0) := flash_req6_addr;
|
|
1105 | markw | when x"40" =>
|
|
1112 | markw | addr(12 downto 0) := flash_req7_addr;
|
|
1105 | markw | when others =>
|
|
1112 | markw | addr(12 downto 0) := flash_req8_addr;
|
|
1105 | markw | end case;
|
|
1205 | markw | ||
update_robin <= complete;
|
|||
if (update_robin='1') then
|
|||
robin_next <= robin_reg(6 downto 0)&robin_reg(7);
|
|||
end if;
|
|||
1103 | markw | case state_reg is
|
|
when state_idle=>
|
|||
1105 | markw | if (or_reduce(robin_reg and flash_req_request)='1') then
|
|
request_addr_next <= addr;
|
|||
1103 | markw | request_di_next <= flash_req1_data_in;
|
|
1105 | markw | if (robin_reg(0)='1' and flash_req1_write_n='0') then --write
|
|
state_next <= state_write;
|
|||
else
|
|||
1103 | markw | state_next <= state_read;
|
|
end if;
|
|||
1105 | markw | output_next <= robin_reg;
|
|
1103 | markw | ||
1105 | markw | device_next <= device;
|
|
1205 | markw | else
|
|
update_robin <= '1';
|
|||
1103 | markw | end if;
|
|
when state_read=>
|
|||
flash_read <= '1';
|
|||
1330 | markw | state_next <= state_read_wait;
|
|
1103 | markw | when state_read_wait =>
|
|
if (flash_readvalid = '1') then
|
|||
1333 | markw | complete <= '1';
|
|
1109 | markw | state_next <= state_delay;
|
|
1103 | markw | end if;
|
|
when state_write=>
|
|||
1333 | markw | flash_write_next <= '1';
|
|
state_next <= state_write_wait;
|
|||
when state_write_wait=>
|
|||
1103 | markw | if (flash_waitrequest='0') then
|
|
1333 | markw | flash_write_next <= '0';
|
|
complete <= '1';
|
|||
1109 | markw | state_next <= state_delay;
|
|
1103 | markw | end if;
|
|
1109 | markw | when state_delay=>
|
|
1179 | markw | 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=>
|
|||
1333 | markw | if (flash_waitrequest='0') then
|
|
state_next <= state_idle;
|
|||
end if;
|
|||
1103 | markw | when others=>
|
|
state_next <= state_idle;
|
|||
end case;
|
|||
end process;
|
|||
-- mux on selected device
|
|||
process(device_reg, flash_data_do, flash_config_do,
|
|||
1333 | markw | flash_write_reg,flash_read,flash_data_readvalid,flash_data_waitrequest)
|
|
1103 | markw | 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;
|
|||
1333 | markw | flash_config_write <= flash_write_reg;
|
|
1103 | markw | flash_readvalid <= '1';
|
|
elsif (device_reg='0') then --main
|
|||
flash_do <= flash_data_do;
|
|||
flash_data_read <= flash_read;
|
|||
1333 | markw | flash_data_write <= flash_write_reg;
|
|
1103 | markw | flash_readvalid <= flash_data_readvalid;
|
|
flash_waitrequest <= flash_data_waitrequest;
|
|||
end if;
|
|||
end process;
|
|||
1109 | markw | -- register complete
|
|
flash_complete_next <= output_reg and (complete&complete&complete&complete&complete&complete&complete&complete);
|
|||
1175 | markw | 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;
|
|||
1109 | markw | ||
1103 | markw | -- mux on who requested
|
|
1109 | markw | flash_req_complete <= flash_complete_reg;
|
|
1175 | markw | flash_req_complete_slow <= flash_complete_slow_reg;
|
|
1103 | markw | ||
-- outputs
|
|||
1109 | markw | flash_data_out <= flash_do_reg;
|
|
1175 | markw | flash_data_out_slow <= flash_do_slow_reg;
|
|
1103 | markw | ||
end vhdl;
|