- removed register interface - first write data, then command git-svn-id: http://moon:8086/svn/vhdl/trunk@1302 cc03376c-175c-47c8-b038-4cd826a8556b
253 lines
5.5 KiB
VHDL
253 lines
5.5 KiB
VHDL
LIBRARY IEEE;
|
|
USE IEEE.STD_LOGIC_1164.ALL;
|
|
USE IEEE.NUMERIC_STD.ALL;
|
|
|
|
LIBRARY WORK;
|
|
USE WORK.spi_types.all;
|
|
|
|
ENTITY spi_flash_wb IS
|
|
Generic
|
|
(
|
|
FLASH_ADDR_BITS : natural := 24;
|
|
CACHE_ADDR_BITS : natural := 8
|
|
);
|
|
Port
|
|
(
|
|
CLK_I : in STD_LOGIC;
|
|
RST_I : in STD_LOGIC;
|
|
INT_O : out STD_LOGIC;
|
|
CYC_I : in STD_LOGIC;
|
|
STB_I : in STD_LOGIC;
|
|
SEL_I : in unsigned(3 downto 0);
|
|
WE_I : in STD_LOGIC;
|
|
ACK_O : out STD_LOGIC;
|
|
SRDY_O : out STD_LOGIC;
|
|
MRDY_I : in STD_LOGIC;
|
|
ADDR_I : in unsigned(31 downto 0);
|
|
DAT_I : in unsigned(31 downto 0);
|
|
DAT_O : out unsigned(31 downto 0);
|
|
spi_hold : in std_logic;
|
|
spi_ss : out std_logic;
|
|
spi_clk : out std_logic;
|
|
spi_miso : in std_logic;
|
|
spi_mosi : out std_logic
|
|
);
|
|
END spi_flash_wb;
|
|
|
|
ARCHITECTURE rtl OF spi_flash_wb IS
|
|
|
|
type state_t is (reset, idle, spi_cmd, spi_data, cache_fill_start, cache_fill, finish);
|
|
|
|
-- Signals for UART connections
|
|
signal mst_cmd : cmd_t;
|
|
signal mst_cmd_vld : std_logic;
|
|
signal mst_cmd_rdy : std_logic;
|
|
signal mst_shift_en : std_logic;
|
|
signal mst_din_vld : std_logic;
|
|
signal mst_din_rdy : std_logic;
|
|
|
|
signal mst_ctrl : ctrl_t;
|
|
signal mst_status : status_t;
|
|
signal mst_din : unsigned(31 downto 0);
|
|
signal mst_dout : unsigned(31 downto 0);
|
|
signal mst_dout_re : std_logic;
|
|
signal mst_dout_vld : std_logic;
|
|
signal fill_addr : unsigned(CACHE_ADDR_BITS-1 downto 2);
|
|
signal data_ram_addr_rd : unsigned(CACHE_ADDR_BITS-1 downto 2);
|
|
signal word_addr_reg : unsigned(CACHE_ADDR_BITS-1 downto 2);
|
|
|
|
signal tag_we : std_logic;
|
|
signal tag_reg : unsigned(FLASH_ADDR_BITS-1 downto CACHE_ADDR_BITS);
|
|
signal tag_valid : std_logic;
|
|
signal tag_match : std_logic;
|
|
|
|
signal state : state_t;
|
|
signal state_next : state_t;
|
|
|
|
signal SRDY_mem : std_logic;
|
|
signal ACK_mem : std_logic;
|
|
signal DAT_mem : unsigned(31 downto 0);
|
|
signal data_vld : std_logic;
|
|
|
|
begin
|
|
mst_ctrl.clk_div <= to_unsigned(0, 8);
|
|
mst_ctrl.cpol <= '0';
|
|
mst_ctrl.cpha <= '0';
|
|
mst_ctrl.msb_first <= '1';
|
|
mst_dout_re <= mst_dout_vld;
|
|
mst_shift_en <= not spi_hold;
|
|
mst_cmd <= to_cmd(32 + 8 * 2**CACHE_ADDR_BITS, 32);
|
|
mst_din <= X"03" & ADDR_I(FLASH_ADDR_BITS-1 downto CACHE_ADDR_BITS) & (CACHE_ADDR_BITS-1 downto 0 => '0');
|
|
INT_O <= '0';
|
|
|
|
ACK_O <= ACK_mem;
|
|
DAT_O <= DAT_mem;
|
|
SRDY_O <= SRDY_mem;
|
|
|
|
tag_match <= tag_valid when ADDR_I(tag_reg'range) = tag_reg else '0';
|
|
|
|
data_ram_addr_rd <= word_addr_reg when tag_we = '1' else ADDR_I(CACHE_ADDR_BITS-1 downto 2);
|
|
|
|
inst_spi_master : entity work.spi_master
|
|
GENERIC MAP
|
|
(
|
|
WORD_WIDTH => 32,
|
|
CAT_FIFO_DEPTH => 4,
|
|
DATA_FIFO_DEPTH => 4
|
|
)
|
|
PORT MAP
|
|
(
|
|
rst => RST_I,
|
|
clk => CLK_I,
|
|
cmd_vld => mst_cmd_vld,
|
|
cmd_rdy => mst_cmd_rdy,
|
|
cmd => mst_cmd,
|
|
din_vld => mst_din_vld,
|
|
din_rdy => mst_din_rdy,
|
|
din => mst_din,
|
|
dout_re => mst_dout_re,
|
|
dout_vld => mst_dout_vld,
|
|
dout => mst_dout,
|
|
shift_en => mst_shift_en,
|
|
mosi => spi_mosi,
|
|
miso => spi_miso,
|
|
sclk => spi_clk,
|
|
mso => spi_ss,
|
|
ctrl => mst_ctrl,
|
|
status => mst_status
|
|
|
|
);
|
|
|
|
inst_data_ram : entity work.dpram_1w1r2c_ra
|
|
GENERIC MAP
|
|
(
|
|
addr_width => CACHE_ADDR_BITS-2,
|
|
data_width => 32
|
|
)
|
|
PORT MAP
|
|
(
|
|
clk_a => CLK_I,
|
|
clk_b => CLK_I,
|
|
re_b => '1',
|
|
we_a => mst_dout_vld,
|
|
addr_a => fill_addr,
|
|
addr_b => data_ram_addr_rd,
|
|
din_a => mst_dout,
|
|
dout_b => DAT_mem
|
|
);
|
|
|
|
|
|
word_addr_register:
|
|
process(CLK_I)
|
|
begin
|
|
if rising_edge(CLK_I) then
|
|
if (CYC_I and STB_I and SRDY_mem and not WE_I) = '1' then
|
|
word_addr_reg <= ADDR_I(CACHE_ADDR_BITS-1 downto 2);
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
read_cache_ack:
|
|
process(CLK_I)
|
|
begin
|
|
if rising_edge(CLK_I) then
|
|
ACK_mem <= data_vld;
|
|
end if;
|
|
end process;
|
|
|
|
tag_register:
|
|
process(CLK_I)
|
|
begin
|
|
if rising_edge(CLK_I) then
|
|
if RST_I = '1' then
|
|
tag_valid <= '0';
|
|
elsif tag_we = '1' then
|
|
tag_valid <= '1';
|
|
tag_reg <= ADDR_I(tag_reg'range);
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
fill_addr_register:
|
|
process(CLK_I)
|
|
begin
|
|
if rising_edge(CLK_I) then
|
|
if mst_cmd_vld = '1' then
|
|
fill_addr <= (others => '0');
|
|
elsif mst_dout_vld = '1' then
|
|
fill_addr <= fill_addr + 1;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
proc_state_next:
|
|
process(CLK_I)
|
|
begin
|
|
if rising_edge(CLK_I) then
|
|
if RST_I = '1' then
|
|
state <= reset;
|
|
else
|
|
state <= state_next;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
proc_fsm:
|
|
process(state, CYC_I, STB_I, WE_I, tag_match, mst_cmd_rdy, mst_din_rdy, mst_status)
|
|
begin
|
|
state_next <= state;
|
|
SRDY_mem <= '0';
|
|
mst_cmd_vld <= '0';
|
|
mst_din_vld <= '0';
|
|
tag_we <= '0';
|
|
data_vld <= '0';
|
|
|
|
case state is
|
|
|
|
when reset =>
|
|
state_next <= idle;
|
|
|
|
when idle =>
|
|
SRDY_mem <= CYC_I;
|
|
if (CYC_I and STB_I and not WE_I) = '1' then
|
|
if tag_match = '0' then
|
|
state_next <= spi_data;
|
|
else
|
|
data_vld <= '1';
|
|
end if;
|
|
end if;
|
|
|
|
when spi_data =>
|
|
mst_din_vld <= '1';
|
|
if mst_din_rdy = '1' then
|
|
state_next <= spi_cmd;
|
|
end if;
|
|
|
|
when spi_cmd =>
|
|
mst_cmd_vld <= '1';
|
|
if mst_cmd_rdy = '1' then
|
|
state_next <= cache_fill_start;
|
|
end if;
|
|
|
|
when cache_fill_start =>
|
|
if mst_status.xfer_busy = '1' then
|
|
state_next <= cache_fill;
|
|
end if;
|
|
|
|
when cache_fill =>
|
|
if mst_status.xfer_busy = '0' then
|
|
state_next <= finish;
|
|
end if;
|
|
|
|
when finish =>
|
|
tag_we <= '1';
|
|
data_vld <= '1';
|
|
state_next <= idle;
|
|
|
|
when others =>
|
|
state_next <= idle;
|
|
|
|
end case;
|
|
end process;
|
|
|
|
end rtl;
|