[spi_flash_wb.vhd]
- added caching git-svn-id: http://moon:8086/svn/vhdl/trunk@1296 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
+166
-32
@@ -36,6 +36,8 @@ END spi_flash_wb;
|
|||||||
|
|
||||||
ARCHITECTURE rtl OF spi_flash_wb IS
|
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
|
-- Signals for UART connections
|
||||||
signal mst_cmd : cmd_t;
|
signal mst_cmd : cmd_t;
|
||||||
signal mst_cmd_vld : std_logic;
|
signal mst_cmd_vld : std_logic;
|
||||||
@@ -50,22 +52,37 @@ ARCHITECTURE rtl OF spi_flash_wb IS
|
|||||||
signal mst_dout : unsigned(31 downto 0);
|
signal mst_dout : unsigned(31 downto 0);
|
||||||
signal mst_dout_re : std_logic;
|
signal mst_dout_re : std_logic;
|
||||||
signal mst_dout_vld : std_logic;
|
signal mst_dout_vld : std_logic;
|
||||||
signal word_addr : unsigned(CACHE_ADDR_BITS-1 downto 0);
|
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_reg : unsigned(FLASH_ADDR_BITS-1 downto CACHE_ADDR_BITS);
|
||||||
signal tag_valid : std_logic;
|
signal tag_valid : std_logic;
|
||||||
signal tag_match : std_logic;
|
signal tag_match : std_logic;
|
||||||
signal cache_miss : std_logic;
|
|
||||||
signal register_access : std_logic;
|
signal register_access : std_logic;
|
||||||
|
|
||||||
|
signal state : state_t;
|
||||||
|
signal state_next : state_t;
|
||||||
|
|
||||||
|
signal ACK_mem : std_logic;
|
||||||
|
signal ACK_reg : std_logic;
|
||||||
|
signal DAT_mem : unsigned(31 downto 0);
|
||||||
|
signal DAT_reg : unsigned(31 downto 0);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
mst_dout_re <= '1';
|
||||||
mst_shift_en <= not spi_hold;
|
mst_shift_en <= not spi_hold;
|
||||||
|
mst_cmd <= to_cmd(2080, 32);
|
||||||
SRDY_O <= CYC_I;
|
mst_din <= X"03" & ADDR_I(FLASH_ADDR_BITS-1 downto CACHE_ADDR_BITS) & X"00";
|
||||||
INT_O <= '0';
|
INT_O <= '0';
|
||||||
|
|
||||||
tag_match <= '1' when ADDR_I(tag_reg'range) = tag_reg else '0';
|
ACK_O <= ACK_mem or ACK_reg;
|
||||||
cache_miss <= CYC_I and STB_I and not WE_I and not tag_match;
|
DAT_O <= DAT_reg when ACK_reg = '1' else DAT_mem;
|
||||||
register_access <= CYC_I and STB_I and ADDR_I(FLASH_ADDR_BITS);
|
|
||||||
|
tag_match <= tag_valid when ADDR_I(tag_reg'range) = tag_reg else '0';
|
||||||
|
register_access <= ADDR_I(FLASH_ADDR_BITS);
|
||||||
|
|
||||||
data_ram_addr_rd <= word_addr_reg when tag_we = '1' else ADDR_I(CACHE_ADDR_BITS-1 downto 2);
|
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
|
inst_spi_master : entity work.spi_master
|
||||||
@@ -97,33 +114,152 @@ inst_spi_master : entity work.spi_master
|
|||||||
status => mst_status
|
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 not register_access 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 <= (CYC_I and STB_I and not register_access and not WE_I and tag_match) or tag_we;
|
||||||
|
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, register_access)
|
||||||
|
begin
|
||||||
|
state_next <= state;
|
||||||
|
SRDY_O <= CYC_I;
|
||||||
|
mst_cmd_vld <= '0';
|
||||||
|
mst_din_vld <= '0';
|
||||||
|
tag_we <= '0';
|
||||||
|
case state is
|
||||||
|
|
||||||
|
when reset =>
|
||||||
|
state_next <= idle;
|
||||||
|
|
||||||
|
when idle =>
|
||||||
|
if (CYC_I and STB_I and not WE_I and not register_access) = '1' then
|
||||||
|
if tag_match = '0' then
|
||||||
|
state_next <= spi_cmd;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when spi_cmd =>
|
||||||
|
mst_cmd_vld <= '1';
|
||||||
|
if mst_cmd_rdy = '1' then
|
||||||
|
state_next <= spi_data;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when spi_data =>
|
||||||
|
mst_din_vld <= '1';
|
||||||
|
if mst_din_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';
|
||||||
|
state_next <= idle;
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
state_next <= idle;
|
||||||
|
|
||||||
|
end case;
|
||||||
|
end process;
|
||||||
|
|
||||||
------------------------------------------------------------------
|
------------------------------------------------------------------
|
||||||
registers_write:
|
registers_write:
|
||||||
process(CLK_I)
|
process(CLK_I)
|
||||||
begin
|
begin
|
||||||
mst_cmd_vld <= '0';
|
|
||||||
mst_din_vld <= '0';
|
|
||||||
if rising_edge(CLK_I) then
|
if rising_edge(CLK_I) then
|
||||||
mst_ctrl.clk_div <= to_unsigned(100, 8);
|
if RST_I = '1' then
|
||||||
mst_ctrl.clk_div <= to_unsigned(0, 8);
|
mst_ctrl.clk_div <= to_unsigned(0, 8);
|
||||||
mst_ctrl.cpol <= '0';
|
mst_ctrl.cpol <= '0';
|
||||||
mst_ctrl.cpha <= '0';
|
mst_ctrl.cpha <= '0';
|
||||||
elsif (register_access and WE_I) = '1' then
|
mst_ctrl.msb_first <= '1';
|
||||||
elsif (CYC_I and STB_I and register_access and WE_I) = '1' then
|
elsif (CYC_I and STB_I and register_access and WE_I) = '1' then
|
||||||
case ADDR_I(5 downto 2) is
|
case ADDR_I(5 downto 2) is
|
||||||
|
|
||||||
mst_cmd_vld <= DAT_I(0);
|
|
||||||
when "0000" =>
|
when "0000" =>
|
||||||
|
|
||||||
mst_cmd.xfer_size <= DAT_I;
|
|
||||||
when "0001" =>
|
when "0001" =>
|
||||||
|
|
||||||
mst_cmd.data_size <= DAT_I;
|
|
||||||
when "0010" =>
|
when "0010" =>
|
||||||
|
|
||||||
mst_din <= DAT_I;
|
|
||||||
mst_din_vld <= '1';
|
|
||||||
when "0011" =>
|
when "0011" =>
|
||||||
|
|
||||||
when "0100" =>
|
when "0100" =>
|
||||||
@@ -141,32 +277,30 @@ registers_read:
|
|||||||
registers_read:
|
registers_read:
|
||||||
process(CLK_I)
|
process(CLK_I)
|
||||||
begin
|
begin
|
||||||
mst_dout_re <= '0';
|
if rising_edge(CLK_I) then
|
||||||
ACK_O <= '0';
|
ACK_reg <= '0';
|
||||||
if (register_access) = '1' then
|
if (CYC_I and STB_I and register_access) = '1' then
|
||||||
ACK_O <= not WE_I;
|
ACK_reg <= not WE_I;
|
||||||
DAT_O <= (others => '0');
|
|
||||||
DAT_reg <= (others => '0');
|
DAT_reg <= (others => '0');
|
||||||
case ADDR_I(5 downto 2) is
|
case ADDR_I(5 downto 2) is
|
||||||
|
|
||||||
DAT_O(2 downto 0) <= mst_dout_vld & mst_din_rdy & mst_cmd_rdy;
|
when "0000" =>
|
||||||
DAT_O(15 downto 8) <= spi_hold & mst_status.rx_valid & mst_status.read_fifo_empty & mst_status.read_fifo_full & mst_status.write_fifo_empty & mst_status.write_fifo_full & mst_status.cmd_fifo_empty & mst_status.cmd_fifo_full;
|
DAT_reg(2 downto 0) <= mst_dout_vld & mst_din_rdy & mst_cmd_rdy;
|
||||||
DAT_reg(15 downto 8) <= spi_hold & mst_status.xfer_busy & mst_status.read_fifo_empty & mst_status.read_fifo_full & mst_status.write_fifo_empty & mst_status.write_fifo_full & mst_status.cmd_fifo_empty & mst_status.cmd_fifo_full;
|
DAT_reg(15 downto 8) <= spi_hold & mst_status.xfer_busy & mst_status.read_fifo_empty & mst_status.read_fifo_full & mst_status.write_fifo_empty & mst_status.write_fifo_full & mst_status.cmd_fifo_empty & mst_status.cmd_fifo_full;
|
||||||
|
|
||||||
DAT_O <= mst_cmd.xfer_size;
|
when "0001" =>
|
||||||
DAT_reg <= mst_cmd.xfer_size;
|
DAT_reg <= mst_cmd.xfer_size;
|
||||||
|
|
||||||
DAT_O <= mst_cmd.data_size;
|
when "0010" =>
|
||||||
DAT_reg <= mst_cmd.data_size;
|
DAT_reg <= mst_cmd.data_size;
|
||||||
|
|
||||||
DAT_O <= mst_dout;
|
when "0011" =>
|
||||||
mst_dout_re <= not WE_I;
|
|
||||||
DAT_reg <= mst_dout;
|
DAT_reg <= mst_dout;
|
||||||
|
|
||||||
DAT_O(7 downto 0) <= mst_ctrl.clk_div;
|
when "0100" =>
|
||||||
DAT_O(8) <= mst_ctrl.cpol;
|
DAT_reg(7 downto 0) <= mst_ctrl.clk_div;
|
||||||
DAT_O(9) <= mst_ctrl.cpha;
|
DAT_reg(8) <= mst_ctrl.cpol;
|
||||||
DAT_O(10) <= mst_ctrl.msb_first;
|
DAT_reg(9) <= mst_ctrl.cpha;
|
||||||
DAT_reg(10) <= mst_ctrl.msb_first;
|
DAT_reg(10) <= mst_ctrl.msb_first;
|
||||||
|
|
||||||
when others => null;
|
when others => null;
|
||||||
|
|||||||
@@ -88,6 +88,13 @@ uut : entity work.spi_flash_wb
|
|||||||
);
|
);
|
||||||
|
|
||||||
inst_spi_slave: entity work.S25fl064k
|
inst_spi_slave: entity work.S25fl064k
|
||||||
|
GENERIC MAP
|
||||||
|
(
|
||||||
|
UserPreload => TRUE,
|
||||||
|
mem_file_name => "tb_spi_flash_wb.mem",
|
||||||
|
screg_file_name => "none"
|
||||||
|
|
||||||
|
)
|
||||||
PORT MAP (
|
PORT MAP (
|
||||||
SCK => mst_clk, -- serial clock input
|
SCK => mst_clk, -- serial clock input
|
||||||
SI => mosi, -- serial data input
|
SI => mosi, -- serial data input
|
||||||
@@ -122,6 +129,50 @@ STIMULUS: process
|
|||||||
wait until rising_edge(CLK) and ACK_O = '1';
|
wait until rising_edge(CLK) and ACK_O = '1';
|
||||||
CYC_I <= '0';
|
CYC_I <= '0';
|
||||||
|
|
||||||
|
wait for 10*CLK_PERIOD;
|
||||||
|
wait until rising_edge(CLK);
|
||||||
|
ADDR_I <= X"0000_0000";
|
||||||
|
STB_I <= '1';
|
||||||
|
CYC_I <= '1';
|
||||||
|
wait until rising_edge(CLK) and SRDY_O = '1';
|
||||||
|
STB_I <= '0';
|
||||||
|
wait until rising_edge(CLK) and ACK_O = '1';
|
||||||
|
CYC_I <= '0';
|
||||||
|
|
||||||
|
wait for 10*CLK_PERIOD;
|
||||||
|
wait until rising_edge(CLK);
|
||||||
|
ADDR_I <= X"0000_0004";
|
||||||
|
STB_I <= '1';
|
||||||
|
CYC_I <= '1';
|
||||||
|
wait until rising_edge(CLK) and SRDY_O = '1';
|
||||||
|
STB_I <= '0';
|
||||||
|
wait until rising_edge(CLK) and ACK_O = '1';
|
||||||
|
CYC_I <= '0';
|
||||||
|
|
||||||
|
wait for 10*CLK_PERIOD;
|
||||||
|
wait until rising_edge(CLK);
|
||||||
|
ADDR_I <= X"0000_0100";
|
||||||
|
STB_I <= '1';
|
||||||
|
CYC_I <= '1';
|
||||||
|
wait until rising_edge(CLK) and SRDY_O = '1';
|
||||||
|
STB_I <= '0';
|
||||||
|
wait until rising_edge(CLK) and ACK_O = '1';
|
||||||
|
CYC_I <= '0';
|
||||||
|
|
||||||
|
wait for 10*CLK_PERIOD;
|
||||||
|
CYC_I <= '1';
|
||||||
|
|
||||||
|
for i in 0 to 63 loop
|
||||||
|
ADDR_I <= to_unsigned(4*i, 32);
|
||||||
|
STB_I <= '1';
|
||||||
|
wait until rising_edge(CLK) and SRDY_O = '1';
|
||||||
|
STB_I <= '0';
|
||||||
|
wait until rising_edge(CLK) and ACK_O = '1';
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
wait for 10*CLK_PERIOD;
|
||||||
|
CYC_I <= '1';
|
||||||
|
|
||||||
wait;
|
wait;
|
||||||
|
|
||||||
end process;
|
end process;
|
||||||
|
|||||||
Reference in New Issue
Block a user