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;