diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_biu.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_biu.vhd
new file mode 100644
index 0000000..e54e35d
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_biu.vhd
@@ -0,0 +1,434 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.numeric_std.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+use work.busmaster_types.all;
+
+entity biu is
+ Generic
+ (
+ ICACHE_SIZE : natural := 2048; -- words
+ ICACHE_LINE : natural := 8; -- words
+ DCACHE_SIZE : natural := 2048; -- words
+ DCACHE_LINE : natural := 8; -- words
+ WRITE_FIFO_SIZE : natural := 4; -- words
+ WITH_TLB : boolean
+ );
+ Port
+ (
+ clk : in STD_LOGIC;
+ busy : out STD_LOGIC;
+
+ imem_err : out STD_LOGIC;
+ imem_rdy : out STD_LOGIC;
+ imem_en : in STD_LOGIC;
+ imem_addr : in word_t;
+ imem_dout : out word_t;
+ dmem_err : out STD_LOGIC;
+ dmem_rdy : out STD_LOGIC;
+ dmem_en : in STD_LOGIC;
+ dmem_we : in STD_LOGIC;
+ dmem_be : in unsigned(3 downto 0);
+ dmem_din : in word_t;
+ dmem_dout : out word_t;
+ dmem_addr : in word_t;
+
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ ADDR_O : out unsigned(31 downto 0);
+ MDAT_I : in unsigned(31 downto 0);
+ MDAT_O : out unsigned(31 downto 0);
+ WE_O : out STD_LOGIC;
+ SEL_O : out unsigned(3 downto 0);
+ CYC_O : out STD_LOGIC;
+ STB_O : out STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+
+ ctrl_in : in biu_ctrl_in_t;
+ ctrl_out : out biu_ctrl_out_t
+
+ );
+end biu;
+
+architecture behavior of biu is
+
+ type bus_state_t is (init, ready, icache_bus_access, dcache_bus_access, write_bus, read_bus, read_finish);
+
+ signal s, sn : bus_state_t;
+ signal bus_idle : std_logic;
+
+ type timeout_cnt_t is range 0 to 1E5-1;
+ signal bus_timeout_cnt : timeout_cnt_t;
+ signal bus_timeout : std_logic;
+
+ -------------------------------------------------
+ signal RST : std_logic;
+ signal CPU_CLK : std_logic;
+
+ -- busmaster signals
+ signal bus_din : word_t;
+ signal bus_din_rdy : std_logic;
+ signal bus_din_we : std_logic;
+
+ signal bus_dout : word_t;
+ signal bus_dout_vld : std_logic;
+ signal bus_dout_re : std_logic;
+
+ signal bus_cmd_rdy : std_logic;
+ signal bus_cmd_we : std_logic;
+ signal bus_cmd_cycle_en : std_logic;
+ signal bus_cmd : bm_cmd_t;
+ signal bus_cyc_complete : std_logic;
+
+ signal i_bus_din_rdy : std_logic;
+ signal i_bus_cmd_rdy : std_logic;
+ signal i_bus_cmd_we : std_logic;
+ signal i_bus_cmd_cycle_en : std_logic;
+ signal i_bus_cmd : bm_cmd_t;
+
+ signal i_tlb_ctrl_in : tlb_ctrl_in_t;
+ signal i_tlb_ctrl_out : tlb_ctrl_out_t;
+ signal i_tlb_qry_in : tlb_query_in_t;
+ signal i_tlb_qry_out : tlb_query_out_t;
+ signal i_tlb_rdy : std_logic;
+ signal i_cache_rdy : std_logic;
+
+ signal d_bus_din_rdy : std_logic;
+ signal d_bus_cmd_rdy : std_logic;
+ signal d_bus_cmd_we : std_logic;
+ signal d_bus_cmd_cycle_en : std_logic;
+ signal d_bus_cmd : bm_cmd_t;
+
+ signal d_tlb_ctrl_in : tlb_ctrl_in_t;
+ signal d_tlb_ctrl_out : tlb_ctrl_out_t;
+ signal d_tlb_qry_in : tlb_query_in_t;
+ signal d_tlb_qry_out : tlb_query_out_t;
+ signal d_tlb_rdy : std_logic;
+ signal d_cache_rdy : std_logic;
+
+ signal icache_bus_gnt : std_logic;
+ signal dcache_bus_gnt : std_logic;
+
+
+begin
+
+ CPU_CLK <= clk;
+ RST <= RST_I;
+ imem_rdy <= i_cache_rdy;
+ dmem_rdy <= d_cache_rdy;
+
+ ctrl_out.itlb <= i_tlb_ctrl_out;
+ ctrl_out.dtlb <= d_tlb_ctrl_out;
+
+
+biu_busy_state:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if RST_I = '1' then
+ busy <= '1';
+ elsif (i_tlb_rdy and i_cache_rdy and d_cache_rdy and d_tlb_rdy) = '1' then
+ busy <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_busmaster : entity work.busmaster_async
+ GENERIC MAP
+ (
+ DATA_WIDTH => 32,
+ FIFO_DEPTH => 16
+ )
+ PORT MAP
+ (
+ -- System signals
+ rst => RST,
+ clk => CPU_CLK,
+
+ cmd_cycle_finished => bus_cyc_complete,
+ cmd_cycle_en => bus_cmd_cycle_en,
+
+ cmd_rdy => bus_cmd_rdy,
+ cmd_we => bus_cmd_we,
+ cmd_in => bus_cmd,
+
+ din_rdy => bus_din_rdy,
+ din_we => bus_din_we,
+ din => bus_din,
+
+ dout => bus_dout,
+ dout_vld => bus_dout_vld,
+ dout_re => bus_dout_re,
+
+ -- JBUS Master signals
+ RST_I => RST_I,
+ CLK_I => CLK_I,
+ CYC_O => CYC_O,
+ STB_O => STB_O,
+ WE_O => WE_O,
+ SEL_O => SEL_O,
+ ACK_I => ACK_I,
+ SRDY_I => SRDY_I,
+ MRDY_O => MRDY_O,
+ ADDR_O => ADDR_O,
+ MDAT_I => MDAT_I,
+ MDAT_O => MDAT_O
+ );
+
+inst_i_tlb : entity work.tlb
+ GENERIC MAP
+ (
+ NUM_ENTRIES => TLB_NUM_ENTRIES,
+ CACHE_KSEG1 => false,
+ USE_TLB => WITH_TLB
+ )
+ PORT MAP
+ (
+ -- System signals
+ rst => RST,
+ clk => CPU_CLK,
+ ce => '1',
+
+ rdy => i_tlb_rdy,
+
+ ctrl_in => i_tlb_ctrl_in,
+ ctrl_out => i_tlb_ctrl_out,
+
+ query_in => i_tlb_qry_in,
+ query_out => i_tlb_qry_out
+
+ );
+
+ i_tlb_ctrl_in <= ctrl_in.itlb;
+
+inst_icache: entity work.icache
+ GENERIC MAP
+ (
+ CACHE_SIZE => ICACHE_SIZE,
+ LINE_SIZE => ICACHE_LINE
+ )
+ PORT MAP
+ (
+ rst => RST,
+ clk => CPU_CLK,
+
+ -- CPU control/data
+ en => imem_en,
+ addr => imem_addr,
+ dout => imem_dout,
+ rdy => i_cache_rdy,
+
+ -- Cache control
+ ctrl_in => ctrl_in.icache,
+ tlb_query_in => i_tlb_qry_out,
+ tlb_query_out => i_tlb_qry_in,
+
+ -- busmaster data
+ bus_din => bus_dout,
+ bus_din_rdy => i_bus_din_rdy,
+ bus_din_vld => bus_dout_vld,
+
+ -- busmaster command
+ bus_cmd_rdy => i_bus_cmd_rdy,
+ bus_cmd_we => i_bus_cmd_we,
+ bus_cmd_cycle_en => i_bus_cmd_cycle_en,
+ bus_cmd_out => i_bus_cmd,
+ bus_cyc_complete => bus_cyc_complete
+ );
+
+
+inst_d_tlb : entity work.tlb
+ GENERIC MAP
+ (
+ NUM_ENTRIES => TLB_NUM_ENTRIES,
+ CACHE_KSEG1 => false,
+ USE_TLB => WITH_TLB
+ )
+ PORT MAP
+ (
+ -- System signals
+ rst => RST,
+ clk => CPU_CLK,
+ ce => '1',
+
+ rdy => d_tlb_rdy,
+
+ ctrl_in => d_tlb_ctrl_in,
+ ctrl_out => d_tlb_ctrl_out,
+
+ query_in => d_tlb_qry_in,
+ query_out => d_tlb_qry_out
+
+ );
+
+ d_tlb_ctrl_in <= ctrl_in.dtlb;
+
+inst_dcache: entity work.dcache
+ GENERIC MAP
+ (
+ CACHE_SIZE => DCACHE_SIZE,
+ LINE_SIZE => DCACHE_LINE,
+ WRITE_FIFO_SIZE => WRITE_FIFO_SIZE
+ )
+ PORT MAP
+ (
+ rst => RST,
+ clk => CPU_CLK,
+
+ -- CPU control/data
+ en => dmem_en,
+ we => dmem_we,
+ addr => dmem_addr,
+ be => dmem_be,
+ din => dmem_din,
+ dout => dmem_dout,
+ rdy => d_cache_rdy,
+
+ -- Cache control
+ ctrl_in => ctrl_in.dcache,
+ tlb_query_in => d_tlb_qry_out,
+ tlb_query_out => d_tlb_qry_in,
+
+ -- busmaster data
+ bus_din => bus_dout,
+ bus_din_rdy => d_bus_din_rdy,
+ bus_din_vld => bus_dout_vld,
+
+ bus_dout => bus_din,
+ bus_dout_vld => bus_din_we,
+ bus_dout_rdy => bus_din_rdy,
+
+ -- busmaster command
+ bus_cmd_rdy => d_bus_cmd_rdy,
+ bus_cmd_we => d_bus_cmd_we,
+ bus_cmd_cycle_en => d_bus_cmd_cycle_en,
+ bus_cmd_out => d_bus_cmd,
+ bus_cyc_complete => bus_cyc_complete
+ );
+
+bus_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if RST_I = '1' then
+ s <= init;
+ else
+ s <= sn;
+ end if;
+ end if;
+ end process;
+
+bus_state:
+ process(s, i_bus_cmd_cycle_en, d_bus_cmd_cycle_en, i_bus_cmd_we, i_bus_cmd, d_bus_cmd_we, d_bus_cmd, bus_cyc_complete, i_bus_din_rdy, d_bus_din_rdy, bus_cmd_rdy)
+ begin
+
+ icache_bus_gnt <= '0';
+ dcache_bus_gnt <= '0';
+
+ i_bus_cmd_rdy <= '0';
+ d_bus_cmd_rdy <= '0';
+
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ bus_cmd <= i_bus_cmd;
+ bus_dout_re <= '0';
+ bus_idle <= '0';
+
+ sn <= s;
+ case s is
+ when init =>
+ sn <= ready;
+ when ready =>
+ bus_idle <= '1';
+ if i_bus_cmd_cycle_en = '1' then
+ sn <= icache_bus_access;
+ elsif d_bus_cmd_cycle_en = '1' then
+ sn <= dcache_bus_access;
+ end if;
+ when icache_bus_access =>
+ icache_bus_gnt <= '1';
+ i_bus_cmd_rdy <= bus_cmd_rdy;
+ bus_cmd_cycle_en <= i_bus_cmd_cycle_en;
+ bus_cmd_we <= i_bus_cmd_we;
+ bus_dout_re <= i_bus_din_rdy;
+ if i_bus_cmd_cycle_en = '0' then
+ sn <= ready;
+ end if;
+ when dcache_bus_access =>
+ dcache_bus_gnt <= '1';
+ d_bus_cmd_rdy <= bus_cmd_rdy;
+ bus_cmd_cycle_en <= d_bus_cmd_cycle_en;
+ bus_cmd <= d_bus_cmd;
+ bus_cmd_we <= d_bus_cmd_we;
+ bus_dout_re <= d_bus_din_rdy;
+ if d_bus_cmd_cycle_en = '0' then
+ sn <= ready;
+ end if;
+ when others =>
+ sn <= ready;
+ end case;
+
+ end process;
+
+bus_timeout_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if bus_idle = '0' then
+ if bus_timeout_cnt /= 0 then
+ bus_timeout_cnt <= bus_timeout_cnt - 1;
+ else
+ bus_timeout <= '1';
+ end if;
+ else
+ bus_timeout_cnt <= timeout_cnt_t'high;
+ bus_timeout <= '0';
+ end if;
+ end if;
+ end process;
+
+bus_err:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if RST_I = '1' then
+ imem_err <= '0';
+ dmem_err <= '0';
+ elsif bus_timeout = '1' then
+ imem_err <= icache_bus_gnt;
+ dmem_err <= dcache_bus_gnt;
+ end if;
+ end if;
+ end process;
+
+-------------------------------------------------------------------
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cam.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cam.vhd
new file mode 100644
index 0000000..0ae8736
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cam.vhd
@@ -0,0 +1,319 @@
+LIBRARY IEEE;
+USE IEEE.MATH_REAL.ALL;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+ENTITY cam IS
+ Generic
+ (
+ NUM_ENTRIES : natural := 32;
+ DATA_WIDTH : natural := 20;
+ CAM_RAM_MAX_WIDTH : natural := 15
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ clk_rd : in STD_LOGIC;
+
+ rdy : out STD_LOGIC;
+
+ re : in STD_LOGIC;
+ we : in STD_LOGIC;
+ vld : in STD_LOGIC;
+ addr : in unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ tag_wr : in unsigned (DATA_WIDTH-1 downto 0);
+
+ tag_rd : in unsigned (DATA_WIDTH-1 downto 0);
+ hit : out unsigned (NUM_ENTRIES-1 downto 0);
+ hit_vld : out STD_LOGIC
+
+ );
+END cam;
+
+ARCHITECTURE behavior OF cam IS
+
+ type debug_t is record
+ num_cam_rams : integer;
+ cam_ram_data_width : integer;
+ cam_ram_addr_width : integer;
+ end record;
+
+ signal debug : debug_t;
+
+ constant NUM_BLOCKS : integer := integer(real(DATA_WIDTH)/real(CAM_RAM_MAX_WIDTH-lg2(NUM_ENTRIES)));
+ constant BLOCK_ADDR_WIDTH : integer := CAM_RAM_MAX_WIDTH - lg2(NUM_ENTRIES);
+
+ type state_t is (init, ready, clear);
+ signal state : state_t;
+ signal state_next : state_t;
+
+ type pipe_stage_t is record
+ re : std_logic;
+ we : std_logic;
+ vld : std_logic;
+ addr : unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ data : unsigned (DATA_WIDTH-1 downto 0);
+ vld_cam : unsigned (NUM_ENTRIES-1 downto 0);
+ end record;
+
+ signal pipe0 : pipe_stage_t;
+ signal pipe1 : pipe_stage_t;
+ signal pipe2 : pipe_stage_t;
+ signal pipe3 : pipe_stage_t;
+ signal pipe0_rd : pipe_stage_t;
+ signal pipe1_rd : pipe_stage_t;
+ signal pipe2_rd : pipe_stage_t;
+ signal pipe3_rd : pipe_stage_t;
+ signal busy : std_logic;
+ signal vld_cam : unsigned (NUM_ENTRIES-1 downto 0);
+
+ signal cam_ram_re : std_logic;
+ signal cam_ram_we : std_logic;
+
+ type cam_ram_array_t is array (0 to NUM_BLOCKS-1) of unsigned (NUM_ENTRIES-1 downto 0);
+ signal cam_ram_din : cam_ram_array_t;
+ signal cam_ram_dout : cam_ram_array_t;
+ signal cam_ram_result : unsigned (NUM_ENTRIES-1 downto 0);
+
+ signal cam_ram_addr_wr : unsigned (DATA_WIDTH-1 downto 0);
+ signal cam_ram_addr_rd : unsigned (DATA_WIDTH-1 downto 0);
+
+ signal track_ram_re : std_logic;
+ signal track_ram_we : std_logic;
+ signal track_ram_addr_wr : unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ signal track_ram_addr_rd : unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ signal track_ram_din : unsigned (DATA_WIDTH downto 0);
+ signal track_ram_dout : unsigned (DATA_WIDTH downto 0);
+
+ signal clear_data : unsigned (DATA_WIDTH-1 downto 0);
+ signal clear_addr : unsigned (BLOCK_ADDR_WIDTH-1 downto 0);
+ signal clear_count_en : std_logic;
+ signal clear_count_rdy : std_logic;
+ signal over_write : std_logic;
+
+
+begin
+
+ over_write <= track_ram_dout(DATA_WIDTH) and pipe1.we;
+ rdy <= not busy;
+ hit_vld <= pipe1.re;
+
+ debug.num_cam_rams <= NUM_BLOCKS;
+ debug.cam_ram_addr_width <= BLOCK_ADDR_WIDTH;
+ debug.cam_ram_data_width <= NUM_ENTRIES;
+
+ track_ram_re <= '1';
+ track_ram_we <= clear_count_en or pipe1.we;
+ track_ram_addr_rd <= pipe0.addr;
+ track_ram_addr_wr <= clear_data(lg2(NUM_ENTRIES)-1 downto 0) when clear_count_en = '1' else pipe1.addr;
+ track_ram_din <= (others => '0') when clear_count_en = '1' else (pipe1.vld & pipe1.data);
+
+ cam_ram_re <= re when pipe1_rd.we = '0' else not busy;
+ cam_ram_we <= clear_count_en or (pipe2.we and pipe2.vld) or over_write;
+ cam_ram_addr_rd <= tag_rd when pipe1_rd.we = '0' else pipe1_rd.data; -- clk_rd same edge of clk
+-- cam_ram_addr_rd <= tag_rd when pipe2_rd.we = '0' else pipe2_rd.data; -- clk_rd opposite edge of clk
+ cam_ram_addr_wr <= clear_data when clear_count_en = '1' else track_ram_dout(DATA_WIDTH-1 downto 0) when over_write = '1' else pipe2.data;
+
+combine_cam_ram_din:
+ process(clear_count_en, over_write, pipe2, cam_ram_dout)
+ begin
+ for i in 0 to NUM_BLOCKS-1 loop
+ if clear_count_en = '1' or over_write = '1' then
+ cam_ram_din(i) <= (others => '0');
+ else
+ cam_ram_din(i) <= (((NUM_ENTRIES-1 downto 0 => pipe2.vld) and pipe2.vld_cam) xor cam_ram_dout(i));
+ end if;
+ end loop;
+ end process;
+
+combine_clear_addr:
+ process(clear_addr)
+ begin
+ for i in 0 to NUM_BLOCKS-1 loop
+ clear_data((i+1)*BLOCK_ADDR_WIDTH-1 downto i*BLOCK_ADDR_WIDTH) <= clear_addr;
+ end loop;
+ end process;
+
+combine_cam_ram_result:
+ process(cam_ram_dout)
+ variable result : unsigned (NUM_ENTRIES-1 downto 0);
+ begin
+ result := (others => '0');
+
+ for i in 0 to NUM_BLOCKS-1 loop
+ result := result or cam_ram_dout(i);
+ end loop;
+
+ cam_ram_result <= result;
+ end process;
+
+ pipe0.re <= re and not busy;
+ pipe0.vld <= vld;
+ pipe0.we <= we and not busy;
+ pipe0.addr <= addr;
+ pipe0.data <= tag_wr;
+ pipe0.vld_cam <= vld_cam;
+
+pipe_line_wr:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ pipe3.we <= '0';
+ pipe2.we <= '0';
+ pipe1.we <= '0';
+ else
+ pipe3 <= pipe2;
+ pipe2 <= pipe1;
+ pipe1 <= pipe0;
+ end if;
+ end if;
+ end process;
+
+ pipe0_rd <= pipe0;
+pipe_line_rd:
+ process(clk_rd)
+ begin
+ if rising_edge(clk_rd) then
+ if rst = '1' then
+ pipe3_rd.we <= '0';
+ pipe2_rd.we <= '0';
+ pipe1_rd.we <= '0';
+ else
+ pipe3_rd <= pipe2_rd;
+ pipe2_rd <= pipe1_rd;
+ pipe1_rd <= pipe0_rd;
+ end if;
+ end if;
+ end process;
+
+combine_cam_hit:
+ process(cam_ram_dout, clear_count_en)
+ variable result : unsigned (NUM_ENTRIES-1 downto 0);
+ begin
+ result := (others => not clear_count_en);
+
+ for i in 0 to NUM_BLOCKS-1 loop
+ result := result and cam_ram_dout(i);
+ end loop;
+
+ hit <= result;
+ end process;
+
+vld_decode:
+process(vld, addr)
+ begin
+ vld_cam <= (others => '0');
+ vld_cam(to_integer(addr)) <= vld;
+ end process;
+
+
+inst_track_ram: entity work.dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => DATA_WIDTH+1
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => track_ram_we,
+ addr_a => track_ram_addr_wr,
+ addr_b => track_ram_addr_rd,
+ din_a => track_ram_din,
+ dout_b => track_ram_dout
+ );
+
+gen_cam_ram:
+for i in 0 to NUM_BLOCKS-1 generate
+
+ inst_cam_ram: entity work.dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => BLOCK_ADDR_WIDTH,
+ data_width => NUM_ENTRIES
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk_rd,
+ en_a => '1',
+ en_b => cam_ram_re,
+ we_a => cam_ram_we,
+ addr_a => cam_ram_addr_wr((i+1)*BLOCK_ADDR_WIDTH-1 downto i*BLOCK_ADDR_WIDTH),
+ addr_b => cam_ram_addr_rd((i+1)*BLOCK_ADDR_WIDTH-1 downto i*BLOCK_ADDR_WIDTH),
+ din_a => cam_ram_din(i),
+ dout_b => cam_ram_dout(i)
+ );
+
+end generate;
+
+cam_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ state <= init;
+ else
+ state <= state_next;
+ end if;
+ end if;
+ end process;
+
+cam_state:
+ process(state, clear_count_rdy, over_write)
+ begin
+ busy <= over_write;
+ clear_count_en <= '0';
+
+ state_next <= state;
+
+ case state is
+
+ when init =>
+ busy <= '1';
+ state_next <= clear;
+
+ when clear =>
+ busy <= '1';
+ clear_count_en <= '1';
+ if clear_count_rdy = '1' then
+ state_next <= ready;
+ end if;
+
+ when ready =>
+
+ when others =>
+ state_next <= ready;
+
+ end case;
+
+ end process;
+
+clear_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if clear_count_en = '0' then
+ clear_count_rdy <= '0';
+ clear_addr <= (BLOCK_ADDR_WIDTH-1 downto 0 => '1');
+ else
+ if clear_addr /= (BLOCK_ADDR_WIDTH-1 downto 0 => '0') then
+ clear_addr <= clear_addr - 1;
+ else
+ clear_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+------------------------------------------------------------------
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cam2.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cam2.vhd
new file mode 100644
index 0000000..9173513
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cam2.vhd
@@ -0,0 +1,329 @@
+LIBRARY IEEE;
+USE IEEE.MATH_REAL.ALL;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+ENTITY cam2 IS
+ Generic
+ (
+ NUM_ENTRIES : natural := 32;
+ ENTRY_WIDTH : natural := 32;
+ DATA_WIDTH : natural := 20;
+ REGISTERED_RTAG : boolean := true;
+ REGISTERED_RESULT : boolean := false;
+ CAM_RAM_MAX_WIDTH : natural := 8
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ rdy : out STD_LOGIC;
+
+ re : in STD_LOGIC;
+ we : in STD_LOGIC;
+ vld : in STD_LOGIC;
+ addr : in unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ entry_din : in unsigned (ENTRY_WIDTH-1 downto 0);
+ entry_dout : out unsigned (ENTRY_WIDTH-1 downto 0);
+
+ tag_wr : in unsigned (DATA_WIDTH-1 downto 0);
+ tag_rd : in unsigned (DATA_WIDTH-1 downto 0);
+
+ hit_vld : out STD_LOGIC
+
+ );
+END cam2;
+
+ARCHITECTURE behavior OF cam2 IS
+
+ type debug_t is record
+ num_cam_rams : integer;
+ cam_ram_data_width : integer;
+ cam_ram_addr_width : integer;
+ end record;
+
+ signal debug : debug_t;
+
+ constant NUM_BLOCKS : integer := integer(real(2*DATA_WIDTH)/real(CAM_RAM_MAX_WIDTH))-1;
+ constant BLOCK_ADDR_WIDTH : integer := CAM_RAM_MAX_WIDTH;
+
+ type state_t is (init, ready, clear);
+ signal state : state_t;
+ signal state_next : state_t;
+
+ type pipe_stage_t is record
+ re : std_logic;
+ we : std_logic;
+ vld : std_logic;
+ addr : unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ data : unsigned (DATA_WIDTH-1 downto 0);
+ entry_data : unsigned (ENTRY_WIDTH downto 0);
+ end record;
+
+ signal read_tag : unsigned (DATA_WIDTH-1 downto 0);
+ signal read_en : std_logic;
+
+ signal pipe0 : pipe_stage_t;
+ signal pipe1 : pipe_stage_t;
+ signal pipe2 : pipe_stage_t;
+ signal pipe3 : pipe_stage_t;
+ signal pipe0_rd : pipe_stage_t;
+ signal pipe1_rd : pipe_stage_t;
+ signal pipe2_rd : pipe_stage_t;
+ signal pipe3_rd : pipe_stage_t;
+ signal busy : std_logic;
+
+ signal cam_ram_re : std_logic;
+ signal cam_ram_we : std_logic;
+ signal cam_ram_addr_wr : unsigned (DATA_WIDTH-1 downto 0);
+ signal cam_ram_addr_rd : unsigned (DATA_WIDTH-1 downto 0);
+
+ signal track_ram_re : std_logic;
+ signal track_ram_we : std_logic;
+ signal track_ram_addr_wr : unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ signal track_ram_addr_rd : unsigned (lg2(NUM_ENTRIES)-1 downto 0);
+ signal track_ram_din : unsigned (DATA_WIDTH downto 0);
+ signal track_ram_dout : unsigned (DATA_WIDTH downto 0);
+
+ signal clear_addr : unsigned (BLOCK_ADDR_WIDTH-1 downto 0);
+ signal clear_count_en : std_logic;
+ signal clear_count_rdy : std_logic;
+ signal over_write : std_logic;
+
+ type cam_stage_addr_t is array(0 to NUM_BLOCKS-1) of unsigned (CAM_RAM_MAX_WIDTH-1 downto 0);
+ signal cam_stage_raddr : cam_stage_addr_t;
+ signal cam_stage_waddr : cam_stage_addr_t;
+
+ type cam_stage_data_t is array(0 to NUM_BLOCKS-1) of unsigned (CAM_RAM_MAX_WIDTH/2-1 downto 0);
+ signal cam_stage_din : cam_stage_data_t;
+ signal cam_stage_dout : cam_stage_data_t;
+
+ signal final_stage_we : std_logic;
+ signal final_stage_din : unsigned (ENTRY_WIDTH downto 0);
+ signal final_stage_dout : unsigned (ENTRY_WIDTH downto 0);
+ signal final_stage_wptr : unsigned (CAM_RAM_MAX_WIDTH-1 downto 0);
+ signal final_stage_rptr : unsigned (CAM_RAM_MAX_WIDTH-1 downto 0);
+
+begin
+
+
+
+ rdy <= not busy;
+ over_write <= track_ram_dout(DATA_WIDTH) and pipe1.we;
+
+ --------------------------------------------------------
+ final_stage_we <= clear_count_en or (pipe2.we and pipe2.vld) or over_write;
+ final_stage_wptr <= clear_addr when clear_count_en = '1' else cam_stage_waddr(NUM_BLOCKS-1);
+ final_stage_rptr <= cam_stage_raddr(NUM_BLOCKS-1);
+ final_stage_din <= (others => '0') when (clear_count_en or over_write) = '1' else pipe2.entry_data;
+
+ cam_ram_we <= clear_count_en or (pipe2.we and pipe2.vld) or over_write;
+ cam_ram_re <= not busy;
+ cam_ram_addr_rd <= read_tag when pipe1_rd.we = '0' else pipe1_rd.data; -- clk_rd same edge of clk
+ cam_ram_addr_wr <= track_ram_dout(DATA_WIDTH-1 downto 0) when over_write = '1' else pipe2.data;
+
+ track_ram_re <= '1';
+ track_ram_we <= clear_count_en or pipe1.we;
+ track_ram_addr_rd <= pipe0.addr;
+ track_ram_addr_wr <= clear_addr(lg2(NUM_ENTRIES)-1 downto 0) when clear_count_en = '1' else pipe1.addr;
+ track_ram_din <= (others => '0') when clear_count_en = '1' else (pipe1.vld & pipe1.data);
+
+ pipe0.re <= read_en and not busy;
+ pipe0.vld <= vld;
+ pipe0.we <= we and not busy;
+ pipe0.addr <= addr;
+ pipe0.data <= tag_wr;
+ pipe0.entry_data <= vld & entry_din;
+
+
+gen_registered_rtag:
+if REGISTERED_RTAG = true generate
+registered_rtag:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ read_en <= re;
+ if re = '1' then
+ read_tag <= tag_rd;
+ end if;
+ end if;
+ end process;
+
+end generate;
+gen_non_registered_rtag:
+if REGISTERED_RTAG = false generate
+ read_en <= re;
+ read_tag <= read_tag;
+end generate;
+
+gen_registered_output:
+if REGISTERED_RESULT = true generate
+registered_output:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if read_en = '1' then
+ entry_dout <= final_stage_dout(ENTRY_WIDTH-1 downto 0);
+ hit_vld <= final_stage_dout(ENTRY_WIDTH);
+ end if;
+ end if;
+ end process;
+end generate;
+gen_non_registered_output:
+if REGISTERED_RESULT = false generate
+ entry_dout <= final_stage_dout(ENTRY_WIDTH-1 downto 0);
+ hit_vld <= final_stage_dout(ENTRY_WIDTH);
+end generate;
+
+pipe_line_wr:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ pipe3.we <= '0';
+ pipe2.we <= '0';
+ pipe1.we <= '0';
+ else
+ pipe3 <= pipe2;
+ pipe2 <= pipe1;
+ pipe1 <= pipe0;
+ end if;
+ end if;
+ end process;
+
+inst_track_ram: entity work.dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => DATA_WIDTH+1
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => track_ram_we,
+ addr_a => track_ram_addr_wr,
+ addr_b => track_ram_addr_rd,
+ din_a => track_ram_din,
+ dout_b => track_ram_dout
+ );
+
+ --------------------------------------------------------
+ cam_stage_raddr(0) <= read_tag(DATA_WIDTH-1 downto DATA_WIDTH-CAM_RAM_MAX_WIDTH);
+ cam_stage_waddr(0) <= cam_ram_addr_wr(DATA_WIDTH-1 downto DATA_WIDTH-CAM_RAM_MAX_WIDTH);
+ cam_stage_din(0) <= cam_ram_addr_wr(DATA_WIDTH-CAM_RAM_MAX_WIDTH/2-1 downto DATA_WIDTH-CAM_RAM_MAX_WIDTH);
+
+gen_cam_stage_addresses:
+for i in 1 to NUM_BLOCKS-1 generate
+ cam_stage_raddr(i) <= to_mips_01(cam_stage_dout(i-1)) & read_tag(DATA_WIDTH-(i+1)*CAM_RAM_MAX_WIDTH/2-1 downto DATA_WIDTH-(i+2)*CAM_RAM_MAX_WIDTH/2);
+ cam_stage_waddr(i) <= cam_ram_addr_wr(DATA_WIDTH-i*CAM_RAM_MAX_WIDTH/2-1 downto DATA_WIDTH-(i+2)*CAM_RAM_MAX_WIDTH/2);
+ cam_stage_din(i) <= cam_ram_addr_wr(DATA_WIDTH-(i+1)*CAM_RAM_MAX_WIDTH/2-1 downto DATA_WIDTH-(i+2)*CAM_RAM_MAX_WIDTH/2);
+end generate;
+
+gen_cam_stages:
+for i in 0 to NUM_BLOCKS-2 generate
+
+inst_cam_stage: entity work.dpram_1w1r1wc
+ GENERIC MAP
+ (
+ addr_width => CAM_RAM_MAX_WIDTH,
+ data_width => CAM_RAM_MAX_WIDTH/2
+ )
+ PORT MAP
+ (
+ clk_w => clk,
+ we => cam_ram_we,
+ wptr => cam_stage_waddr(i),
+ rptr => cam_stage_raddr(i),
+ din => cam_stage_din(i),
+ dout => cam_stage_dout(i)
+ );
+
+end generate;
+
+inst_cam_final_stage: entity work.dpram_1w1r1wc
+ GENERIC MAP
+ (
+ addr_width => CAM_RAM_MAX_WIDTH,
+ data_width => 1+ENTRY_WIDTH
+ )
+ PORT MAP
+ (
+ clk_w => clk,
+ we => final_stage_we,
+ wptr => final_stage_wptr,
+ rptr => final_stage_rptr,
+ din => final_stage_din,
+ dout => final_stage_dout
+ );
+
+------------------------------------------------------------------
+cam_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ state <= init;
+ else
+ state <= state_next;
+ end if;
+ end if;
+ end process;
+
+cam_state:
+ process(state, clear_count_rdy, over_write)
+ begin
+ busy <= over_write;
+ clear_count_en <= '0';
+
+ state_next <= state;
+
+ case state is
+
+ when init =>
+ busy <= '1';
+ state_next <= clear;
+
+ when clear =>
+ busy <= '1';
+ clear_count_en <= '1';
+ if clear_count_rdy = '1' then
+ state_next <= ready;
+ end if;
+
+ when ready =>
+
+ when others =>
+ state_next <= ready;
+
+ end case;
+
+ end process;
+
+------------------------------------------------------------------
+clear_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if clear_count_en = '0' then
+ clear_count_rdy <= '0';
+ clear_addr <= (BLOCK_ADDR_WIDTH-1 downto 0 => '1');
+ else
+ if clear_addr /= (BLOCK_ADDR_WIDTH-1 downto 0 => '0') then
+ clear_addr <= clear_addr - 1;
+ else
+ clear_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+------------------------------------------------------------------
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cop.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cop.vhd
new file mode 100644
index 0000000..9352e8c
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_cop.vhd
@@ -0,0 +1,867 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: The arithmetic logic unit
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.numeric_std.ALL;
+
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+use work.mips_instr.all;
+
+entity cop is
+ Generic
+ (
+ icache_size : natural := 2048; -- words
+ icache_line : natural := 8; -- words
+ dcache_size : natural := 2048; -- words
+ dcache_line : natural := 8 -- words
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ eb : in STD_LOGIC;
+ int : in unsigned(5 downto 0);
+ nmi : in STD_LOGIC;
+ ir_en : in STD_LOGIC;
+ ir : in word_t;
+ ctrl_in : in cop0_ctrl_in_t;
+ ctrl_out : out cop0_ctrl_out_t;
+ din : in word_t;
+ dout : out word_t
+ );
+end cop;
+
+architecture Behavioral of cop is
+
+ type cp0_regs_t is record
+ index : word_t;
+ random : word_t;
+ entry_lo : word_t;
+ config : word_t;
+ context : word_t;
+ pagemask : word_t;
+ wired : word_t;
+ badvaddr : word_t;
+ entry_hi : word_t;
+ status : word_t;
+ cause : word_t;
+ epc : word_t;
+ prid : word_t;
+ test : word_t;
+ end record;
+
+ signal regs : cp0_regs_t;
+ constant COP0_INDEX : natural := 0;
+ constant COP0_RANDOM : natural := 1;
+ constant COP0_ENTRY_LO : natural := 2;
+ constant COP0_CONFIG : natural := 3;
+ constant COP0_CONTEXT : natural := 4;
+ constant COP0_PAGEMASK : natural := 5;
+ constant COP0_WIRED : natural := 6;
+ constant COP0_07 : natural := 7;
+ constant COP0_BADVADDR : natural := 8;
+ constant COP0_09 : natural := 9;
+ constant COP0_ENTRY_HI : natural := 10;
+ constant COP0_0B : natural := 11;
+ constant COP0_STATUS : natural := 12;
+ constant COP0_CAUSE : natural := 13;
+ constant COP0_EPC : natural := 14;
+ constant COP0_PRID : natural := 15;
+ constant COP0_10 : natural := 16;
+ constant COP0_11 : natural := 17;
+ constant COP0_12 : natural := 18;
+ constant COP0_13 : natural := 19;
+ constant COP0_14 : natural := 20;
+ constant COP0_15 : natural := 21;
+ constant COP0_16 : natural := 22;
+ constant COP0_17 : natural := 23;
+ constant COP0_18 : natural := 24;
+ constant COP0_19 : natural := 25;
+ constant COP0_1A : natural := 26;
+ constant COP0_1B : natural := 27;
+ constant COP0_1C : natural := 28;
+ constant COP0_1D : natural := 29;
+ constant COP0_1E : natural := 30;
+ constant COP0_1F : natural := 31;
+
+ signal EX_reg_we : unsigned (31 downto 0);
+ signal index : unsigned (lg2(TLB_NUM_ENTRIES)-1 downto 0);
+ signal random : unsigned (lg2(TLB_NUM_ENTRIES)-1 downto 0);
+ signal PTEBase : unsigned (10 downto 0);
+ signal itlb_exc : STD_LOGIC;
+ signal dtlb_exc : STD_LOGIC;
+ signal itlb_entry_hi : tlb_entry_hi_t;
+ signal itlb_entry_lo : tlb_entry_lo_t;
+ signal dtlb_entry_hi : tlb_entry_hi_t;
+ signal dtlb_entry_lo : tlb_entry_lo_t;
+ signal entry_hi : tlb_entry_hi_t;
+ signal entry_lo : tlb_entry_lo_t;
+ signal exc_code : unsigned(4 downto 0);
+ signal tlb_sel : STD_LOGIC;
+ signal epc_reg_we : STD_LOGIC;
+ signal code_reg_we : STD_LOGIC;
+ signal bd : STD_LOGIC;
+ signal sw_int : unsigned(1 downto 0);
+ signal ip : unsigned(7 downto 0);
+ signal im : unsigned(7 downto 0);
+ signal status_save : STD_LOGIC;
+ signal status_rest : STD_LOGIC;
+ signal eflags : exc_flags_t;
+ signal EB_reg : STD_LOGIC;
+ signal icache_info : unsigned(7 downto 0);
+ signal dcache_info : unsigned(7 downto 0);
+ signal reg_rptr : reg_ptr_t;
+ signal reg_wptr : reg_ptr_t;
+ signal inject_exc : STD_LOGIC;
+ signal latch_vect_en : STD_LOGIC;
+ signal int_nmi : STD_LOGIC;
+ signal nmi_asserted : std_logic;
+
+ type cop_pipe_t is record
+ opc : opcode_t;
+ RFE : std_logic;
+ CO : std_logic;
+ reg_ptr : reg_ptr_t;
+ rs : reg_ptr_t;
+ rd : reg_ptr_t;
+ rt : reg_ptr_t;
+ func : func_t;
+ we : std_logic;
+ re : std_logic;
+ cs : std_logic;
+ TLBP : std_logic;
+ TLBR : std_logic;
+ TLBWI : std_logic;
+ TLBWR : std_logic;
+ end record;
+
+ signal cop_pipe_ID : cop_pipe_t;
+ signal cop_pipe_EX : cop_pipe_t;
+
+ function eval_int(ip : unsigned) return STD_LOGIC is
+ variable result : STD_LOGIC;
+ begin
+ result := '0';
+ for i in ip'range loop
+ result := result or ip(i);
+ end loop;
+
+ return result;
+ end eval_int;
+
+ type exc_state_t is (exc_idle, exc_pipe_flush, exc_commit, exc_inject, exc_enter, exc_leave, exc_left);
+ signal exc_state, exc_staten : exc_state_t;
+
+ function to_tlb_entry_lo(x : word_t) return tlb_entry_lo_t is
+ variable result : tlb_entry_lo_t;
+ begin
+ result.PFN := x(31 downto lg2(TLB_PAGE_SIZE));
+ result.N := x(11);
+ result.D := x(10);
+ result.V := x(9);
+ result.G := x(8);
+
+ return result;
+
+ end to_tlb_entry_lo;
+
+ function to_tlb_entry_hi(x : word_t) return tlb_entry_hi_t is
+ variable result : tlb_entry_hi_t;
+ begin
+ result.VPN := x(31 downto lg2(TLB_PAGE_SIZE));
+ result.ASID := x(lg2(TLB_PAGE_SIZE)-1 downto lg2(TLB_PAGE_SIZE)-lg2(TLB_NUM_ASIDS));
+
+ return result;
+
+ end to_tlb_entry_hi;
+
+ function to_tlb_entry_hi(x : tlb_entry_hi_t; va : word_t) return tlb_entry_hi_t is
+ variable result : tlb_entry_hi_t;
+ begin
+ result.VPN := va(31 downto lg2(TLB_PAGE_SIZE));
+ result.ASID := x.ASID;
+
+ return result;
+
+ end to_tlb_entry_hi;
+
+ function to_reg(x : tlb_entry_lo_t) return word_t is
+ variable result : word_t;
+ begin
+ result(31 downto lg2(TLB_PAGE_SIZE)) := x.PFN;
+ result(11) := x.N;
+ result(10) := x.D;
+ result(9) := x.V;
+ result(8) := x.G;
+ result(7 downto 0) := (others => '0');
+
+ return result;
+
+ end to_reg;
+
+ function to_reg(x : tlb_entry_hi_t) return word_t is
+ variable result : word_t;
+ begin
+ result(31 downto lg2(TLB_PAGE_SIZE)) := x.VPN;
+ result(lg2(TLB_PAGE_SIZE)-1 downto lg2(TLB_PAGE_SIZE)-lg2(TLB_NUM_ASIDS)) := x.ASID;
+ result(lg2(TLB_PAGE_SIZE)-lg2(TLB_NUM_ASIDS)-1 downto 0) := (others => '0');
+
+ return result;
+
+ end to_reg;
+
+--------------------------------------------------------------------------
+begin
+
+ -- Pass to pipeline TLB status
+ ctrl_out.pipe.ITLB <= ctrl_in.itlb.stat;
+ ctrl_out.pipe.DTLB <= ctrl_in.dtlb.stat;
+
+ -- I-TLB stuff
+ ctrl_out.itlb.entry_re <= '1'; -- cop_pipe_ID.TLBR and not tlb_sel; -- on tlbr
+ ctrl_out.itlb.entry_we <= (cop_pipe_EX.TLBWI or cop_pipe_EX.TLBWR) and not tlb_sel; -- on tlbwi or tlbwr
+ ctrl_out.itlb.entry_rd_idx <= index;
+ ctrl_out.itlb.entry_wr_idx <= random when cop_pipe_EX.TLBWR = '1' else index;
+ ctrl_out.itlb.entry_lo <= itlb_entry_lo;
+ ctrl_out.itlb.entry_hi <= itlb_entry_hi;
+
+ -- D-TLB stuff
+ ctrl_out.dtlb.entry_re <= '1'; -- cop_pipe_ID.TLBR and tlb_sel; -- on tlbr
+ ctrl_out.dtlb.entry_we <= (cop_pipe_EX.TLBWI or cop_pipe_EX.TLBWR) and tlb_sel; -- on tlbwi or tlbwr
+ ctrl_out.dtlb.entry_rd_idx <= index;
+ ctrl_out.dtlb.entry_wr_idx <= random when cop_pipe_EX.TLBWR = '1' else index;
+ ctrl_out.dtlb.entry_lo <= dtlb_entry_lo;
+ ctrl_out.dtlb.entry_hi <= dtlb_entry_hi;
+
+ cop_pipe_ID.cs <= ir_en;
+ cop_pipe_ID.opc <= extract_opc(ir);
+ cop_pipe_ID.rs <= extract_rs(ir);
+ cop_pipe_ID.rd <= extract_rd(ir);
+ cop_pipe_ID.rt <= extract_rt(ir);
+ cop_pipe_ID.func <= extract_func(ir);
+ cop_pipe_ID.CO <= ir(25);
+ cop_pipe_ID.re <= cop_pipe_ID.cs when (cop_pipe_ID.opc = "111000" or (cop_pipe_ID.opc = "010000" and cop_pipe_ID.rs = "00000")) else '0';
+ cop_pipe_ID.we <= cop_pipe_ID.cs when (cop_pipe_ID.opc = "110000" or (cop_pipe_ID.opc = "010000" and cop_pipe_ID.rs = "00100")) else '0';
+ cop_pipe_ID.RFE <= cop_pipe_ID.cs when (cop_pipe_ID.CO = '1' and cop_pipe_ID.func = "010000") else '0';
+ cop_pipe_ID.TLBP <= cop_pipe_ID.cs when (cop_pipe_ID.CO = '1' and cop_pipe_ID.func = "001000") else '0';
+ cop_pipe_ID.TLBR <= cop_pipe_ID.cs when (cop_pipe_ID.CO = '1' and cop_pipe_ID.func = "000001") else '0';
+ cop_pipe_ID.TLBWI <= cop_pipe_ID.cs when (cop_pipe_ID.CO = '1' and cop_pipe_ID.func = "000010") else '0';
+ cop_pipe_ID.TLBWR <= cop_pipe_ID.cs when (cop_pipe_ID.CO = '1' and cop_pipe_ID.func = "000110") else '0';
+ ctrl_out.pipe.EB <= EB_reg xor (regs.status(25) and not regs.status(1));
+ ctrl_out.pipe.user_mode <= not regs.status(1);
+ ctrl_out.pipe.exc_inject <= inject_exc or rst;
+ cop_pipe_ID.reg_ptr <= cop_pipe_ID.rd when cop_pipe_ID.opc = "010000" else cop_pipe_ID.rt;
+
+ eflags.Ov <= ctrl_in.pipe.events.alu_ovf or ctrl_in.pipe.events.alu_uvf;
+ eflags.DAdEL <= ctrl_in.pipe.events.data_load_err;
+ eflags.DAdES <= ctrl_in.pipe.events.data_store_err;
+ eflags.IAdEL <= ctrl_in.pipe.events.inst_load_err;
+ eflags.IAdEK <= ctrl_in.pipe.events.inst_priv_addr and not regs.status(1);
+ eflags.Sys <= ctrl_in.pipe.events.syscall;
+ eflags.Bp <= ctrl_in.pipe.events.break;
+ eflags.RI <= ctrl_in.pipe.events.illegal;
+ eflags.Int <= ctrl_in.pipe.events.int;
+ eflags.ITLB_MOD <= ctrl_in.pipe.events.ITLB_MOD;
+ eflags.ITLB_LOAD <= ctrl_in.pipe.events.ITLB_LOAD;
+ eflags.ITLB_STORE <= ctrl_in.pipe.events.ITLB_STORE;
+ eflags.DTLB_MOD <= ctrl_in.pipe.events.DTLB_MOD;
+ eflags.DTLB_LOAD <= ctrl_in.pipe.events.DTLB_LOAD;
+ eflags.DTLB_STORE <= ctrl_in.pipe.events.DTLB_STORE;
+
+ im <= regs.status(15 downto 8);
+ entry_lo <= itlb_entry_lo when tlb_sel = '0' else dtlb_entry_lo;
+ entry_hi <= itlb_entry_hi when tlb_sel = '0' else dtlb_entry_hi;
+ icache_info <= "00" & to_unsigned(lg2(icache_line), 3) & to_unsigned(lg2(icache_size)-8, 3);
+ dcache_info <= "00" & to_unsigned(lg2(dcache_line), 3) & to_unsigned(lg2(dcache_size)-8, 3);
+
+ regs.index <= '0' & '0' & (29 downto 8+lg2(TLB_NUM_ENTRIES) => '0') & index & (7 downto 0 => '0');
+ regs.random <= (31 downto 8+lg2(TLB_NUM_ENTRIES) => '0') & random & (7 downto 0 => '0');
+ regs.entry_lo <= to_reg(entry_lo);
+ regs.context <= PTEBase & regs.badvaddr(31 downto 13) & "00";
+ regs.entry_hi <= to_reg(entry_hi);
+ regs.cause <= bd & (30 downto 16 => '0') & ip & '0' & exc_code & "00";
+ regs.prid <= dcache_info & icache_info & X"02" & to_unsigned(REVISION ,8);
+
+ tlb_sel <= regs.config(0);
+
+-- COP Register read
+cop_register_read:
+ process(reg_rptr, regs)
+ variable reg : word_t;
+ variable reg_num : natural;
+ begin
+
+ reg_num := to_integer(reg_rptr);
+
+ case reg_num is
+
+ when COP0_INDEX => -- 00: index
+ reg := regs.index;
+
+ when COP0_RANDOM => -- 01: random
+ reg := regs.random;
+
+ when COP0_ENTRY_LO => -- 02: entry_lo
+ reg := regs.entry_lo;
+
+ when COP0_CONFIG => -- 03: config
+ reg := regs.config;
+
+ when COP0_CONTEXT => -- 04: Context
+ reg := regs.context;
+
+ -- 05: PageMask
+
+ when COP0_WIRED => -- 06: wired
+ reg := regs.wired;
+
+ -- 07: Reserved
+
+ when COP0_BADVADDR => -- 08: BadVAddr
+ reg := regs.badvaddr;
+
+ -- 09: Reserved
+
+ when COP0_ENTRY_HI => -- 0A: entry_hi
+ reg := regs.entry_hi;
+
+ -- 0B: Reserved
+
+ when COP0_STATUS => -- 0C: Status
+ reg := regs.status;
+
+ when COP0_CAUSE => -- 0D: Cause
+ reg := regs.cause;
+
+ when COP0_EPC => -- 0E: EPC (Exception Program Counter)
+ reg := regs.epc;
+
+ when COP0_PRID => -- 0F: PRId (Processor Revision Register)
+ reg := regs.prid;
+
+ -- 10 .. 1E : reserved
+
+ when COP0_1F => -- 1F: test
+ reg := regs.test;
+
+ when others =>
+ reg := (others => '-');
+
+ end case;
+
+ dout <= reg after 2 ns;
+
+ end process;
+
+-- Cop pipeline
+cop_pipe:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cop_pipe_EX.cs <= '0';
+ cop_pipe_EX.we <= '0';
+ cop_pipe_EX.re <= '0';
+ elsif ctrl_in.pipe.sdu.stall_all = '0' then
+ cop_pipe_EX <= cop_pipe_ID;
+ if cop_pipe_ID.we = '1' then
+ reg_wptr <= cop_pipe_ID.reg_ptr;
+ end if;
+ if cop_pipe_ID.re = '1' then
+ reg_rptr <= cop_pipe_ID.reg_ptr;
+ end if;
+ end if;
+ end if;
+ end process;
+
+-- COP Register write strobe generation
+cop_we_gen:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+-- if ctrl_in.pipe.sdu.stall_all = '0' then
+ EX_reg_we <= (others => '0');
+ if cop_pipe_ID.we = '1' then
+ EX_reg_we(to_integer(cop_pipe_ID.reg_ptr)) <= '1';
+ end if;
+-- end if;
+ end if;
+ end process;
+
+
+-- NMI/RST transition detector
+proc_nmi_transition:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ int_nmi <= '0';
+ nmi_asserted <= '0';
+ elsif latch_vect_en = '1' then
+ int_nmi <= '0';
+ elsif nmi_asserted = '1' then
+ if nmi = '0' then
+ nmi_asserted <= '0';
+ int_nmi <= '1';
+ end if;
+ elsif nmi = '1' then
+ nmi_asserted <= '1';
+ end if;
+ end if;
+ end process;
+
+-- Endian switch sampled at hard reset
+sample_endian:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ EB_reg <= eb;
+ end if;
+ end if;
+ end process;
+
+-- Main exception FSM next
+proc_exc_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ exc_state <= exc_idle;
+ else
+ exc_state <= exc_staten;
+ end if;
+ end if;
+ end process;
+
+-- Main exception FSM
+proc_exc_state:
+ process(exc_state, ctrl_in, cop_pipe_ID)
+ begin
+
+ ctrl_out.pipe.exc_commit <= '0';
+ ctrl_out.pipe.exc_pending <= '0';
+ ctrl_out.pipe.exc_exit <= '0';
+ epc_reg_we <= '0';
+ code_reg_we <= '0';
+ status_save <= '0';
+ status_rest <= '0';
+ inject_exc <= '0';
+ latch_vect_en <= '0';
+
+ exc_staten <= exc_state;
+
+ case exc_state is
+
+ when exc_idle =>
+ if cop_pipe_ID.RFE = '1' then
+ exc_staten <= exc_leave;
+ ctrl_out.pipe.exc_exit <= '1';
+ ctrl_out.pipe.exc_commit <= '1';
+ elsif ctrl_in.pipe.exc_req = '1' then
+ exc_staten <= exc_pipe_flush;
+ end if;
+
+ when exc_pipe_flush =>
+ ctrl_out.pipe.exc_pending <= '1';
+ ctrl_out.pipe.exc_commit <= '1';
+ if ctrl_in.pipe.exc_ack = '1' then
+ exc_staten <= exc_commit;
+ end if;
+
+ when exc_commit =>
+ latch_vect_en <= '1';
+ ctrl_out.pipe.exc_pending <= '1';
+ ctrl_out.pipe.exc_commit <= '1';
+ if ctrl_in.pipe.sdu.ID_stall = '0' then
+ exc_staten <= exc_inject;
+ end if;
+
+ when exc_inject =>
+ ctrl_out.pipe.exc_pending <= '1';
+ ctrl_out.pipe.exc_commit <= '1';
+ code_reg_we <= '1';
+ status_save <= '1';
+ epc_reg_we <= '1';
+ inject_exc <= '1';
+ exc_staten <= exc_enter;
+
+ when exc_enter =>
+ ctrl_out.pipe.exc_pending <= '1';
+ exc_staten <= exc_idle;
+
+ when exc_leave =>
+ exc_staten <= exc_left;
+ status_rest <= '1';
+ ctrl_out.pipe.exc_exit <= '1';
+ ctrl_out.pipe.exc_commit <= '1';
+
+ when exc_left =>
+ exc_staten <= exc_idle;
+
+ when others =>
+ exc_staten <= exc_idle;
+
+ end case;
+ end process;
+
+-- EPC reg and BD-bit write
+cop_exception_epc_write:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ bd <= '0';
+ regs.epc <= (others => '0');
+ elsif epc_reg_we = '1' then
+ bd <= ctrl_in.pipe.bd_wb;
+ regs.epc <= ctrl_in.pipe.epc_wb;
+ end if;
+ end if;
+ end process;
+
+-- BadVaddr and exception code write
+cop_exception_map:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ itlb_exc <= '0';
+ dtlb_exc <= '0';
+ if rst = '1' then
+ exc_code <= (others => '0');
+ regs.badvaddr <= (others => '0');
+ elsif code_reg_we = '1' then
+ if eflags.Ov = '1' then
+ exc_code <= "01100";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ elsif eflags.Sys = '1' then
+ exc_code <= "01000";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ elsif eflags.Bp = '1' then
+ exc_code <= "01001";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ elsif eflags.RI = '1' then
+ exc_code <= "01010";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ elsif eflags.IAdEL = '1' then
+ exc_code <= "00100";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ elsif eflags.IAdEK = '1' then
+ exc_code <= "00100";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ elsif eflags.DAdEL = '1' then
+ exc_code <= "00100";
+ regs.badvaddr <= ctrl_in.pipe.dmem_addr;
+ elsif eflags.DAdES = '1' then
+ exc_code <= "00101";
+ regs.badvaddr <= ctrl_in.pipe.dmem_addr;
+ elsif eflags.Int = '1' then
+ exc_code <= "00000";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ elsif eflags.ITLB_MOD = '1' then
+ exc_code <= "00001";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ itlb_exc <= '1';
+ elsif eflags.ITLB_LOAD = '1' then
+ exc_code <= "00010";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ itlb_exc <= '1';
+ elsif eflags.ITLB_STORE = '1' then
+ exc_code <= "00011";
+ regs.badvaddr <= ctrl_in.pipe.imem_addr;
+ itlb_exc <= '1';
+ elsif eflags.DTLB_MOD = '1' then
+ exc_code <= "00001";
+ regs.badvaddr <= ctrl_in.pipe.dmem_addr;
+ dtlb_exc <= '1';
+ elsif eflags.DTLB_LOAD = '1' then
+ exc_code <= "00010";
+ regs.badvaddr <= ctrl_in.pipe.dmem_addr;
+ dtlb_exc <= '1';
+ elsif eflags.DTLB_STORE = '1' then
+ exc_code <= "00011";
+ regs.badvaddr <= ctrl_in.pipe.dmem_addr;
+ dtlb_exc <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+-- Exception vector dispatch
+cop_exc_vector:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ ctrl_out.pipe.exc_vec <= X"BFC00000";
+ elsif latch_vect_en = '1' then
+ if ctrl_in.pipe.events.nmi = '1' then
+ ctrl_out.pipe.exc_vec <= X"BFC00000";
+ else
+ ctrl_out.pipe.exc_vec <= X"80000080";
+ if regs.status(22) = '1' then
+ ctrl_out.pipe.exc_vec <= X"BFC00180";
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ ctrl_out.icache.inv_addr <= regs.test;
+ ctrl_out.dcache.inv_addr <= regs.test;
+
+-- Custom I/D-Cache operations: invalidate all/line
+cop_cache_op:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ ctrl_out.icache.inv_at <= '0';
+ ctrl_out.icache.inv_all <= '0';
+ ctrl_out.dcache.inv_at <= '0';
+ ctrl_out.dcache.inv_all <= '0';
+ if cop_pipe_ID.cs = '1' and cop_pipe_ID.CO = '1' then
+ case cop_pipe_ID.func is
+ when "100000" =>
+ ctrl_out.icache.inv_all <= '1';
+ when "100001" =>
+ ctrl_out.icache.inv_at <= '1';
+ when "100010" =>
+ ctrl_out.dcache.inv_all <= '1';
+ when "100011" =>
+ ctrl_out.dcache.inv_at <= '1';
+
+ when others => null;
+ end case;
+ end if;
+ end if;
+ end process;
+
+-- CAUSE: IP register write and signalling Int to pipeline
+cop_ip_register:
+ process(clk)
+ variable ip_v : unsigned(7 downto 0);
+ variable ipm_v : unsigned(7 downto 0);
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ sw_int <= (others => '0');
+ elsif ctrl_in.pipe.sdu.WB_nop = '0' then
+ if EX_reg_we(COP0_CAUSE) = '1' then
+ sw_int <= din(9 downto 8);
+ end if;
+ end if;
+ ip_v := (int & sw_int);
+ ipm_v := ip_v and im;
+ ip <= ip_v;
+ ctrl_out.pipe.int <= (eval_int(ipm_v) and regs.status(0));
+ ctrl_out.pipe.NMI <= int_nmi;
+ end if;
+ end process;
+
+
+-- WIRED: Wired Register (RO)
+cop_wired_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ regs.wired <= X"0000_0008";
+ end if;
+ end if;
+ end process;
+
+-- RANDOM: Random Register (RO)
+cop_random_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or EX_reg_we(COP0_WIRED) = '1' then
+ random <= to_unsigned(TLB_NUM_ENTRIES-1, lg2(TLB_NUM_ENTRIES));
+ elsif random > regs.wired(lg2(TLB_NUM_ENTRIES)-1 downto 0) then
+ random <= random - 1;
+ else
+ random <= to_unsigned(TLB_NUM_ENTRIES-1, lg2(TLB_NUM_ENTRIES));
+ end if;
+ end if;
+ end process;
+
+-- INDEX: Index Register (RW)
+cop_index_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ index <= to_unsigned(0, lg2(TLB_NUM_ENTRIES));
+ elsif EX_reg_we(COP0_INDEX) = '1' then
+ index <= din(8+lg2(TLB_NUM_ENTRIES)-1 downto 8);
+ end if;
+ end if;
+ end process;
+
+-- CONTEXT: PTEBase Register (RW)
+cop_context_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ PTEBase <= to_unsigned(0, PTEBase'length);
+ elsif EX_reg_we(COP0_CONTEXT) = '1' then
+ PTEBase <= din(31 downto 21);
+ end if;
+ end if;
+ end process;
+
+-- ITLB EntryLO
+itlb_entrylo_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ itlb_entry_lo <= to_tlb_entry_lo(to_unsigned(0, 32));
+ elsif cop_pipe_EX.TLBR = '1' then
+ itlb_entry_lo <= ctrl_in.itlb.entry_lo;
+ elsif EX_reg_we(COP0_ENTRY_LO) = '1' and tlb_sel = '0' then
+ itlb_entry_lo <= to_tlb_entry_lo(din);
+ end if;
+ end if;
+ end process;
+
+-- ITLB EntryHI
+itlb_entryhi_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ itlb_entry_hi <= to_tlb_entry_hi(to_unsigned(0, 32));
+ elsif itlb_exc = '1' then
+ itlb_entry_hi <= to_tlb_entry_hi(itlb_entry_hi, regs.badvaddr);
+ elsif cop_pipe_EX.TLBR = '1' then
+ itlb_entry_hi <= ctrl_in.itlb.entry_hi;
+ elsif EX_reg_we(COP0_ENTRY_HI) = '1' and tlb_sel = '0' then
+ itlb_entry_hi <= to_tlb_entry_hi(din);
+ end if;
+ end if;
+ end process;
+
+-- DTLB
+dtlb_entrylo_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ dtlb_entry_lo <= to_tlb_entry_lo(to_unsigned(0, 32));
+ elsif cop_pipe_EX.TLBR = '1' then
+ dtlb_entry_lo <= ctrl_in.dtlb.entry_lo;
+ elsif EX_reg_we(COP0_ENTRY_LO) = '1' and tlb_sel = '1' then
+ dtlb_entry_lo <= to_tlb_entry_lo(din);
+ end if;
+ end if;
+ end process;
+
+-- DTLB EntryHI
+dtlb_entryhi_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ dtlb_entry_hi <= to_tlb_entry_hi(to_unsigned(0, 32));
+ elsif dtlb_exc = '1' then
+ dtlb_entry_hi <= to_tlb_entry_hi(dtlb_entry_hi, regs.badvaddr);
+ elsif cop_pipe_EX.TLBR = '1' then
+ dtlb_entry_hi <= ctrl_in.dtlb.entry_hi;
+ elsif EX_reg_we(COP0_ENTRY_HI) = '1' and tlb_sel = '1' then
+ dtlb_entry_hi <= to_tlb_entry_hi(din);
+ end if;
+ end if;
+ end process;
+
+-- TEST: COP Test Register
+cop_test_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ regs.test <= (others => '0');
+ elsif ctrl_in.pipe.sdu.WB_nop = '0' then
+ if EX_reg_we(COP0_1F) = '1' then
+ regs.test <= din;
+ end if;
+ end if;
+ end if;
+ end process;
+
+-- CONFIG: COP Config Register
+cop_config_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ regs.config <= (others => '0');
+ elsif ctrl_in.pipe.sdu.WB_nop = '0' then
+ if EX_reg_we(COP0_CONFIG) = '1' then
+ regs.config <= din;
+ end if;
+ end if;
+ end if;
+ end process;
+
+-- STATUS: COP Status Register
+cop_status_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ regs.status <= X"00600002"; -- at reset: set kernel mode enabled and interrupts disabled
+ elsif status_save = '1' then
+ if ctrl_in.pipe.events.nmi = '0' then
+ regs.status(5 downto 4) <= regs.status(3 downto 2);
+ regs.status(3 downto 2) <= regs.status(1 downto 0);
+ else
+ regs.status(22) <= '1';
+ end if;
+ regs.status(1 downto 0) <= "10"; -- at exception: set kernel mode enabled and interrupts disabled
+ elsif status_rest = '1' then
+ regs.status(1 downto 0) <= regs.status(3 downto 2);
+ regs.status(3 downto 2) <= regs.status(5 downto 4);
+ elsif ctrl_in.pipe.sdu.WB_nop = '0' then
+ if EX_reg_we(COP0_STATUS) = '1' then
+ if regs.status(1) = '1' then -- accessible only in kernel mode
+ regs.status(0) <= din(0); -- IEc
+ regs.status(1) <= din(1); -- KUc
+ regs.status(2) <= din(2); -- IEp
+ regs.status(3) <= din(3); -- KUp
+ regs.status(4) <= din(4); -- IEo
+ regs.status(5) <= din(5); -- KUo
+ end if;
+ regs.status(15 downto 8) <= din(15 downto 8); -- IM
+ regs.status(22) <= din(22); -- BEV
+ regs.status(25) <= din(25); -- RE
+ end if;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+end Behavioral;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_dcache.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_dcache.vhd
new file mode 100644
index 0000000..6f8d7e2
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_dcache.vhd
@@ -0,0 +1,780 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ CACHE_SIZE : natural := 1024; -- words
+ LINE_SIZE : natural := 8; -- words
+ WRITE_FIFO_SIZE : natural := 4
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ be : in unsigned(3 downto 0);
+ addr : in word_t;
+ din : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ bus_dout : out word_t;
+ bus_dout_vld : out std_logic;
+ bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(LINE_SIZE);
+ constant cache_index_width : natural := lg2(CACHE_SIZE) - word_index_width;
+ constant tag_width : natural := addr_width - lg2(CACHE_SIZE) - 2;
+ constant tag_ram_data_width : natural := 1 + tag_width + lg2(TLB_NUM_ENTRIES)+1;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tag : unsigned(tag_width-1 downto 0);
+ idx : unsigned(lg2(TLB_NUM_ENTRIES) downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tag := x(tag_width downto 1);
+ result.idx := x(lg2(TLB_NUM_ENTRIES)+tag_width+1 downto tag_width+1);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(tag_width downto 1) := x.tag;
+ result(lg2(TLB_NUM_ENTRIES)+tag_width+1 downto tag_width+1) := x.idx;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_busy_state_t is (init, ready, busy);
+ signal cache_busy_state, cache_busy_state_next : cache_busy_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, invalidate_post, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, wait_write_thru);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ type debug_t is record
+ ready : std_logic;
+ req_strobe : std_logic;
+ req_read : std_logic;
+ req_write : std_logic;
+ req_va : word_t;
+ req_pa : word_t;
+ dout_reg : word_t;
+ din_reg : word_t;
+ end record;
+
+ signal debug : debug_t;
+
+ signal req_strobe : std_logic;
+ signal cache_req : std_logic;
+ signal cache_req_rd : std_logic;
+ signal cache_req_wr : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal read_rdy : std_logic;
+ signal write_rdy : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+
+ signal mem_fetch_req : std_logic;
+ signal mem_fetch_ack : std_logic;
+ signal single_read_en : std_logic;
+ signal single_read_set : std_logic;
+ signal single_read_reg_vld : std_logic;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal data_ram_addr : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal data_ram_dout : word_t;
+ signal din_reg : word_t;
+ signal be_reg : unsigned(3 downto 0);
+ signal ctrl_data_ram_addr : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal data_ram_we : unsigned(3 downto 0);
+ signal single_read_reg : word_t;
+ signal cache_dout : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal write_hit : std_logic;
+ signal instant_raw : std_logic;
+ signal ram_write_en : std_logic;
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+ signal write_data_avail : std_logic;
+ signal read_write_buffer : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal write_through_en : std_logic;
+
+begin
+
+ -- Print info
+ assert false report "addr_width = " & natural'image(addr_width) & "." severity note;
+ assert false report "tag_width = " & natural'image(tag_width) & "." severity note;
+ assert false report "word_index_width = " & natural'image(word_index_width) & "." severity note;
+ assert false report "cache_index_width = " & natural'image(cache_index_width) & "." severity note;
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ bus_din_rdy <= fill_count_en or single_read_en;
+ bus_cmd_out.addr <= write_fifo_addr_out when read_write_buffer = '1' else to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= read_write_buffer;
+ bus_cmd_out.sel <= write_fifo_sel_out when read_write_buffer = '1' else (others => '1');
+ bus_dout <= write_fifo_data_out;
+ bus_dout_vld <= read_write_buffer and write_data_avail;
+
+-- tlb_query_out.vld <= cache_req;
+-- tlb_query_out.vaddr <= request_va;
+-- tlb_query_out.write <= cache_req_wr;
+ tlb_query_out.vld <= req_strobe;
+ tlb_query_out.vaddr <= addr;
+ tlb_query_out.idx <= cache_entry_out.idx;
+ tlb_query_out.write <= we;
+
+ request_pa <= tlb_query_in.paddr;
+
+ write_hit <= cache_req_wr and cache_hit and not tlb_query_in.exc;
+
+ debug.req_strobe <= req_strobe;
+ debug.req_read <= cache_req_rd;
+ debug.req_write <= cache_req_wr;
+ debug.req_va <= request_va;
+ debug.req_pa <= request_pa;
+ debug.din_reg <= din_reg;
+ debug.dout_reg <= cache_dout;
+ debug.ready <= cache_rdy;
+
+-------------------------------------------------
+-- ctrl
+-------------------------------------------------
+req_strobe <= cache_rdy and en;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_req_rd <= '0';
+ cache_req_wr <= '0';
+ elsif cache_rdy = '1' then
+ cache_req_rd <= en and not we;
+ cache_req_wr <= en and we;
+ cache_req <= en;
+ if we = '1' then
+ hit_cache_index <= to_cache_index(addr);
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ request_va <= (others => '0');
+ elsif req_strobe = '1' then
+ din_reg <= din;
+ be_reg <= be;
+ request_va <= addr;
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ instant_raw <= '0';
+ if to_word_index(addr) = fill_word_index and to_cache_index(addr) = hit_cache_index then
+ instant_raw <= write_hit and en and not we;
+ end if;
+ end if;
+ end process;
+
+-------------------------------------------------
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => lg2(WRITE_FIFO_SIZE),
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ write_fifo_data_in <= din_reg;
+ write_fifo_addr_in <= request_pa;
+ write_fifo_sel_in <= be_reg;
+ write_fifo_re <= read_write_buffer and bus_dout_rdy and bus_cmd_rdy;
+ write_fifo_we <= write_through_en;
+ write_data_avail <= not write_fifo_empty;
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+bus_request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ elsif single_read_en = '0' then
+ if single_read_set = '1' then
+ single_read_en <= '1';
+ end if;
+ elsif single_read_reg_vld = '1' then
+ if en = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ end if;
+ elsif bus_din_vld = '1' and single_read_en = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= '1';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(CACHE_SIZE),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => data_ram_addr,
+ din_a => din_reg(8*(i+1)-1 downto 8*i),
+ din_b => bus_din(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_busy_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_busy_state <= cache_busy_state_next;
+ end if;
+ end if;
+ end process;
+
+ cache_rdy <= read_rdy and not instant_raw and write_rdy;
+ write_rdy <= not (write_fifo_full and cache_req_wr);
+ rdy <= cache_rdy;
+
+ cache_dout <= single_read_reg when single_read_en = '1' else to_mips_01(data_ram_dout);
+ dout <= cache_dout;
+
+-- tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ tag_match <= '1' when ((to_tag(request_pa) xor cache_entry_out.tag) = (tag_width-1 downto 0 => '0')) else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when (was_miss = '0' and instant_raw = '0') else to_cache_index(request_va);
+
+ cache_entry_out <= to_dcache_entry(to_mips_01(tag_ram_dout));
+ cache_entry_out_inv <= to_dcache_entry(to_mips_01(tag_ram_dout_inv));
+
+ ram_read_en <= en or was_miss or fill_count_en;
+ data_ram_addr <= (to_cache_index(addr) & to_word_index(addr)) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (to_cache_index(request_va) & fill_word_index);
+ ctrl_data_ram_addr <= to_cache_index(request_va) & fill_word_index;
+ ctrl_data_ram_we <= (others => ram_write_en and bus_din_vld);
+ data_ram_we <= be_reg when (write_hit = '1') else (others => '0');
+
+ write_through_en <= cache_rdy and cache_req_wr; -- and tlb_query_in.hit and not tlb_query_in.flags.D;
+
+cache_busy_state_fsm:
+ process(cache_busy_state, tlb_query_in, cache_req_rd, cache_hit, mem_fetch_ack, single_read_en, single_read_reg_vld)
+ begin
+
+ read_rdy <= '0';
+ mem_fetch_req <= '0';
+ single_read_set <= '0';
+ cache_busy_state_next <= cache_busy_state;
+
+ case cache_busy_state is
+
+ when init =>
+ cache_busy_state_next <= ready;
+
+ when ready =>
+ if single_read_en = '1' then
+ read_rdy <= single_read_reg_vld;
+ else
+ read_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_query_in.exc = '0' then
+ if tlb_query_in.flags.N = '1' or cache_hit = '0' then
+-- mem_fetch_req <= '1';
+ read_rdy <= '0';
+ cache_busy_state_next <= busy;
+ end if;
+ end if;
+ end if;
+ end if;
+
+ when busy =>
+ mem_fetch_req <= '1';
+ if mem_fetch_ack = '1' then
+ single_read_set <= tlb_query_in.flags.N;
+ cache_busy_state_next <= ready;
+ end if;
+
+ when others =>
+ cache_busy_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, mem_fetch_req, tlb_query_in, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, bus_din_vld, invalidate_req, invalidate_all, write_through_en, write_data_avail)
+ begin
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ mem_fetch_ack <= '0';
+ read_write_buffer <= '0';
+
+ cache_entry_in.idx <= tlb_query_in.idx;
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif mem_fetch_req = '1' or write_data_avail = '1' then
+ cache_ctrl_state_next <= bus_request;
+-- bus_cmd_cycle_en <= '1';
+ elsif write_through_en = '1' then
+ cache_ctrl_state_next <= wait_write_thru;
+-- bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when invalidate_post =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when wait_write_thru =>
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ if write_data_avail = '1' then
+ read_write_buffer <= '1';
+ bus_cmd_we <= '1';
+ elsif mem_fetch_req = '1' then
+ if tlb_query_in.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ else
+ cache_ctrl_state_next <= mem_read;
+ end if;
+ else
+ cache_ctrl_state_next <= ready;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ mem_fetch_ack <= '1';
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ mem_fetch_ack <= '1';
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_func_pkg.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_func_pkg.vhd
new file mode 100644
index 0000000..59f6f31
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_func_pkg.vhd
@@ -0,0 +1,276 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: Types, constants and functions for JIPS
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+
+--------------------------------------------------------------------------
+package mips_func_pkg is
+
+ function store_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t;
+ function store_be(va : unsigned(1 downto 0); be_src, word2_en, word4_en, align_left, bypass : std_logic) return unsigned;
+ function load_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t;
+ function load_be(va : unsigned(1 downto 0); align_left, bypass : std_logic) return unsigned;
+ function load_sign_ext(x : word_t; bypass, signed, word2_en, word4_en : std_logic) return word_t;
+ function events_clr return event_t;
+ function event_is_active(e : event_t) return std_logic;
+ function "or" (a, b : event_t) return event_t;
+
+end mips_func_pkg;
+
+--------------------------------------------------------------------------
+package body mips_func_pkg is
+
+ function store_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t is
+ variable stage1 : word_t;
+ variable result : word_t;
+ variable sa : unsigned(1 downto 0);
+ begin
+
+ if bypass = '1' then
+ sa := "00";
+ else
+ sa := va + shift_off;
+ end if;
+
+ stage1 := x;
+ if sa(0) = '1' then
+ stage1 := x(23 downto 0) & x(31 downto 24);
+ end if;
+ result := stage1;
+ if sa(1) = '1' then
+ result := stage1(15 downto 0) & stage1(31 downto 16);
+ end if;
+
+ return result;
+ end store_shift;
+
+--------------------------------------------------------------------------
+ function store_be(va : unsigned(1 downto 0); be_src, word2_en, word4_en, align_left, bypass : std_logic) return unsigned is
+ variable result : unsigned(3 downto 0);
+ begin
+ result := (3 downto 0 => be_src);
+ if bypass = '0' then
+ if word2_en = '1' then
+ case va is
+ when "00" =>
+ result := "00" & be_src & be_src;
+ when "10" =>
+ result := be_src & be_src & "00";
+ when others => null;
+ end case;
+ elsif word4_en = '1' then
+ case va is
+ when "00" =>
+ result := "000" & be_src;
+ when "01" =>
+ result := "00" & be_src & '0';
+ when "10" =>
+ result := '0' & be_src & "00";
+ when "11" =>
+ result := be_src & "000";
+ when others => null;
+ end case;
+ elsif align_left = '1' then
+ case va is
+ when "00" =>
+ result := be_src & be_src & be_src & be_src;
+ when "01" =>
+ result := be_src & be_src & be_src & '0';
+ when "10" =>
+ result := be_src & be_src & "00";
+ when "11" =>
+ result := be_src & "000";
+ when others => null;
+ end case;
+ else
+ case va is
+ when "00" =>
+ result := "000" & be_src;
+ when "01" =>
+ result := "00" & be_src & be_src;
+ when "10" =>
+ result := '0' & be_src & be_src & be_src;
+ when "11" =>
+ result := be_src & be_src & be_src & be_src;
+ when others => null;
+ end case;
+ end if;
+ end if;
+
+ return result;
+
+ end store_be;
+
+--------------------------------------------------------------------------
+ function load_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t is
+ variable stage1 : word_t;
+ variable result : word_t;
+ variable sa : unsigned(1 downto 0);
+
+ begin
+ if bypass = '1' then
+ sa := "00";
+ else
+ sa := va + shift_off;
+ end if;
+
+ stage1 := x;
+ if sa(0) = '1' then
+ stage1 := x(7 downto 0) & x(31 downto 8);
+ end if;
+ result := stage1;
+ if sa(1) = '1' then
+ result := stage1(15 downto 0) & stage1(31 downto 16);
+ end if;
+
+ return result;
+ end load_shift;
+
+--------------------------------------------------------------------------
+ function load_be(va : unsigned(1 downto 0); align_left, bypass : std_logic) return unsigned is
+ variable result : unsigned(3 downto 0);
+ begin
+ result := (3 downto 0 => '1');
+ if bypass = '0' then
+ if align_left = '1' then
+ case va is
+ when "00" =>
+ result := "1000";
+ when "01" =>
+ result := "1100";
+ when "10" =>
+ result := "1110";
+ when "11" =>
+ result := "1111";
+ when others => null;
+ end case;
+ else
+ case va is
+ when "00" =>
+ result := "1111";
+ when "01" =>
+ result := "0111";
+ when "10" =>
+ result := "0011";
+ when "11" =>
+ result := "0001";
+ when others => null;
+ end case;
+ end if;
+ end if;
+
+ return result;
+
+ end load_be;
+
+--------------------------------------------------------------------------
+ function load_sign_ext(x : word_t; bypass, signed, word2_en, word4_en : std_logic) return word_t is
+ variable result : word_t;
+ variable sign : std_logic;
+
+ begin
+ if bypass = '1' then
+ result := x;
+ elsif word2_en = '1' then
+ sign := signed and x(15);
+ result := (31 downto 16 => sign) & x(15 downto 0);
+ else
+ sign := signed and x(7);
+ result := (31 downto 8 => sign) & x(7 downto 0);
+ end if;
+
+ return result;
+ end load_sign_ext;
+
+--------------------------------------------------------------------------
+ function events_clr return event_t is
+ variable result : event_t;
+ begin
+ result.NMI := '0';
+ result.Int := '0';
+ result.data_load_err := '0';
+ result.data_store_err := '0';
+ result.inst_load_err := '0';
+ result.inst_priv_addr := '0';
+ result.alu_ovf := '0';
+ result.alu_uvf := '0';
+ result.syscall := '0';
+ result.break := '0';
+ result.illegal := '0';
+
+ return result;
+
+ end events_clr;
+
+--------------------------------------------------------------------------
+ function event_is_active(e : event_t) return std_logic is
+ variable result : std_logic;
+ begin
+ result := '0';
+
+ result := result or e.NMI;
+ result := result or e.Int;
+ result := result or e.data_load_err;
+ result := result or e.data_store_err;
+ result := result or e.inst_load_err;
+ result := result or e.inst_priv_addr;
+ result := result or e.alu_ovf;
+ result := result or e.alu_uvf;
+ result := result or e.syscall;
+ result := result or e.break;
+ result := result or e.illegal;
+
+ return result;
+
+ end event_is_active;
+
+--------------------------------------------------------------------------
+ function "or" (a, b : event_t) return event_t is
+ variable result : event_t;
+ begin
+ result.NMI := a.NMI or b.NMI;
+ result.Int := a.Int or b.Int;
+ result.data_load_err := a.data_load_err or b.data_load_err;
+ result.data_store_err := a.data_store_err or b.data_store_err;
+ result.inst_load_err := a.inst_load_err or b.inst_load_err;
+ result.inst_priv_addr := a.inst_priv_addr or b.inst_priv_addr;
+ result.alu_ovf := a.alu_ovf or b.alu_ovf;
+ result.alu_uvf := a.alu_uvf or b.alu_uvf;
+ result.syscall := a.syscall or b.syscall;
+ result.break := a.break or b.break;
+ result.illegal := a.illegal or b.illegal;
+
+ return result;
+
+ end "or";
+
+--------------------------------------------------------------------------
+end mips_types;
+
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_icache.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_icache.vhd
new file mode 100644
index 0000000..55f862b
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_icache.vhd
@@ -0,0 +1,663 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ CACHE_SIZE : natural := 1024; -- words
+ LINE_SIZE : natural := 8 -- words
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ -- CPU control/data
+ en : in STD_LOGIC;
+ addr : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(LINE_SIZE);
+ constant cache_index_width : natural := lg2(CACHE_SIZE) - word_index_width;
+ constant tag_width : natural := addr_width - lg2(CACHE_SIZE) - 2;
+ constant tag_ram_data_width : natural := 1 + tag_width + lg2(TLB_NUM_ENTRIES);
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tag : unsigned(tag_width-1 downto 0);
+ tlb_idx : unsigned(lg2(TLB_NUM_ENTRIES)-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tag := x(tag_width downto 1);
+ result.tlb_idx := x(lg2(TLB_NUM_ENTRIES)+tag_width downto tag_width+1);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(tag_width downto 1) := x.tag;
+ result(lg2(TLB_NUM_ENTRIES)+tag_width downto tag_width+1) := x.tlb_idx;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+ type cache_busy_state_t is (init, ready, busy);
+ signal cache_busy_state, cache_busy_state_next : cache_busy_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, invalidate_post, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ type debug_t is record
+ ready : std_logic;
+ req_strobe : std_logic;
+ req_read : std_logic;
+ req_va : word_t;
+ req_pa : word_t;
+ dout_reg : word_t;
+ end record;
+
+ signal debug : debug_t;
+
+ signal req_strobe : std_logic;
+ signal cache_req_rd : std_logic;
+ signal read_rdy : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+
+ signal mem_fetch_req : std_logic;
+ signal mem_fetch_ack : std_logic;
+ signal single_read_en : std_logic;
+ signal single_read_set : std_logic;
+ signal single_read_reg_vld : std_logic;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+ signal single_read_reg : word_t;
+ signal cache_dout : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal ram_write_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+
+begin
+
+ -- Print info
+ assert false report "addr_width = " & natural'image(addr_width) & "." severity note;
+ assert false report "tag_width = " & natural'image(tag_width) & "." severity note;
+ assert false report "word_index_width = " & natural'image(word_index_width) & "." severity note;
+ assert false report "cache_index_width = " & natural'image(cache_index_width) & "." severity note;
+
+-- tlb_query_out.vld <= cache_req_rd;
+-- tlb_query_out.vaddr <= request_va;
+-- tlb_query_out.write <= '0';
+ tlb_query_out.vld <= req_strobe;
+ tlb_query_out.vaddr <= addr;
+ tlb_query_out.write <= '0';
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ request_pa <= tlb_query_in.paddr;
+
+ debug.req_strobe <= req_strobe;
+ debug.req_read <= cache_req_rd;
+ debug.req_va <= request_va;
+ debug.req_pa <= request_pa;
+ debug.dout_reg <= cache_dout;
+ debug.ready <= cache_rdy;
+
+-------------------------------------------------
+-- ctrl
+-------------------------------------------------
+req_strobe <= cache_rdy and en;
+
+ctrl_request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ cache_req_rd <= en;
+ end if;
+ end if;
+ end process;
+
+-------------------------------------------------
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ request_va <= (others => '0');
+ elsif req_strobe = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+bus_request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ elsif single_read_en = '0' then
+ if single_read_set = '1' then
+ single_read_en <= '1';
+ end if;
+ elsif single_read_reg_vld = '1' then
+ if en = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ end if;
+ elsif bus_din_vld = '1' and single_read_en = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= '1';
+ end if;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(CACHE_SIZE),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_busy_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_busy_state <= cache_busy_state_next;
+ end if;
+ end if;
+ end process;
+
+ bus_din_rdy <= fill_count_en or single_read_en;
+ bus_cmd_out.addr <= to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= '0';
+ bus_cmd_out.sel <= (others => '1');
+
+ cache_rdy <= read_rdy;
+ rdy <= cache_rdy;
+
+ cache_dout <= single_read_reg when single_read_en = '1' else data_ram_data_rd;
+ dout <= cache_dout;
+
+ cache_entry_out <= to_icache_entry(to_mips_01(tag_ram_data_rd));
+ tag_match <= '1' when ((to_tag(request_pa) xor cache_entry_out.tag) = (tag_width-1 downto 0 => '0')) else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+
+ cache_entry_out_inv <= to_icache_entry(to_mips_01(tag_ram_data_rd_inv));
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+
+ ram_read_en <= en or was_miss;
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when was_miss = '0' else to_cache_index(request_va);
+ data_ram_addr_rd <= (to_cache_index(addr) & to_word_index(addr)) when was_miss = '0' else (to_cache_index(request_va) & fill_word_index);
+ data_ram_addr_wr <= to_cache_index(request_va) & fill_word_index;
+ data_ram_data_wr <= bus_din;
+ data_ram_we <= ram_write_en and bus_din_vld;
+
+cache_busy_state_fsm:
+ process(cache_busy_state, tlb_query_in, cache_req_rd, cache_hit, mem_fetch_ack, single_read_en, single_read_reg_vld)
+ begin
+
+ read_rdy <= '0';
+ mem_fetch_req <= '0';
+ single_read_set <= '0';
+ cache_busy_state_next <= cache_busy_state;
+
+ case cache_busy_state is
+
+ when init =>
+ cache_busy_state_next <= ready;
+
+ when ready =>
+ if single_read_en = '1' then
+ read_rdy <= single_read_reg_vld;
+ else
+ read_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_query_in.exc = '0' then
+ if tlb_query_in.flags.N = '1' or cache_hit = '0' then
+-- mem_fetch_req <= '1';
+ read_rdy <= '0';
+ single_read_set <= tlb_query_in.flags.N;
+ cache_busy_state_next <= busy;
+ end if;
+ end if;
+ end if;
+ end if;
+
+ when busy =>
+ mem_fetch_req <= '1';
+ if mem_fetch_ack = '1' then
+ cache_busy_state_next <= ready;
+ end if;
+
+ when others =>
+ cache_busy_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, mem_fetch_req, tlb_query_in, bus_din_vld, cache_hit_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, invalidate_req, invalidate_all)
+ begin
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ mem_fetch_ack <= '0';
+
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif mem_fetch_req = '1' then
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when invalidate_post =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if tlb_query_in.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ mem_fetch_ack <= '1';
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ mem_fetch_ack <= '1';
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_pipeline.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_pipeline.vhd
new file mode 100644
index 0000000..e61aa27
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_pipeline.vhd
@@ -0,0 +1,877 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: The pipeline
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.numeric_std.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_instr.all;
+use work.mips_util_pkg.all;
+
+entity pipeline is
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+ imem_err : in STD_LOGIC;
+ imem_rdy : in STD_LOGIC;
+ imem_en : out STD_LOGIC;
+ imem_addr : out word_t;
+ imem_data : in word_t;
+ dmem_err : in STD_LOGIC;
+ dmem_rdy : in STD_LOGIC;
+ dmem_en : out STD_LOGIC;
+ dmem_we : out STD_LOGIC;
+ dmem_be : out unsigned(3 downto 0);
+ dmem_addr : out word_t;
+ dmem_din : in word_t;
+ dmem_dout : out word_t;
+ cop_ir : out word_t;
+ cop_ir_en : out STD_LOGIC;
+ cop_din : in word_t;
+ cop_dout : out word_t;
+ ctrl_out : out pipe_ctrl_out_t;
+ ctrl_in : in pipe_ctrl_in_t
+
+ );
+end pipeline;
+
+architecture Behavioral of pipeline is
+
+--------------------------------------------------------------------------
+ COMPONENT reg_dual is
+ Generic
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ Port
+ (
+ clk_w : in STD_LOGIC;
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ wptr : in unsigned (addr_width-1 downto 0);
+ din : in unsigned (data_width-1 downto 0);
+ rptr_a : in unsigned (addr_width-1 downto 0);
+ rptr_b : in unsigned (addr_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT shifter is
+ Generic
+ (
+ data_width : integer
+ );
+ Port
+ (
+ shift_ctrl : in shift_ctrl_t;
+ din : in unsigned (data_width-1 downto 0);
+ dout : out unsigned (data_width-1 downto 0)
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT alu is
+ Generic
+ (
+ data_width : integer
+ );
+ Port
+ (
+ op1_in : in unsigned (data_width-1 downto 0);
+ op2_in : in unsigned (data_width-1 downto 0);
+ op2_shifted : in unsigned (data_width-1 downto 0);
+ ctrl : in alu_ctrl_t;
+ result : out unsigned (data_width-1 downto 0);
+ flags : out alu_flags_t
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT bcu is
+ Generic
+ (
+ data_width : integer
+ );
+ Port
+ (
+ op1_in : in unsigned (data_width-1 downto 0);
+ op2_in : in unsigned (data_width-1 downto 0);
+ flags : out bcu_flags_t
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT muldiv is
+ Port
+ (
+ rst : in std_logic;
+ clk : in std_logic;
+ hilo_we : in std_logic;
+ din_hi : in word_t;
+ din_lo : in word_t;
+ mul_divn : in std_logic;
+ start : in std_logic;
+ s_un : in std_logic;
+ hilo_sel : in std_logic;
+ busy : out std_logic;
+ dout : out word_t
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ signal ID_stage : ID_t;
+ signal EX_stage : EX_t;
+ signal MEM_stage : MEM_t;
+ signal WB_stage : WB_t;
+ signal clk_2, clk_1 : STD_LOGIC;
+ signal hdu : hdu_t;
+ signal sdu : sdu_t;
+ signal reg_a : word_t;
+ signal reg_b : word_t;
+ signal branch_ce : STD_LOGIC;
+ signal cpu_run : STD_LOGIC;
+ signal alu_result : word_t;
+ signal mul_result : word_t;
+ signal mul_busy : STD_LOGIC;
+ signal EX_events_instr : event_t;
+ signal EX_events_alu : event_t;
+ signal EX_events_mem : event_t;
+ signal EX_events : event_t;
+ signal MEM_events : event_t;
+ signal bcu_op_a : word_t;
+ signal bcu_op_b : word_t;
+ signal bcu_flags : bcu_flags_t;
+ signal vaddr1 : word_t;
+ signal vaddr2 : word_t;
+ signal dmem_src : word_t;
+ signal stage_rst : unsigned(3 downto 0);
+ signal pipe_rst : STD_LOGIC;
+
+ signal pc : pc_t;
+
+--------------------------------------------------------------------------
+begin
+
+ clk_1 <= clk;
+ clk_2 <= not clk;
+ cpu_run <= ce;
+
+ -- Stall Detection Unit ---------------------------------------------------
+ sdu.ID_nop <= sdu.imem_dep or ctrl_in.exc_pending or ID_stage.exc or EX_stage.exc or MEM_stage.exc;
+ sdu.EX_nop <= sdu.mul_dep or ID_stage.nop or ID_stage.exc;
+ sdu.MEM_nop <= EX_stage.nop or EX_stage.exc;
+ sdu.WB_nop <= sdu.dmem_dep or MEM_stage.exc or WB_stage.exc or ctrl_in.exc_pending;
+
+ sdu.stall_all <= sdu.dmem_dep;
+ sdu.ID_stall <= sdu.stall_all or sdu.imem_dep or sdu.mul_dep or ctrl_in.exc_exit;
+ sdu.EX_stall <= sdu.stall_all;
+ sdu.MEM_stall <= sdu.stall_all;
+ sdu.WB_stall <= '0';
+
+ sdu.mul_dep <= ID_stage.ctrl.mul_access and (EX_stage.ctrl.mul_start or mul_busy);
+ sdu.imem_dep <= not imem_rdy;
+ sdu.dmem_dep <= not dmem_rdy and MEM_stage.ctrl.dmem_en;
+ ---------------------------------------------------------------------------
+ imem_en <= cpu_run and not (sdu.mul_dep or sdu.dmem_dep or ctrl_in.exc_commit);
+
+--------------------------------------------------------------------------
+-- Coprocessor assignments
+--------------------------------------------------------------------------
+ ctrl_out.sdu <= sdu;
+ ctrl_out.exc_req <= WB_stage.exc and not WB_stage.exc_last;
+ ctrl_out.exc_ack <= '1';
+ cop_ir <= ID_stage.IR;
+ cop_ir_en <= ID_stage.ctrl.cop_instr_en;
+ cop_dout <= EX_stage.reg_b; -- dmem_din when MEM_stage.ctrl.dmem_en = '1' else MEM_stage.ex_result;
+
+--------------------------------------------------------------------------
+-- Muldiv
+--------------------------------------------------------------------------
+inst_muldiv: muldiv
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ hilo_we => EX_stage.ctrl.mul_hilo_we,
+ din_hi => EX_stage.reg_a,
+ din_lo => EX_stage.reg_b,
+ mul_divn => EX_stage.ctrl.mul_mul_divn,
+ start => EX_stage.ctrl.mul_start,
+ s_un => EX_stage.ctrl.mul_s_un,
+ hilo_sel => EX_stage.ctrl.mul_hilo_sel,
+ busy => mul_busy,
+ dout => mul_result
+ );
+
+--------------------------------------------------------------------------
+-- IF stage
+--------------------------------------------------------------------------
+ imem_addr <= pc.curr;
+
+ pipe_rst <= stage_rst(0);
+
+proc_stage_reset:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if rst = '1' then
+ stage_rst <= (others => '1');
+ else
+ stage_rst <= stage_rst(stage_rst'left-1 downto 0) & '0';
+ end if;
+ end if;
+ end process;
+
+proc_stage_pc:
+ process(pc)
+ begin
+ if pc.branch_take = '1' then
+ pc.curr <= pc.pc_branch after 2 ns;
+ else
+ pc.curr <= pc.nxt after 2 ns;
+ end if;
+ end process;
+
+proc_stage_pc_branch:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if sdu.ID_stall = '0' then
+ pc.pc_branch <= pc.curr + ID_stage.bimm18;
+ end if;
+ end if;
+ end process;
+
+proc_stage_branch_ce:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if pipe_rst = '1' then
+ branch_ce <= '1';
+ else
+ branch_ce <= ctrl_in.exc_pending;
+ if sdu.ID_stall = '0' and ctrl_in.exc_inject = '0' then
+ branch_ce <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_pc_next:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if ctrl_in.exc_inject = '1' then
+ pc.nxt <= ctrl_in.exc_vec;
+ elsif sdu.ID_stall = '0' then
+ pc.last <= pc.curr;
+ if ID_stage.ctrl.jump = '1' then
+ pc.nxt <= ID_stage.jimm32;
+ elsif ID_stage.ctrl.jump_long = '1' then
+ pc.nxt <= ID_stage.reg_a;
+ elsif cpu_run = '1' then
+ pc.nxt <= pc.curr + 4;
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_branch:
+ process(clk_2)
+ begin
+ if rising_edge(clk_2) and branch_ce = '1' then
+ pc.branch_take <= '0';
+ if EX_stage.ctrl.branch = '1' then
+
+ case EX_stage.ctrl.bc_src is
+
+ when bc_eq_ne =>
+ pc.branch_take <= EX_stage.ctrl.bc_not xor bcu_flags.eq;
+
+ when bc_lez_gtz =>
+ pc.branch_take <= EX_stage.ctrl.bc_not xor (bcu_flags.eq or bcu_flags.ltz);
+
+ when bc_ltz_gez =>
+ pc.branch_take <= EX_stage.ctrl.bc_not xor bcu_flags.ltz;
+
+ when others => null;
+ end case;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+-- ID stage
+--------------------------------------------------------------------------
+ ID_stage.IR <= to_01(imem_data);
+ ID_stage.pcn <= pc.curr;
+ ID_stage.op <= decode_op(ID_stage.IR);
+ ID_stage.jimm32 <= extract_jimm32(ID_stage.IR, ID_stage.pcn);
+ ID_stage.bimm18 <= extract_bimm18(ID_stage.IR, ID_stage.pcn);
+ ID_stage.shamt <= extract_shamt(ID_stage.IR);
+ ID_stage.reg_a_rptr <= extract_rs(ID_stage.IR);
+ ID_stage.reg_b_rptr <= extract_rt(ID_stage.IR);
+ ID_stage.ctrl <= opcode_ctrl_lines(ID_stage.IR) when sdu.ID_nop = '0' else ctrl_lines_default;
+ ID_stage.reg_write <= ID_stage.ctrl.reg_write;
+ ID_stage.epc <= pc.last;
+ ID_stage.exc <= event_is_active(ID_stage.events); -- Todo: works
+ ID_stage.nop <= sdu.ID_nop;
+ ID_stage.va <= ID_stage.reg_a + extract_simm32(ID_stage.IR);
+
+proc_ID_except:
+ process(ID_stage, ctrl_in, pc)
+ begin
+ ID_stage.events <= events_clr;
+ ID_stage.events.inst_load_err <= not ctrl_in.exc_pending and (pc.nxt(1) or pc.nxt(0));
+ ID_stage.events.inst_priv_addr <= not ctrl_in.exc_pending and (pc.nxt(word_t'left) and ctrl_in.user_mode);
+ ID_stage.events.ITLB_LOAD <= ctrl_in.ITLB.exc_vld and ctrl_in.ITLB.exc_miss and not ctrl_in.ITLB.write;
+ ID_stage.events.ITLB_STORE <= ctrl_in.ITLB.exc_vld and ctrl_in.ITLB.exc_miss and ctrl_in.ITLB.write;
+ ID_stage.events.ITLB_MOD <= ctrl_in.ITLB.exc_vld and ctrl_in.ITLB.exc_dirty;
+ end process;
+
+proc_stage_hdu:
+ process(ID_stage, EX_stage, MEM_stage, WB_stage)
+ variable read_a, read_b : boolean;
+ variable raw_a_EX, raw_a_MEM, raw_a_WB : boolean;
+ variable raw_b_EX, raw_b_MEM, raw_b_WB : boolean;
+ variable reg_ptr_a : reg_ptr_t;
+ variable reg_ptr_b : reg_ptr_t;
+ begin
+
+ reg_ptr_a := ID_stage.reg_a_rptr;
+ reg_ptr_b := ID_stage.reg_b_rptr;
+ raw_a_EX := reg_ptr_a = EX_stage.reg_wptr and EX_stage.reg_we = '1';
+ raw_a_MEM := reg_ptr_a = MEM_stage.reg_wptr and MEM_stage.reg_we = '1';
+ raw_a_WB := reg_ptr_a = WB_stage.reg_wptr and WB_stage.reg_we = '1';
+ raw_b_EX := reg_ptr_b = EX_stage.reg_wptr and EX_stage.reg_we = '1';
+ raw_b_MEM := reg_ptr_b = MEM_stage.reg_wptr and MEM_stage.reg_we = '1';
+ raw_b_WB := reg_ptr_b = WB_stage.reg_wptr and WB_stage.reg_we = '1';
+
+ hdu.alu_fwd_a_ex <= raw_a_EX after 1 ns;
+ hdu.alu_fwd_a_mem <= raw_a_MEM after 1 ns;
+ hdu.alu_fwd_a_wb <= raw_a_WB after 1 ns;
+ hdu.alu_fwd_b_ex <= raw_b_EX after 1 ns;
+ hdu.alu_fwd_b_mem <= raw_b_MEM after 1 ns;
+ hdu.alu_fwd_b_wb <= raw_b_WB after 1 ns;
+
+ end process;
+
+proc_stage_fwd_a:
+ process(reg_a, hdu, EX_stage, MEM_stage, WB_stage)
+ variable data : word_t;
+ begin
+ data := reg_a;
+ if hdu.alu_fwd_a_ex then
+ data := EX_stage.result;
+ elsif hdu.alu_fwd_a_mem then
+ data := MEM_stage.reg_data;
+ elsif hdu.alu_fwd_a_wb then
+ data := WB_stage.reg_data;
+ end if;
+
+ for i in 0 to 31 loop
+ if data(i) = '1' then
+ ID_stage.reg_a(i) <= '1' after 1 ns;
+ else
+ ID_stage.reg_a(i) <= '0' after 1 ns;
+ end if;
+ end loop;
+
+ end process;
+
+proc_stage_fwd_b:
+ process(reg_b, hdu, EX_stage, MEM_stage, WB_stage)
+ variable data : word_t;
+ begin
+ data := reg_b;
+ if hdu.alu_fwd_b_ex then
+ data := EX_stage.result;
+ elsif hdu.alu_fwd_b_mem then
+ data := MEM_stage.reg_data;
+ elsif hdu.alu_fwd_b_wb then
+ data := WB_stage.reg_data;
+ end if;
+ ID_stage.reg_b <= to_mips_01(data) after 1 ns;
+
+ end process;
+
+proc_imm_mux:
+ process(ID_stage)
+ variable data : word_t;
+ begin
+ data := extract_uimm16(ID_stage.IR);
+
+ case ID_stage.ctrl.imm_src is
+
+ when src_imm32 =>
+ data := extract_simm32(ID_stage.IR);
+
+ when src_imm16 =>
+ data := extract_uimm16(ID_stage.IR);
+
+ when src_imm16_high =>
+ data := ID_stage.IR(word_t'length/2-1 downto 0) & (word_t'length/2-1 downto 0 => '0');
+
+ when others => null;
+
+ end case;
+
+ ID_stage.imm <= data after 1 ns;
+
+ end process;
+
+--------------------------------------------------------------------------
+inst_reg_dual: reg_dual
+ GENERIC MAP
+ (
+ addr_width => reg_ptr_t'length,
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_w => clk_1,
+ we => WB_stage.reg_we,
+ en => '1',
+ wptr => WB_stage.reg_wptr,
+ din => WB_stage.reg_data,
+ rptr_a => ID_stage.reg_a_rptr,
+ rptr_b => ID_stage.reg_b_rptr,
+ dout_a => reg_a,
+ dout_b => reg_b
+ );
+
+--------------------------------------------------------------------------
+-- EX stage
+--------------------------------------------------------------------------
+ EX_stage.reg_a_rptr <= extract_rs(EX_stage.IR);
+ EX_stage.reg_b_rptr <= extract_rt(EX_stage.IR);
+ EX_stage.result <= alu_result when EX_stage.ctrl.mul_access = '0' else mul_result;
+
+proc_stage_ID_EX_1:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if stage_rst(1) = '1' then
+ EX_stage.op <= op_nop;
+ EX_stage.IR <= (others => '0');
+ EX_stage.ctrl <= ctrl_lines_default;
+ EX_stage.reg_write <= '0';
+ EX_stage.epc <= (others => '0');
+ EX_stage.pcn <= (others => '0');
+ EX_stage.events_in <= events_clr;
+ elsif sdu.EX_stall = '0' then
+ EX_stage.nop <= sdu.EX_nop;
+ EX_stage.op <= ID_stage.op;
+ EX_stage.IR <= ID_stage.IR;
+ EX_stage.va <= ID_stage.va;
+
+ EX_stage.reg_a <= ID_stage.reg_a;
+ EX_stage.reg_b <= ID_stage.reg_b;
+ EX_stage.events_in <= ID_stage.events;
+ EX_stage.ctrl <= ID_stage.ctrl;
+ EX_stage.reg_write <= ID_stage.reg_write;
+ EX_stage.pcn <= ID_stage.pcn;
+ EX_stage.epc <= ID_stage.epc;
+ if sdu.EX_nop = '1' then
+ EX_stage.IR <= (others => '0');
+ EX_stage.ctrl <= ctrl_lines_default;
+ EX_stage.reg_write <= '0';
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_EX_instr_except:
+ process(EX_stage, ctrl_in)
+ begin
+ EX_events_instr <= events_clr;
+ EX_events_instr.illegal <= EX_stage.ctrl.exc_illegal;
+ EX_events_instr.break <= EX_stage.ctrl.exc_break;
+ EX_events_instr.syscall <= EX_stage.ctrl.exc_syscall;
+ end process;
+
+proc_stage_EX_alu_except:
+ process(EX_stage)
+ begin
+ EX_events_alu <= events_clr;
+ if EX_stage.ctrl.alu_exc_en = '1' then
+ if EX_stage.alu_flags.ovf = '1' then
+ EX_events_alu.alu_ovf <= '1';
+ end if;
+ if EX_stage.alu_flags.uvf = '1' then
+ EX_events_alu.alu_uvf <= '1';
+ end if;
+ end if;
+ end process;
+
+proc_stage_EX_mem_except:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if pipe_rst = '1' then
+ dmem_en <= '0';
+ elsif sdu.EX_stall = '0' then
+ EX_events_mem <= events_clr;
+ dmem_en <= '0';
+ if ID_stage.ctrl.dmem_en = '1' then
+ dmem_en <= '1';
+ if ID_stage.ctrl.except_en = '1' then
+ if ID_stage.ctrl.word2_en = '1' then
+ if ID_stage.va(0) = '1' then
+ EX_events_mem.data_load_err <= not ID_stage.ctrl.dmem_we;
+ EX_events_mem.data_store_err <= ID_stage.ctrl.dmem_we;
+ dmem_en <= '0';
+ end if;
+ elsif ID_stage.va(1 downto 0) /= "00" then
+ EX_events_mem.data_load_err <= not ID_stage.ctrl.dmem_we;
+ EX_events_mem.data_store_err <= ID_stage.ctrl.dmem_we;
+ dmem_en <= '0';
+ end if;
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ ctrl_out.dtlb_va <= ID_stage.va;
+ ctrl_out.dtlb_en <= ID_stage.ctrl.dmem_en;
+
+proc_stage_DMEM_ADDR:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if sdu.EX_stall = '0' then
+ if ctrl_in.EB = '1' then
+ if ID_stage.ctrl.word2_en = '0' then
+ EX_stage.pa_off <= not ID_stage.va(1 downto 0);
+ else
+ EX_stage.pa_off <= not ID_stage.va(1) & ID_stage.va(0);
+ end if;
+ else
+ EX_stage.pa_off <= ID_stage.va(1 downto 0);
+ end if;
+ end if;
+ end if;
+ end process;
+ dmem_src <= cop_din when EX_stage.ctrl.cop_instr_en = '1' else EX_stage.reg_b;
+ dmem_be <= store_be(EX_stage.pa_off, EX_stage.ctrl.dmem_en, EX_stage.ctrl.word2_en, EX_stage.ctrl.word4_en, EX_stage.ctrl.align_left, EX_stage.ctrl.shift_byp) after 1 ns;
+ dmem_we <= EX_stage.ctrl.dmem_we;
+ dmem_dout <= store_shift(dmem_src, EX_stage.pa_off, EX_stage.ctrl.shift_offset, EX_stage.ctrl.shift_byp) after 1ns;
+ dmem_addr <= EX_stage.va;
+ EX_stage.events <= EX_events_instr or EX_events_mem or EX_events_alu or EX_stage.events_in;
+ EX_stage.exc <= event_is_active(EX_stage.events);
+
+--------------------------------------------------------------------------
+proc_wptr_mux:
+ process(EX_stage)
+ variable opclass : opcode_t;
+ variable reg_wptr : reg_ptr_t;
+ begin
+
+ opclass := extract_opc(EX_stage.IR);
+ case opclass is
+ when "000000" =>
+ reg_wptr := extract_rd(EX_stage.IR);
+ when others =>
+ reg_wptr := extract_rt(EX_stage.IR);
+ end case;
+
+ EX_stage.reg_we <= EX_stage.reg_write after 1 ns;
+ if reg_wptr = "00000" then
+ EX_stage.reg_we <= '0' after 1 ns;
+ end if;
+
+ EX_stage.reg_wptr <= reg_wptr after 1 ns;
+ case EX_stage.ctrl.wptr_srcsel is
+ when wptr_src_imm =>
+ EX_stage.reg_wptr <= reg_wptr after 1 ns;
+
+ when wptr_src_const =>
+ EX_stage.reg_wptr <= to_unsigned(31, reg_ptr_t'length) after 1 ns;
+ EX_stage.reg_we <= '1' after 1 ns;
+
+ when others => null;
+ end case;
+
+ end process;
+
+--------------------------------------------------------------------------
+proc_stage_bcu_op:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) and sdu.EX_stall = '0' then
+ bcu_op_a <= ID_stage.reg_a;
+ bcu_op_b <= ID_stage.reg_b;
+ end if;
+ end process;
+
+EX_stage.alu_op1 <= EX_stage.reg_a;
+
+alu_op2_mux:
+ process(clk_1)
+ variable data : word_t;
+ begin
+
+ if rising_edge(clk_1) and sdu.EX_stall = '0' then
+ data := ID_stage.reg_b;
+
+ case ID_stage.ctrl.alu.op2_src is
+
+ when alu_src_reg =>
+ data := ID_stage.reg_b;
+
+ when alu_src_imm =>
+ data := ID_stage.imm;
+
+ when others => null;
+
+ end case;
+
+ EX_stage.alu_op2 <= data;
+ end if;
+
+ end process;
+
+shifter_sa_mux:
+ process(clk_1)
+ variable data : shamt_t;
+ variable data_inv : shamt_t;
+
+ begin
+ if rising_edge(clk_1) and sdu.EX_stall = '0' then
+ data := ID_stage.reg_a(4 downto 0);
+ case ID_stage.ctrl.shamt2_srcsel is
+
+ when sa_src_reg =>
+ data := ID_stage.reg_a(4 downto 0);
+
+ when sa_src_imm =>
+ data := ID_stage.shamt;
+
+ when others => null;
+
+ end case;
+ data_inv := not data + 1;
+ if ID_stage.ctrl.alu.shift_right = '0' then
+ EX_stage.shift_ctrl.shamt_rnd <= data_inv after 1 ns;
+ else
+ EX_stage.shift_ctrl.shamt_rnd <= data after 1 ns;
+ end if;
+ EX_stage.shift_ctrl.shamt_nrm <= data after 1 ns;
+ EX_stage.shift_ctrl.shift_right <= ID_stage.ctrl.alu.shift_right;
+ EX_stage.shift_ctrl.shift_arith <= ID_stage.ctrl.alu.shift_arith;
+ end if;
+
+ end process;
+
+--------------------------------------------------------------------------
+inst_shifter: shifter
+ GENERIC MAP
+ (
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ shift_ctrl => EX_stage.shift_ctrl,
+ din => EX_stage.reg_b,
+ dout => EX_stage.alu_op2_s
+ );
+
+inst_alu: alu
+ GENERIC MAP
+ (
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ op1_in => EX_stage.alu_op1,
+ op2_in => EX_stage.alu_op2,
+ op2_shifted => EX_stage.alu_op2_s,
+ ctrl => EX_stage.ctrl.alu,
+ result => alu_result,
+ flags => EX_stage.alu_flags
+ );
+
+inst_bcu: bcu
+ GENERIC MAP
+ (
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ op1_in => bcu_op_a,
+ op2_in => bcu_op_b,
+ flags => bcu_flags
+ );
+
+--------------------------------------------------------------------------
+-- MEM stage
+--------------------------------------------------------------------------
+proc_stage_MEM_n:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if stage_rst(2) = '1' then
+ MEM_stage.op <= op_nop;
+ MEM_stage.reg_we <= '0';
+ MEM_stage.ctrl <= ctrl_lines_default;
+ MEM_stage.pa_off <= (others => '0');
+ MEM_stage.events_in <= events_clr;
+ elsif sdu.MEM_stall = '0' then
+ MEM_stage.nop <= sdu.MEM_nop;
+ MEM_stage.op <= EX_stage.op;
+ MEM_stage.epc <= EX_stage.epc;
+ MEM_stage.pcn <= EX_stage.pcn;
+ MEM_stage.events_in <= EX_stage.events;
+ MEM_stage.reg_we <= EX_stage.reg_we;
+ MEM_stage.ctrl <= EX_stage.ctrl;
+ if EX_stage.ctrl.dmem_en = '1' then
+ MEM_stage.va <= EX_stage.va;
+ end if;
+ MEM_stage.pa_off <= EX_stage.pa_off;
+ MEM_stage.reg_wptr <= EX_stage.reg_wptr;
+ if MEM_stage.reg_wptr = EX_stage.reg_wptr then
+ if (EX_stage.ctrl.dmem_en and MEM_stage.ctrl.dmem_en) = '1' then
+ MEM_stage.ex_result <= MEM_stage.reg_data;
+ end if;
+ else
+ MEM_stage.ex_result <= EX_stage.reg_b;
+ end if;
+ if EX_stage.ctrl.cop_instr_en = '1' then
+ if EX_stage.ctrl.cop_read = '1' then
+ MEM_stage.ex_result <= cop_din;
+ end if;
+ elsif EX_stage.ctrl.dmem_en = '0' then
+ MEM_stage.ex_result <= EX_stage.result;
+ end if;
+ if sdu.MEM_nop = '1' then
+ MEM_stage.reg_we <= '0';
+ MEM_stage.ctrl <= ctrl_lines_default;
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_MEM_mux:
+ process(MEM_stage, dmem_din)
+ variable temp1 : word_t;
+ variable temp2 : word_t;
+ variable data : word_t;
+ variable be : unsigned(3 downto 0);
+ begin
+ data := MEM_stage.ex_result;
+ if MEM_stage.ctrl.reg_link = '1' then
+ data := MEM_stage.epc + 8;
+ elsif MEM_stage.ctrl.dmem_en = '1' then
+ temp1 := load_shift(dmem_din, MEM_stage.pa_off, MEM_stage.ctrl.shift_offset, MEM_stage.ctrl.shift_byp);
+ temp2 := load_sign_ext(temp1, MEM_stage.ctrl.sign_ext_byp, MEM_stage.ctrl.load_signed, MEM_stage.ctrl.word2_en, MEM_stage.ctrl.word4_en);
+ be := load_be(MEM_stage.pa_off, MEM_stage.ctrl.align_left, MEM_stage.ctrl.byte_en_byp);
+ if be(0) = '1' then
+ data(7 downto 0) := temp2(7 downto 0);
+ end if;
+ if be(1) = '1' then
+ data(15 downto 8) := temp2(15 downto 8);
+ end if;
+ if be(2) = '1' then
+ data(23 downto 16) := temp2(23 downto 16);
+ end if;
+ if be(3) = '1' then
+ data(31 downto 24) := temp2(31 downto 24);
+ end if;
+ end if;
+ MEM_stage.reg_data <= data after 1 ns;
+
+ end process;
+
+proc_stage_MEM_except:
+ process(MEM_stage, ctrl_in)
+ begin
+ MEM_stage.events <= MEM_stage.events_in;
+ MEM_stage.events.Int <= ctrl_in.int;
+ MEM_stage.events.NMI <= ctrl_in.NMI;
+ MEM_stage.events.DTLB_LOAD <= ctrl_in.DTLB.exc_vld and ctrl_in.DTLB.exc_miss and not ctrl_in.DTLB.write;
+ MEM_stage.events.DTLB_STORE <= ctrl_in.DTLB.exc_vld and ctrl_in.DTLB.exc_miss and ctrl_in.DTLB.write;
+ MEM_stage.events.DTLB_MOD <= ctrl_in.DTLB.exc_vld and ctrl_in.DTLB.exc_dirty;
+ end process;
+
+ MEM_stage.exc <= event_is_active(MEM_stage.events);
+
+--------------------------------------------------------------------------
+-- WB stage
+--------------------------------------------------------------------------
+proc_stage_WB_p:
+ process(clk_1)
+ variable branch_delay : std_logic;
+
+ begin
+ if rising_edge(clk_1) then
+ if stage_rst(3) = '1' then
+ WB_stage.op <= op_nop;
+ WB_stage.reg_we <= '1';
+ WB_stage.reg_wptr <= (others => '0');
+ WB_stage.epc <= (others => '0');
+ WB_stage.events <= events_clr;
+ WB_stage.exc <= '0';
+ elsif sdu.WB_stall = '0' then
+ WB_stage.nop <= sdu.WB_nop;
+ WB_stage.op <= MEM_stage.op;
+ WB_stage.epc_last <= WB_stage.epc;
+ WB_stage.epc <= MEM_stage.epc;
+ branch_delay := MEM_stage.ctrl.branch or MEM_stage.ctrl.jump or MEM_stage.ctrl.jump_long; -- Todo: works
+ WB_stage.bd <= branch_delay;
+ WB_stage.exc_last <= WB_stage.exc;
+ WB_stage.exc <= MEM_stage.exc;
+ WB_stage.reg_we <= MEM_stage.reg_we;
+ WB_stage.reg_wptr <= MEM_stage.reg_wptr;
+ WB_stage.reg_data <= MEM_stage.reg_data;
+ WB_stage.events <= MEM_stage.events;
+ if sdu.stall_all = '0' then
+ if MEM_stage.exc = '1' and WB_stage.exc = '0' then
+ ctrl_out.dmem_addr <= MEM_stage.va;
+ ctrl_out.imem_addr <= MEM_stage.epc;
+ ctrl_out.epc_wb <= MEM_stage.epc;
+ ctrl_out.bd_wb <= WB_stage.bd;
+ ctrl_out.events <= MEM_stage.events;
+ if WB_stage.bd = '1' then
+ ctrl_out.epc_wb <= WB_stage.epc;
+ end if;
+ end if;
+ end if;
+ if sdu.WB_nop = '1' then
+ WB_stage.reg_we <= '0';
+ end if;
+ if WB_stage.exc = '0' then
+ WB_stage.va <= MEM_stage.va;
+ end if;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+end Behavioral;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb.vhd
new file mode 100644
index 0000000..421032a
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb.vhd
@@ -0,0 +1,340 @@
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+ENTITY tlb IS
+ Generic
+ (
+ NUM_ENTRIES : natural := 8;
+ CACHE_KSEG1 : boolean := false;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+
+ rdy : out STD_LOGIC;
+
+ ctrl_in : in tlb_ctrl_in_t;
+ ctrl_out : out tlb_ctrl_out_t;
+
+ query_in : in tlb_query_in_t;
+ query_out : out tlb_query_out_t
+
+ );
+END tlb;
+
+ARCHITECTURE behavior OF tlb IS
+
+ signal clk_rd : STD_LOGIC;
+ signal cam_entry_lo : tlb_entry_lo_t;
+
+
+ signal entry_lo_UMC : tlb_entry_lo_t;
+ signal entry_lo_UMUC : tlb_entry_lo_t;
+ signal entry_lo_res : tlb_entry_lo_t;
+
+ signal qry_res : tlb_query_out_t;
+ signal stat_res : tlb_status_t;
+
+ signal pa : word_t;
+ signal hit : STD_LOGIC;
+ signal valid : STD_LOGIC;
+
+ signal cam_rdy : STD_LOGIC;
+ signal cam_hit_vld : STD_LOGIC;
+
+ signal vaddr_reg : word_t;
+
+ subtype reg_lo_t is unsigned(23 downto 0);
+ subtype reg_hi_t is unsigned(25 downto 0);
+
+ signal cam_lo_dout : reg_lo_t;
+ signal reg_lo_din : reg_lo_t;
+ signal reg_lo_dout : reg_lo_t;
+ signal reg_hi_din : reg_hi_t;
+ signal reg_hi_dout : reg_hi_t;
+
+ function to_entry_lo(x : reg_lo_t) return tlb_entry_lo_t is
+ variable result : tlb_entry_lo_t;
+ begin
+ result.PFN := x(23 downto 4);
+ result.N := x(3);
+ result.D := x(2);
+ result.V := x(1);
+ result.G := x(0);
+
+ return result;
+
+ end to_entry_lo;
+
+ function to_entry_hi(x : reg_hi_t) return tlb_entry_hi_t is
+ variable result : tlb_entry_hi_t;
+ begin
+ result.VPN := x(25 downto 6);
+ result.ASID := x(5 downto 0);
+
+ return result;
+
+ end to_entry_hi;
+
+ function to_reg_lo(x : tlb_entry_lo_t) return reg_lo_t is
+ variable result : reg_lo_t;
+ begin
+ result(23 downto 4) := x.PFN;
+ result(3) := x.N;
+ result(2) := x.D;
+ result(1) := x.V;
+ result(0) := x.G;
+
+ return result;
+
+ end to_reg_lo;
+
+ function to_reg_hi(x : tlb_entry_hi_t) return reg_hi_t is
+ variable result : reg_hi_t;
+ begin
+ result(25 downto 6) := x.VPN;
+ result(5 downto 0) := x.ASID;
+
+ return result;
+
+ end to_reg_hi;
+
+ signal hit_idx : integer;
+ function decode(x : unsigned; N : integer) return integer is
+ variable result : integer;
+ begin
+ result := 0;
+ for i in 0 to N-1 loop
+ if x(i) = '1' then
+ result := i;
+ end if;
+ end loop;
+
+ return result;
+
+ end decode;
+
+begin
+ clk_rd <= clk;
+ rdy <= cam_rdy;
+
+ stat_res.exc_vld <= valid;
+ stat_res.exc_miss <= not hit;
+ stat_res.exc_dirty <= hit and qry_res.flags.D and query_in.write;
+ stat_res.write <= query_in.write;
+
+ qry_res.paddr <= pa;
+ qry_res.hit <= hit;
+ qry_res.flags.N <= entry_lo_res.N;
+ qry_res.flags.D <= entry_lo_res.D;
+ qry_res.flags.V <= entry_lo_res.V;
+ qry_res.exc <= stat_res.exc_miss or stat_res.exc_dirty;
+ qry_res.vld <= valid;
+
+ query_out <= qry_res;
+ ctrl_out.stat <= stat_res;
+
+ pa <= entry_lo_res.PFN & vaddr_reg(lg2(TLB_PAGE_SIZE)-1 downto 0);
+ cam_entry_lo <= to_entry_lo(to_mips_01(cam_lo_dout));
+
+inst_reg_entry_lo: entity work.dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => 24
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ctrl_in.entry_re,
+ we_a => ctrl_in.entry_we,
+ addr_a => ctrl_in.entry_wr_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ addr_b => ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ din_a => reg_lo_din,
+ dout_b => reg_lo_dout
+ );
+ reg_lo_din <= to_reg_lo(ctrl_in.entry_lo);
+ ctrl_out.entry_lo <= to_entry_lo(to_mips_01(reg_lo_dout));
+
+inst_reg_entry_hi: entity work.dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => 26
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ctrl_in.entry_re,
+ we_a => ctrl_in.entry_we,
+ addr_a => ctrl_in.entry_wr_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ addr_b => ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ din_a => reg_hi_din,
+ dout_b => reg_hi_dout
+ );
+
+ reg_hi_din <= to_reg_hi(ctrl_in.entry_hi);
+ ctrl_out.entry_hi <= to_entry_hi(to_mips_01(reg_hi_dout));
+
+inst_cam_va: entity work.cam2
+ GENERIC MAP
+ (
+ NUM_ENTRIES => NUM_ENTRIES,
+ ENTRY_WIDTH => reg_lo_t'length,
+ DATA_WIDTH => 20,
+ CAM_RAM_MAX_WIDTH => 8
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+
+ rdy => cam_rdy,
+
+ re => query_in.vld,
+ we => ctrl_in.entry_we,
+ vld => '1',
+ addr => ctrl_in.entry_wr_idx,
+ entry_din => reg_lo_din,
+ entry_dout => cam_lo_dout,
+
+ tag_wr => ctrl_in.entry_hi.VPN,
+ tag_rd => query_in.vaddr(31 downto lg2(TLB_PAGE_SIZE)),
+
+ hit_vld => cam_hit_vld
+
+ );
+
+
+proc_entry_lo_umc:
+ process(clk)
+ variable index : integer;
+ begin
+ if rising_edge(clk) then
+ entry_lo_UMC.N <= '0';
+ entry_lo_UMC.D <= '0';
+ entry_lo_UMC.G <= '0';
+ if query_in.vld = '1' then
+ entry_lo_UMC.V <= '0';
+ if query_in.vaddr(31 downto 29) = "100" then -- 80000000 to 9FFFFFFF
+ entry_lo_UMC.V <= '1';
+ entry_lo_UMC.PFN <= "000" & query_in.vaddr(28 downto lg2(TLB_PAGE_SIZE));
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_entry_lo_umuc:
+ process(clk)
+ variable index : integer;
+ begin
+ if rising_edge(clk) then
+ if CACHE_KSEG1 then
+ entry_lo_UMUC.N <= '0';
+ else
+ entry_lo_UMUC.N <= '1';
+ end if;
+ entry_lo_UMUC.D <= '0';
+ entry_lo_UMUC.G <= '0';
+ if query_in.vld = '1' then
+ entry_lo_UMUC.V <= '0';
+ if query_in.vaddr(31 downto 29) = "101" then -- A0000000 to BFFFFFFF
+ entry_lo_UMUC.V <= '1';
+ entry_lo_UMUC.PFN <= "000" & query_in.vaddr(28 downto lg2(TLB_PAGE_SIZE));
+ end if;
+ end if;
+ end if;
+ end process;
+
+tlb_entry_lo_result_translate:
+if USE_TLB = true generate
+ tlb_entry_lo_result:
+ process(cam_entry_lo, entry_lo_umc, entry_lo_umuc)
+ begin
+ entry_lo_res <= cam_entry_lo;
+ if entry_lo_umc.V = '1' then
+ entry_lo_res <= entry_lo_umc;
+ end if;
+ if entry_lo_umuc.V = '1' then
+ entry_lo_res <= entry_lo_umuc;
+ end if;
+
+ end process;
+end generate;
+
+tlb_entry_lo_result_notranslate:
+if USE_TLB = false generate
+ tlb_entry_lo_result:
+ process(cam_entry_lo, vaddr_reg, entry_lo_umc, entry_lo_umuc)
+ begin
+ entry_lo_res.N <= '0';
+ entry_lo_res.D <= '0';
+ entry_lo_res.V <= '1';
+ entry_lo_res.PFN <= vaddr_reg(31 downto lg2(TLB_PAGE_SIZE));
+ if entry_lo_umc.V = '1' then
+ entry_lo_res <= entry_lo_umc;
+ end if;
+ if entry_lo_umuc.V = '1' then
+ entry_lo_res <= entry_lo_umuc;
+ end if;
+
+ end process;
+end generate;
+
+tlb_hit_combine_translate:
+if USE_TLB = true generate
+ tlb_hit_combine:
+ process(cam_hit_vld, entry_lo_umc, entry_lo_umuc)
+ variable t_v : std_logic;
+ begin
+ t_v := cam_hit_vld;
+ t_v := t_v or entry_lo_umc.V or entry_lo_umuc.V;
+ hit <= t_v;
+
+ end process;
+end generate;
+
+tlb_hit_combine_notranslate:
+if USE_TLB = false generate
+ tlb_hit_combine:
+ process(cam_entry_lo, entry_lo_umc, entry_lo_umuc)
+ variable t_v : std_logic;
+ begin
+ t_v := entry_lo_umc.V or entry_lo_umuc.V;
+ hit <= t_v;
+
+ end process;
+end generate;
+
+registered_output:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if query_in.vld = '1' then
+ vaddr_reg <= query_in.vaddr;
+ end if;
+ valid <= query_in.vld;
+ if ce = '1' then
+ if ctrl_in.entry_re = '1' then
+ ctrl_out.entry_vld <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+
+
+------------------------------------------------------------------
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_20130811.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_20130811.vhd
new file mode 100644
index 0000000..d6a270a
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_20130811.vhd
@@ -0,0 +1,204 @@
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+ENTITY tlb IS
+ Generic
+ (
+ NUM_ENTRIES : natural := 8;
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+
+ rdy : out STD_LOGIC;
+
+ ctrl_in : in tlb_ctrl_in_t;
+ ctrl_out : out tlb_ctrl_out_t;
+
+ query_in : in tlb_query_in_t;
+ query_out : out tlb_query_out_t
+
+ );
+END tlb;
+
+ARCHITECTURE behavior OF tlb IS
+
+ constant UNMAPPED_CACHED : natural := NUM_ENTRIES;
+ constant UNMAPPED_UNCACHED : natural := NUM_ENTRIES+1;
+
+ signal blk_entry_we : unsigned(NUM_ENTRIES-1 downto 0);
+ signal blk_hit : unsigned(NUM_ENTRIES-1+2 downto 0);
+
+ type flags_array_t is array (0 to NUM_ENTRIES-1+2) of tlb_flags_t;
+ signal blk_flags : flags_array_t;
+
+ type word_array_t is array (0 to NUM_ENTRIES-1+2) of word_t;
+ signal blk_pfn : word_array_t;
+
+ type tlb_entry_lo_array_t is array (0 to NUM_ENTRIES-1) of tlb_entry_lo_t;
+ signal blk_entry_lo : tlb_entry_lo_array_t;
+
+ type tlb_entry_hi_array_t is array (0 to NUM_ENTRIES-1) of tlb_entry_hi_t;
+ signal blk_entry_hi : tlb_entry_hi_array_t;
+
+ signal qry_res_no_translate : tlb_query_out_t;
+ signal qry_res : tlb_query_out_t;
+
+ signal stat_res_no_translate : tlb_status_t;
+ signal stat_res : tlb_status_t;
+
+ signal pa : word_t;
+ signal hit : STD_LOGIC;
+ signal flags : tlb_flags_t;
+
+
+begin
+
+ rdy <= '1';
+
+ blk_hit(UNMAPPED_CACHED) <= '1' when query_in.vaddr(31 downto 29) = "100" else '0';
+ blk_pfn(UNMAPPED_CACHED) <= "000" & query_in.vaddr(28 downto lg2(TLB_PAGE_SIZE)) & (lg2(TLB_PAGE_SIZE)-1 downto 0 => '0');
+ blk_flags(UNMAPPED_CACHED).N <= '0';
+ blk_flags(UNMAPPED_CACHED).D <= '0';
+ blk_flags(UNMAPPED_CACHED).V <= '1';
+
+ blk_hit(UNMAPPED_UNCACHED) <= '1' when query_in.vaddr(31 downto 29) = "101" else '0';
+ blk_pfn(UNMAPPED_UNCACHED) <= "000" & query_in.vaddr(28 downto lg2(TLB_PAGE_SIZE)) & (lg2(TLB_PAGE_SIZE)-1 downto 0 => '0');
+ blk_flags(UNMAPPED_UNCACHED).N <= '1';
+ blk_flags(UNMAPPED_UNCACHED).D <= '0';
+ blk_flags(UNMAPPED_UNCACHED).V <= '1';
+
+ stat_res.exc_vld <= '0';
+ stat_res.exc_miss <= not hit;
+ stat_res.exc_dirty <= hit and flags.D and query_in.write;
+ stat_res.write <= query_in.write;
+
+ stat_res_no_translate.exc_vld <= '0';
+ stat_res_no_translate.exc_miss <= '0';
+ stat_res_no_translate.exc_dirty <= '0';
+ stat_res_no_translate.write <= query_in.write;
+
+ qry_res.paddr <= pa;
+ qry_res.hit <= hit;
+ qry_res.flags <= flags;
+ qry_res.exc <= stat_res.exc_miss or stat_res.exc_dirty;
+ qry_res.vld <= '0';
+
+ qry_res_no_translate.vld <= '0';
+ qry_res_no_translate.paddr <= query_in.vaddr;
+ qry_res_no_translate.hit <= '1';
+ qry_res_no_translate.exc <= '0';
+ qry_res_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when query_in.vaddr(31 downto 29) = "101" else '0';
+ qry_res_no_translate.flags.D <= '0';
+ qry_res_no_translate.flags.V <= '1';
+
+
+gen_tlb:
+for i in 0 to NUM_ENTRIES-1 generate
+
+ inst_tlb_block : entity work.tlb_block
+ Port map
+ (
+ clk => clk,
+ rst => rst,
+
+ entry_we => blk_entry_we(i),
+ entry_hi_in => ctrl_in.entry_hi,
+ entry_lo_in => ctrl_in.entry_lo,
+
+ entry_hi_out => blk_entry_hi(i),
+ entry_lo_out => blk_entry_lo(i),
+
+ va => query_in.vaddr,
+ pfn => blk_pfn(i),
+ flags => blk_flags(i),
+ hit => blk_hit(i)
+ );
+
+end generate;
+
+tlb_blk_write_mux:
+ process(ctrl_in)
+ begin
+ blk_entry_we <= (others => '0');
+ blk_entry_we(to_integer(ctrl_in.entry_wr_idx(lg2(NUM_ENTRIES)-1 downto 0))) <= ctrl_in.entry_we;
+ end process;
+
+tlb_pa_combine:
+ process(blk_hit, blk_pfn, query_in.vaddr)
+ variable t_v : word_t;
+ begin
+ for i in 0 to NUM_ENTRIES-1+2 loop
+ if blk_hit(i) = '1' then
+ t_v := blk_pfn(i);
+ end if;
+ end loop;
+ pa <= t_v(31 downto lg2(TLB_PAGE_SIZE)) & query_in.vaddr(lg2(TLB_PAGE_SIZE)-1 downto 0);
+
+ end process;
+
+tlb_flags_combine:
+ process(blk_hit, blk_flags)
+ variable t_v : tlb_flags_t;
+ begin
+ for i in 0 to NUM_ENTRIES-1+2 loop
+ if blk_hit(i) = '1' then
+ t_v := blk_flags(i);
+ end if;
+ end loop;
+ flags <= t_v;
+
+ end process;
+
+tlb_hit_combine:
+ process(blk_hit, blk_flags)
+ variable t_v : std_logic;
+ begin
+ t_v := '0';
+ for i in 0 to NUM_ENTRIES-1+2 loop
+ t_v := t_v or (blk_hit(i) and blk_flags(i).V);
+ end loop;
+ hit <= t_v;
+
+ end process;
+
+registered_output:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ ctrl_out.entry_vld <= '0';
+ if query_in.vld = '1' then
+ if USE_TLB then
+ query_out <= qry_res;
+ ctrl_out.stat <= stat_res;
+ else
+ query_out <= qry_res_no_translate;
+ ctrl_out.stat <= stat_res_no_translate;
+ end if;
+ end if;
+ query_out.vld <= query_in.vld;
+ ctrl_out.stat.exc_vld <= query_in.vld;
+ if ce = '1' then
+ if ctrl_in.entry_re = '1' then
+ ctrl_out.entry_lo <= blk_entry_lo(to_integer(ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0)));
+ ctrl_out.entry_hi <= blk_entry_hi(to_integer(ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0)));
+ ctrl_out.entry_vld <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+
+
+------------------------------------------------------------------
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_block.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_block.vhd
new file mode 100644
index 0000000..14466e3
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_block.vhd
@@ -0,0 +1,85 @@
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+ENTITY tlb_block IS
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ entry_we : in STD_LOGIC;
+ entry_lo_in : in tlb_entry_lo_t;
+ entry_hi_in : in tlb_entry_hi_t;
+ entry_lo_out : out tlb_entry_lo_t;
+ entry_hi_out : out tlb_entry_hi_t;
+ va : in word_t;
+ pfn : out word_t;
+ flags : out tlb_flags_t;
+ hit : out STD_LOGIC
+
+ );
+END tlb_block;
+
+ARCHITECTURE behavior OF tlb_block IS
+
+ signal entry_lo : tlb_entry_lo_t;
+ signal entry_hi : tlb_entry_hi_t;
+ signal vpn_match : STD_LOGIC;
+ signal asid_match : STD_LOGIC;
+ signal tlb_hit : STD_LOGIC;
+ signal tlb_pfn : word_t;
+
+begin
+
+asid_match <= '1' when (entry_hi.ASID = entry_hi_in.ASID) else entry_lo.G;
+vpn_match <= '1' when (va(31 downto lg2(TLB_PAGE_SIZE)) = entry_hi.VPN) else '0';
+
+tlb_hit <= (asid_match and vpn_match) after 0 ns;
+tlb_pfn <= entry_lo.PFN & (lg2(TLB_PAGE_SIZE)-1 downto 0 => '0');
+
+pfn <= tlb_pfn after 0 ns;
+
+flags.N <= entry_lo.N;
+flags.D <= entry_lo.D;
+flags.V <= entry_lo.V;
+
+entry_lo_out <= entry_lo;
+entry_hi_out <= entry_hi;
+
+hit <= tlb_hit;
+
+entry_lo_write:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ entry_lo.N <= '0';
+ entry_lo.D <= '0';
+ entry_lo.V <= '0';
+ entry_lo.G <= '0';
+ entry_lo.PFN <= (others => '0');
+ elsif entry_we = '1' then
+ entry_lo <= entry_lo_in;
+ end if;
+ end if;
+ end process;
+
+entry_hi_write:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ entry_hi.VPN <= (others => '0');
+ entry_hi.ASID <= (others => '0');
+ elsif entry_we = '1' then
+ entry_hi <= entry_hi_in;
+ end if;
+ end if;
+ end process;
+
+------------------------------------------------------------------
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_with_cam.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_with_cam.vhd
new file mode 100644
index 0000000..7477e34
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_with_cam.vhd
@@ -0,0 +1,350 @@
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+ENTITY tlb IS
+ Generic
+ (
+ NUM_ENTRIES : natural := 8;
+ CACHE_KSEG1 : boolean := false;
+ TRANSLATE_KSEG0_1 : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+
+ rdy : out STD_LOGIC;
+
+ ctrl_in : in tlb_ctrl_in_t;
+ ctrl_out : out tlb_ctrl_out_t;
+
+ query_in : in tlb_query_in_t;
+ query_out : out tlb_query_out_t
+
+ );
+END tlb;
+
+ARCHITECTURE behavior OF tlb IS
+
+ signal clk_rd : STD_LOGIC;
+ signal blk_hit : unsigned(NUM_ENTRIES-1 downto 0);
+ signal blk_entry_lo : tlb_entry_lo_t;
+
+ constant C_ENTRY_LO_DEFAULT : tlb_entry_lo_t :=
+ (
+ N => '0', D => '0', V => '1', G => '0', PFN => (others => '0')
+ );
+
+ signal kseg1_force_cached : STD_LOGIC;
+ signal kseg_0_1_pfn : unsigned (31 downto lg2(TLB_PAGE_SIZE));
+ signal hit_umc : STD_LOGIC;
+ signal hit_umuc : STD_LOGIC;
+ signal entry_lo_res : tlb_entry_lo_t;
+ signal qry_res : tlb_query_out_t;
+ signal stat_res : tlb_status_t;
+
+ signal pa : word_t;
+ signal hit : STD_LOGIC;
+ signal valid : STD_LOGIC;
+
+ signal cam_rdy : STD_LOGIC;
+ signal cam_hit_vld : STD_LOGIC;
+
+ signal vaddr_reg : word_t;
+
+ subtype reg_lo_t is unsigned(23 downto 0);
+ subtype reg_hi_t is unsigned(25 downto 0);
+
+ signal reg_ctrl_entry_lo_din : reg_lo_t;
+ signal reg_ctrl_entry_lo_dout : reg_lo_t;
+ signal reg_qry_entry_lo_dout : reg_lo_t;
+ signal reg_qry_entry_lo_addr : unsigned(lg2(NUM_ENTRIES)-1 downto 0);
+ signal reg_ctrl_entry_lo_addr : unsigned(lg2(NUM_ENTRIES)-1 downto 0);
+
+ signal reg_ctrl_entry_hi_din : reg_hi_t;
+ signal reg_ctrl_entry_hi_dout : reg_hi_t;
+
+ function to_entry_lo(x : reg_lo_t) return tlb_entry_lo_t is
+ variable result : tlb_entry_lo_t;
+ begin
+ result.PFN := x(23 downto 4);
+ result.N := x(3);
+ result.D := x(2);
+ result.V := x(1);
+ result.G := x(0);
+
+ return result;
+
+ end to_entry_lo;
+
+ function to_entry_hi(x : reg_hi_t) return tlb_entry_hi_t is
+ variable result : tlb_entry_hi_t;
+ begin
+ result.VPN := x(25 downto 6);
+ result.ASID := x(5 downto 0);
+
+ return result;
+
+ end to_entry_hi;
+
+ function to_reg_lo(x : tlb_entry_lo_t) return reg_lo_t is
+ variable result : reg_lo_t;
+ begin
+ result(23 downto 4) := x.PFN;
+ result(3) := x.N;
+ result(2) := x.D;
+ result(1) := x.V;
+ result(0) := x.G;
+
+ return result;
+
+ end to_reg_lo;
+
+ function to_reg_hi(x : tlb_entry_hi_t) return reg_hi_t is
+ variable result : reg_hi_t;
+ begin
+ result(25 downto 6) := x.VPN;
+ result(5 downto 0) := x.ASID;
+
+ return result;
+
+ end to_reg_hi;
+
+ signal hit_idx : integer;
+ function decode(x : unsigned; N : integer) return integer is
+ variable result : integer;
+ begin
+ result := 0;
+ for i in 0 to N-1 loop
+ if x(i) = '1' then
+ result := i;
+ end if;
+ end loop;
+
+ return result;
+
+ end decode;
+
+ function decode2(x : unsigned; N : integer) return unsigned is
+ variable result : unsigned (lg2(N)-1 downto 0);
+ begin
+ result := (others => '0');
+ for i in 0 to N-1 loop
+ result := result or ((lg2(N)-1 downto 0 => x(i)) and to_unsigned(i, lg2(N)));
+ end loop;
+
+ return result;
+
+ end decode2;
+
+begin
+ kseg1_force_cached <= '1' when CACHE_KSEG1 else '0';
+ kseg_0_1_pfn <= "000" & vaddr_reg(28 downto lg2(TLB_PAGE_SIZE)) when TRANSLATE_KSEG0_1 else vaddr_reg(31 downto lg2(TLB_PAGE_SIZE));
+
+ clk_rd <= clk;
+ rdy <= cam_rdy;
+
+ stat_res.exc_vld <= valid;
+ stat_res.exc_miss <= not hit;
+ stat_res.exc_dirty <= hit and qry_res.flags.D and query_in.write;
+ stat_res.write <= query_in.write;
+
+ qry_res.paddr <= pa;
+ qry_res.hit <= hit;
+ qry_res.flags.N <= entry_lo_res.N;
+ qry_res.flags.D <= entry_lo_res.D;
+ qry_res.flags.V <= entry_lo_res.V;
+ qry_res.exc <= stat_res.exc_miss or stat_res.exc_dirty;
+ qry_res.vld <= valid;
+ qry_res.idx <= (hit_umc or hit_umuc) & reg_qry_entry_lo_addr;
+
+ query_out <= qry_res;
+ ctrl_out.stat <= stat_res;
+
+ pa <= entry_lo_res.PFN & vaddr_reg(lg2(TLB_PAGE_SIZE)-1 downto 0);
+
+ hit_idx <= decode(blk_hit, NUM_ENTRIES);
+
+ blk_entry_lo <= to_entry_lo(to_mips_01(reg_qry_entry_lo_dout));
+-- reg_qry_entry_lo_addr <= to_unsigned(hit_idx, lg2(NUM_ENTRIES));
+ reg_qry_entry_lo_addr <= decode2(blk_hit, NUM_ENTRIES);
+ reg_ctrl_entry_lo_din <= to_reg_lo(ctrl_in.entry_lo);
+
+ ctrl_out.entry_hi <= to_entry_hi(to_mips_01(reg_ctrl_entry_hi_dout));
+ reg_ctrl_entry_hi_din <= to_reg_hi(ctrl_in.entry_hi);
+
+inst_reg_entry_lo: entity work.reg_dual
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => reg_lo_t'length
+ )
+ PORT MAP (
+ clk_w => clk,
+ we => ctrl_in.entry_we,
+ en => '1',
+ wptr => ctrl_in.entry_wr_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ din => reg_ctrl_entry_lo_din,
+ rptr_a => ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ rptr_b => reg_qry_entry_lo_addr,
+ dout_a => reg_ctrl_entry_lo_dout,
+ dout_b => reg_qry_entry_lo_dout
+ );
+
+inst_reg_entry_hi: entity work.dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => reg_hi_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ctrl_in.entry_re,
+ we_a => ctrl_in.entry_we,
+ addr_a => ctrl_in.entry_wr_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ addr_b => ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ din_a => reg_ctrl_entry_hi_din,
+ dout_b => reg_ctrl_entry_hi_dout
+ );
+
+inst_cam_va: entity work.cam
+ GENERIC MAP
+ (
+ NUM_ENTRIES => NUM_ENTRIES,
+ DATA_WIDTH => 20,
+ CAM_RAM_MAX_WIDTH => 15
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ clk_rd => clk_rd,
+ rdy => cam_rdy,
+
+ re => query_in.vld,
+ we => ctrl_in.entry_we,
+ vld => '1',
+ addr => ctrl_in.entry_wr_idx,
+ tag_wr => ctrl_in.entry_hi.VPN,
+
+ tag_rd => query_in.vaddr(31 downto lg2(TLB_PAGE_SIZE)),
+ hit => blk_hit(NUM_ENTRIES-1 downto 0),
+ hit_vld => cam_hit_vld
+
+ );
+
+proc_entry_lo_umc:
+ process(clk)
+ variable index : integer;
+ begin
+ if rising_edge(clk) then
+ if query_in.vld = '1' then
+ hit_umc <= '0';
+ if query_in.vaddr(31 downto 29) = "100" then -- 80000000 to 9FFFFFFF
+ hit_umc <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_entry_lo_umuc:
+ process(clk)
+ variable index : integer;
+ begin
+ if rising_edge(clk) then
+ if query_in.vld = '1' then
+ hit_umuc <= '0';
+ if query_in.vaddr(31 downto 29) = "101" then -- A0000000 to BFFFFFFF
+ hit_umuc <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+tlb_entry_lo_result_translate:
+if USE_TLB = true generate
+ tlb_entry_lo_result:
+ process(blk_entry_lo, hit_umc, hit_umuc, kseg_0_1_pfn, kseg1_force_cached)
+ begin
+ entry_lo_res <= blk_entry_lo;
+ if hit_umc = '1' or hit_umuc = '1' then
+ entry_lo_res.N <= hit_umuc and not kseg1_force_cached;
+ entry_lo_res <= C_ENTRY_LO_DEFAULT;
+ entry_lo_res.PFN <= kseg_0_1_pfn;
+ end if;
+
+ end process;
+end generate;
+
+tlb_entry_lo_result_notranslate:
+if USE_TLB = false generate
+ tlb_entry_lo_result:
+ process(blk_entry_lo, vaddr_reg, hit_umc, hit_umuc, kseg_0_1_pfn, kseg1_force_cached)
+ begin
+ entry_lo_res <= C_ENTRY_LO_DEFAULT;
+ entry_lo_res.PFN <= vaddr_reg(31 downto lg2(TLB_PAGE_SIZE));
+ if hit_umc = '1' or hit_umuc = '1' then
+ entry_lo_res.N <= hit_umuc and not kseg1_force_cached;
+ entry_lo_res <= C_ENTRY_LO_DEFAULT;
+ entry_lo_res.PFN <= kseg_0_1_pfn;
+ end if;
+ end process;
+end generate;
+
+tlb_hit_combine_translate:
+if USE_TLB = true generate
+ tlb_hit_combine:
+ process(blk_entry_lo, hit_umc, hit_umuc)
+ variable t_v : std_logic;
+ begin
+ t_v := blk_entry_lo.V;
+ t_v := t_v or hit_umc or hit_umuc;
+ hit <= t_v;
+
+ end process;
+end generate;
+
+tlb_hit_combine_notranslate:
+if USE_TLB = false generate
+ tlb_hit_combine:
+ process(blk_entry_lo, hit_umc, hit_umuc)
+ variable t_v : std_logic;
+ begin
+ t_v := hit_umc or hit_umuc;
+ hit <= t_v;
+
+ end process;
+end generate;
+
+registered_output:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if query_in.vld = '1' then
+ vaddr_reg <= query_in.vaddr;
+ end if;
+ valid <= query_in.vld;
+ if ce = '1' then
+ if ctrl_in.entry_re = '1' then
+
+ ctrl_out.entry_lo <= to_entry_lo(to_mips_01(reg_ctrl_entry_lo_dout));
+ ctrl_out.entry_vld <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+
+
+------------------------------------------------------------------
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_with_comp.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_with_comp.vhd
new file mode 100644
index 0000000..8cdadc3
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_tlb_with_comp.vhd
@@ -0,0 +1,343 @@
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+ENTITY tlb IS
+ Generic
+ (
+ NUM_ENTRIES : natural := 8;
+ CACHE_KSEG1 : boolean := false;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+
+ rdy : out STD_LOGIC;
+
+ ctrl_in : in tlb_ctrl_in_t;
+ ctrl_out : out tlb_ctrl_out_t;
+
+ query_in : in tlb_query_in_t;
+ query_out : out tlb_query_out_t
+
+ );
+END tlb;
+
+ARCHITECTURE behavior OF tlb IS
+
+ signal clk_rd : STD_LOGIC;
+ signal blk_hit : unsigned(NUM_ENTRIES-1 downto 0);
+ signal blk_entry_lo : tlb_entry_lo_t;
+
+
+ signal entry_lo_UMC : tlb_entry_lo_t;
+ signal entry_lo_UMUC : tlb_entry_lo_t;
+ signal entry_lo_res : tlb_entry_lo_t;
+
+ signal qry_res : tlb_query_out_t;
+ signal stat_res : tlb_status_t;
+
+ signal pa : word_t;
+ signal hit : STD_LOGIC;
+ signal valid : STD_LOGIC;
+
+ signal cam_rdy : STD_LOGIC;
+ signal cam_hit_vld : STD_LOGIC;
+
+ signal vaddr_reg : word_t;
+
+ subtype reg_lo_t is unsigned(23 downto 0);
+ subtype reg_hi_t is unsigned(25 downto 0);
+
+ signal reg_lo_din : reg_lo_t;
+ signal reg_lo_dout_a : reg_lo_t;
+ signal reg_lo_dout_b : reg_lo_t;
+ signal reg_lo_addr_b : unsigned(lg2(NUM_ENTRIES)-1 downto 0);
+
+ signal reg_hi_din : reg_hi_t;
+ signal reg_hi_dout_b : reg_hi_t;
+
+ function to_entry_lo(x : reg_lo_t) return tlb_entry_lo_t is
+ variable result : tlb_entry_lo_t;
+ begin
+ result.PFN := x(23 downto 4);
+ result.N := x(3);
+ result.D := x(2);
+ result.V := x(1);
+ result.G := x(0);
+
+ return result;
+
+ end to_entry_lo;
+
+ function to_entry_hi(x : reg_hi_t) return tlb_entry_hi_t is
+ variable result : tlb_entry_hi_t;
+ begin
+ result.VPN := x(25 downto 6);
+ result.ASID := x(5 downto 0);
+
+ return result;
+
+ end to_entry_hi;
+
+ function to_reg_lo(x : tlb_entry_lo_t) return reg_lo_t is
+ variable result : reg_lo_t;
+ begin
+ result(23 downto 4) := x.PFN;
+ result(3) := x.N;
+ result(2) := x.D;
+ result(1) := x.V;
+ result(0) := x.G;
+
+ return result;
+
+ end to_reg_lo;
+
+ function to_reg_hi(x : tlb_entry_hi_t) return reg_hi_t is
+ variable result : reg_hi_t;
+ begin
+ result(25 downto 6) := x.VPN;
+ result(5 downto 0) := x.ASID;
+
+ return result;
+
+ end to_reg_hi;
+
+ signal hit_idx : integer;
+ function decode(x : unsigned; N : integer) return integer is
+ variable result : integer;
+ begin
+ result := 0;
+ for i in 0 to N-1 loop
+ if x(i) = '1' then
+ result := i;
+ end if;
+ end loop;
+
+ return result;
+
+ end decode;
+
+begin
+ clk_rd <= clk;
+ rdy <= cam_rdy;
+
+ stat_res.exc_vld <= valid;
+ stat_res.exc_miss <= not hit;
+ stat_res.exc_dirty <= hit and qry_res.flags.D and query_in.write;
+ stat_res.write <= query_in.write;
+
+ qry_res.paddr <= pa;
+ qry_res.hit <= hit;
+ qry_res.flags.N <= entry_lo_res.N;
+ qry_res.flags.D <= entry_lo_res.D;
+ qry_res.flags.V <= entry_lo_res.V;
+ qry_res.exc <= stat_res.exc_miss or stat_res.exc_dirty;
+ qry_res.vld <= valid;
+
+ query_out <= qry_res;
+ ctrl_out.stat <= stat_res;
+
+ pa <= entry_lo_res.PFN & vaddr_reg(lg2(TLB_PAGE_SIZE)-1 downto 0);
+
+ hit_idx <= decode(blk_hit, NUM_ENTRIES);
+
+ blk_entry_lo <= to_entry_lo(to_mips_01(reg_lo_dout_b));
+ reg_lo_addr_b <= to_unsigned(hit_idx, lg2(NUM_ENTRIES));
+ reg_lo_din <= to_reg_lo(ctrl_in.entry_lo);
+
+ ctrl_out.entry_hi <= to_entry_hi(to_mips_01(reg_hi_dout_b));
+ reg_hi_din <= to_reg_hi(ctrl_in.entry_hi);
+
+inst_reg_entry_lo: entity work.reg_dual
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => 24
+ )
+ PORT MAP (
+ clk_w => clk,
+ we => ctrl_in.entry_we,
+ en => '1',
+ wptr => ctrl_in.entry_wr_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ din => reg_lo_din,
+ rptr_a => ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ rptr_b => reg_lo_addr_b,
+ dout_a => reg_lo_dout_a,
+ dout_b => reg_lo_dout_b
+ );
+
+inst_reg_entry_hi: entity work.dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(NUM_ENTRIES),
+ data_width => 26
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ctrl_in.entry_re,
+ we_a => ctrl_in.entry_we,
+ addr_a => ctrl_in.entry_wr_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ addr_b => ctrl_in.entry_rd_idx(lg2(NUM_ENTRIES)-1 downto 0),
+ din_a => reg_hi_din,
+ dout_b => reg_hi_dout_b
+ );
+
+inst_cam_va: entity work.cam
+ GENERIC MAP
+ (
+ NUM_ENTRIES => NUM_ENTRIES,
+ DATA_WIDTH => 20,
+ CAM_RAM_MAX_WIDTH => 15
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ clk_rd => clk_rd,
+ rdy => cam_rdy,
+
+ re => query_in.vld,
+ we => ctrl_in.entry_we,
+ vld => '1',
+ addr => ctrl_in.entry_wr_idx,
+ tag_wr => ctrl_in.entry_hi.VPN,
+
+ tag_rd => query_in.vaddr(31 downto lg2(TLB_PAGE_SIZE)),
+ hit => blk_hit(NUM_ENTRIES-1 downto 0),
+ hit_vld => cam_hit_vld
+
+ );
+
+proc_entry_lo_umc:
+ process(clk)
+ variable index : integer;
+ begin
+ if rising_edge(clk) then
+ entry_lo_UMC.N <= '0';
+ entry_lo_UMC.D <= '0';
+ entry_lo_UMC.G <= '0';
+ if query_in.vld = '1' then
+ entry_lo_UMC.V <= '0';
+ if query_in.vaddr(31 downto 29) = "100" then -- 80000000 to 9FFFFFFF
+ entry_lo_UMC.V <= '1';
+ entry_lo_UMC.PFN <= "000" & query_in.vaddr(28 downto lg2(TLB_PAGE_SIZE));
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_entry_lo_umuc:
+ process(clk)
+ variable index : integer;
+ begin
+ if rising_edge(clk) then
+ if CACHE_KSEG1 then
+ entry_lo_UMUC.N <= '0';
+ else
+ entry_lo_UMUC.N <= '1';
+ end if;
+ entry_lo_UMUC.D <= '0';
+ entry_lo_UMUC.G <= '0';
+ if query_in.vld = '1' then
+ entry_lo_UMUC.V <= '0';
+ if query_in.vaddr(31 downto 29) = "101" then -- A0000000 to BFFFFFFF
+ entry_lo_UMUC.V <= '1';
+ entry_lo_UMUC.PFN <= "000" & query_in.vaddr(28 downto lg2(TLB_PAGE_SIZE));
+ end if;
+ end if;
+ end if;
+ end process;
+
+tlb_entry_lo_result_translate:
+if USE_TLB = true generate
+ tlb_entry_lo_result:
+ process(blk_entry_lo, entry_lo_umc, entry_lo_umuc)
+ begin
+ entry_lo_res <= blk_entry_lo;
+ if entry_lo_umc.V = '1' then
+ entry_lo_res <= entry_lo_umc;
+ end if;
+ if entry_lo_umuc.V = '1' then
+ entry_lo_res <= entry_lo_umuc;
+ end if;
+
+ end process;
+end generate;
+
+tlb_entry_lo_result_notranslate:
+if USE_TLB = false generate
+ tlb_entry_lo_result:
+ process(blk_entry_lo, vaddr_reg, entry_lo_umc, entry_lo_umuc)
+ begin
+ entry_lo_res.N <= '0';
+ entry_lo_res.D <= '0';
+ entry_lo_res.V <= '1';
+ entry_lo_res.PFN <= vaddr_reg(31 downto lg2(TLB_PAGE_SIZE));
+ if entry_lo_umc.V = '1' then
+ entry_lo_res <= entry_lo_umc;
+ end if;
+ if entry_lo_umuc.V = '1' then
+ entry_lo_res <= entry_lo_umuc;
+ end if;
+
+ end process;
+end generate;
+
+tlb_hit_combine_translate:
+if USE_TLB = true generate
+ tlb_hit_combine:
+ process(blk_entry_lo, entry_lo_umc, entry_lo_umuc)
+ variable t_v : std_logic;
+ begin
+ t_v := blk_entry_lo.V;
+ t_v := t_v or entry_lo_umc.V or entry_lo_umuc.V;
+ hit <= t_v;
+
+ end process;
+end generate;
+
+tlb_hit_combine_notranslate:
+if USE_TLB = false generate
+ tlb_hit_combine:
+ process(blk_entry_lo, entry_lo_umc, entry_lo_umuc)
+ variable t_v : std_logic;
+ begin
+ t_v := entry_lo_umc.V or entry_lo_umuc.V;
+ hit <= t_v;
+
+ end process;
+end generate;
+
+registered_output:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if query_in.vld = '1' then
+ vaddr_reg <= query_in.vaddr;
+ end if;
+ valid <= query_in.vld;
+ if ce = '1' then
+ if ctrl_in.entry_re = '1' then
+
+ ctrl_out.entry_lo <= to_entry_lo(to_mips_01(reg_lo_dout_a));
+ ctrl_out.entry_vld <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+
+
+------------------------------------------------------------------
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_top.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_top.vhd
new file mode 100644
index 0000000..984f6a4
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_top.vhd
@@ -0,0 +1,396 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.numeric_std.ALL;
+
+library work;
+use work.mips_types.all;
+
+entity mips_top is
+ Generic
+ (
+ icache_size : natural := 8192; -- words
+ icache_line : natural := 8; -- words
+ dcache_size : natural := 4096; -- words
+ dcache_line : natural := 8; -- words
+ WITH_TLB : boolean := true
+ );
+ Port
+ (
+ debug : out chip_debug_t;
+ eb : in STD_LOGIC;
+ nmi : in STD_LOGIC;
+ cpu_clk : in STD_LOGIC;
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ ADDR_O : out unsigned(31 downto 0);
+ DAT_I : in unsigned(31 downto 0);
+ DAT_O : out unsigned(31 downto 0);
+ WE_O : out STD_LOGIC;
+ SEL_O : out unsigned(3 downto 0);
+ CYC_O : out STD_LOGIC;
+ STB_O : out STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+ INT : in unsigned (5 downto 0)
+ );
+
+end mips_top;
+
+architecture rtl of mips_top is
+
+--------------------------------------------------------------------------
+-- Pipeline
+--------------------------------------------------------------------------
+ COMPONENT pipeline is
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+ imem_err : in STD_LOGIC;
+ imem_rdy : in STD_LOGIC;
+ imem_en : out STD_LOGIC;
+ imem_addr : out word_t;
+ imem_data : in word_t;
+ dmem_err : in STD_LOGIC;
+ dmem_rdy : in STD_LOGIC;
+ dmem_en : out STD_LOGIC;
+ dmem_we : out STD_LOGIC;
+ dmem_be : out unsigned(3 downto 0);
+ dmem_addr : out word_t;
+ dmem_din : in word_t;
+ dmem_dout : out word_t;
+ cop_ir : out word_t;
+ cop_ir_en : out STD_LOGIC;
+ cop_din : in word_t;
+ cop_dout : out word_t;
+ ctrl_out : out pipe_ctrl_out_t;
+ ctrl_in : in pipe_ctrl_in_t
+ );
+ END COMPONENT;
+ signal imem_err : std_logic;
+ signal imem_rdy : std_logic;
+ signal imem_en : std_logic;
+ signal imem_addr : word_t;
+ signal imem_din : word_t;
+ signal dmem_err : std_logic;
+ signal dmem_rdy : std_logic;
+ signal dmem_en : std_logic;
+ signal dmem_we : std_logic;
+ signal dmem_addr : word_t;
+ signal dmem_dout : word_t;
+ signal dmem_din : word_t;
+ signal dmem_be : unsigned(3 downto 0);
+
+ signal biu_busy : STD_LOGIC;
+ signal biu_rst : STD_LOGIC;
+ signal cpu_rst : STD_LOGIC;
+ signal cpu_run : STD_LOGIC;
+
+ signal pipe_cop_ir : word_t;
+ signal pipe_cop_ir_en : STD_LOGIC;
+ signal pipe_cop_din : word_t;
+ signal pipe_cop_dout : word_t;
+ signal pipe_ctrl_in : pipe_ctrl_in_t;
+ signal pipe_ctrl_out : pipe_ctrl_out_t;
+
+ signal cop0_ctrl_in : cop0_ctrl_in_t;
+ signal cop0_ctrl_out : cop0_ctrl_out_t;
+
+ signal biu_ctrl_in : biu_ctrl_in_t;
+ signal biu_ctrl_out : biu_ctrl_out_t;
+
+--------------------------------------------------------------------------
+-- Coprocessor
+--------------------------------------------------------------------------
+ COMPONENT cop is
+ GENERIC
+ (
+ icache_size : natural;
+ icache_line : natural;
+ dcache_size : natural;
+ dcache_line : natural
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ nmi : in STD_LOGIC;
+ eb : in STD_LOGIC;
+ int : in unsigned (5 downto 0);
+ ir_en : in STD_LOGIC;
+ ir : in word_t;
+ ctrl_in : in cop0_ctrl_in_t;
+ ctrl_out : out cop0_ctrl_out_t;
+ din : in word_t;
+ dout : out word_t
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+-- Bus Interface Unit
+--------------------------------------------------------------------------
+ COMPONENT biu
+ GENERIC
+ (
+ icache_size : natural;
+ icache_line : natural;
+ dcache_size : natural;
+ dcache_line : natural;
+ WRITE_FIFO_SIZE : natural;
+ WITH_TLB : boolean
+ );
+ PORT
+ (
+ clk : in STD_LOGIC;
+ busy : out STD_LOGIC;
+
+ imem_err : out STD_LOGIC;
+ imem_rdy : out STD_LOGIC;
+ imem_en : in STD_LOGIC;
+ imem_addr : in word_t;
+ imem_dout : out word_t;
+ dmem_err : out STD_LOGIC;
+ dmem_rdy : out STD_LOGIC;
+ dmem_en : in STD_LOGIC;
+ dmem_we : in STD_LOGIC;
+ dmem_be : in unsigned(3 downto 0);
+ dmem_din : in word_t;
+ dmem_dout : out word_t;
+ dmem_addr : in word_t;
+
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ ADDR_O : out unsigned(31 downto 0);
+ MDAT_I : in unsigned(31 downto 0);
+ MDAT_O : out unsigned(31 downto 0);
+ WE_O : out STD_LOGIC;
+ SEL_O : out unsigned(3 downto 0);
+ CYC_O : out STD_LOGIC;
+ STB_O : out STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+
+ ctrl_in : in biu_ctrl_in_t;
+ ctrl_out : out biu_ctrl_out_t
+
+ );
+ END COMPONENT;
+
+begin
+
+-------------------------------------------------------------------
+ process(cpu_clk)
+ variable reset_delay : unsigned (31 downto 0);
+ begin
+ if rising_edge(cpu_clk) then
+ if RST_I = '1' then
+ reset_delay := (others => '0');
+ biu_rst <= '1';
+ cpu_rst <= '1';
+ cpu_run <= '0';
+ else
+ reset_delay := reset_delay(reset_delay'left-1 downto 0) & '1';
+ if reset_delay(20) = '1' then
+ biu_rst <= '0';
+ end if;
+ if reset_delay(31) = '1' then
+ cpu_rst <= '0';
+ end if;
+ if reset_delay(16) = '1' and biu_busy = '0' then
+ cpu_run <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+inst_pipeline: pipeline
+ PORT MAP
+ (
+ rst => cpu_rst,
+ clk => cpu_clk,
+ ce => cpu_run,
+ imem_err => imem_err,
+ imem_rdy => imem_rdy,
+ imem_en => imem_en,
+ imem_addr => imem_addr,
+ imem_data => imem_din,
+ dmem_err => dmem_err,
+ dmem_rdy => dmem_rdy,
+ dmem_en => dmem_en,
+ dmem_we => dmem_we,
+ dmem_be => dmem_be,
+ dmem_addr => dmem_addr,
+ dmem_din => dmem_din,
+ dmem_dout => dmem_dout,
+ cop_ir => pipe_cop_ir,
+ cop_ir_en => pipe_cop_ir_en,
+ cop_din => pipe_cop_din,
+ cop_dout => pipe_cop_dout,
+ ctrl_out => pipe_ctrl_out,
+ ctrl_in => pipe_ctrl_in
+ );
+
+ pipe_ctrl_in <= cop0_ctrl_out.pipe;
+
+inst_cop: cop
+ GENERIC MAP
+ (
+ icache_size => icache_size, -- words
+ icache_line => icache_line, -- words
+ dcache_size => dcache_size, -- words
+ dcache_line => dcache_line -- words
+ )
+ PORT MAP
+ (
+ rst => cpu_rst,
+ clk => cpu_clk,
+ nmi => nmi,
+ eb => eb,
+ int => INT,
+ ir_en => pipe_cop_ir_en,
+ ir => pipe_cop_ir,
+ ctrl_in => cop0_ctrl_in,
+ ctrl_out => cop0_ctrl_out,
+ dout => pipe_cop_din,
+ din => pipe_cop_dout
+ );
+
+ cop0_ctrl_in.pipe <= pipe_ctrl_out;
+ cop0_ctrl_in.itlb <= biu_ctrl_out.itlb;
+ cop0_ctrl_in.dtlb <= biu_ctrl_out.dtlb;
+
+inst_biu: biu
+ GENERIC MAP
+ (
+ icache_size => icache_size, -- words
+ icache_line => icache_line, -- words
+ dcache_size => dcache_size, -- words
+ dcache_line => dcache_line, -- words
+ WRITE_FIFO_SIZE => 4,
+ WITH_TLB => WITH_TLB
+ )
+ PORT MAP
+ (
+
+ clk => cpu_clk,
+ busy => biu_busy,
+
+ imem_err => imem_err,
+ imem_rdy => imem_rdy,
+ imem_en => imem_en,
+ imem_addr => imem_addr,
+ imem_dout => imem_din,
+ dmem_err => dmem_err,
+ dmem_rdy => dmem_rdy,
+ dmem_en => dmem_en,
+ dmem_we => dmem_we,
+ dmem_be => dmem_be,
+ dmem_addr => dmem_addr,
+ dmem_din => dmem_dout,
+ dmem_dout => dmem_din,
+
+ RST_I => biu_rst,
+ CLK_I => CLK_I,
+ ACK_I => ACK_I,
+ SRDY_I => SRDY_I,
+ ADDR_O => ADDR_O,
+ MDAT_I => DAT_I,
+ MDAT_O => DAT_O,
+ WE_O => WE_O,
+ SEL_O => SEL_O,
+ CYC_O => CYC_O,
+ STB_O => STB_O,
+ MRDY_O => MRDY_O,
+
+ ctrl_in => biu_ctrl_in,
+ ctrl_out => biu_ctrl_out
+
+ );
+
+ biu_ctrl_in.dcache <= cop0_ctrl_out.dcache;
+ biu_ctrl_in.icache <= cop0_ctrl_out.icache;
+ biu_ctrl_in.dtlb <= cop0_ctrl_out.dtlb;
+ biu_ctrl_in.itlb <= cop0_ctrl_out.itlb;
+
+-------------------------------------------
+-- debug
+-------------------------------------------
+ debug.imem_err <= imem_err;
+ debug.dmem_err <= dmem_err;
+
+debug_imem_din_register:
+ process(cpu_clk)
+ variable en_r: std_logic;
+ variable addr_r: word_t;
+ begin
+ if rising_edge(cpu_clk) then
+ debug.imem_din_vld <= '0';
+ if imem_rdy = '1' then
+ if en_r = '1' then
+ debug.imem_addr_reg <= addr_r;
+ debug.imem_din_reg <= imem_din;
+ debug.imem_din_vld <= '1';
+ end if;
+ if imem_en = '1' then
+ addr_r := imem_addr;
+ end if;
+ en_r := imem_en;
+ end if;
+ end if;
+ end process;
+
+debug_dmem_din_register:
+ process(cpu_clk)
+ variable en_r: std_logic;
+ variable we_r: std_logic;
+ variable addr_r: word_t;
+ variable dout_r: word_t;
+ begin
+ if rising_edge(cpu_clk) then
+ debug.dmem_din_vld <= '0';
+ debug.dmem_dout_vld <= '0';
+ if dmem_rdy = '1' then
+ if en_r = '1' then
+ debug.dmem_addr_reg <= addr_r;
+ debug.dmem_din_reg <= dmem_din;
+ debug.dmem_din_vld <= not we_r;
+ debug.dmem_dout_reg <= dout_r;
+ debug.dmem_dout_vld <= we_r;
+ end if;
+ if dmem_en = '1' then
+ dout_r := dmem_dout;
+ addr_r := dmem_addr;
+ end if;
+ en_r := dmem_en;
+ we_r := dmem_we;
+ end if;
+ end if;
+ end process;
+
+end rtl;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_types.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_types.vhd
new file mode 100644
index 0000000..f14ab8a
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_types.vhd
@@ -0,0 +1,807 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: Types, constants and functions for JIPS
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+
+--------------------------------------------------------------------------
+package mips_types is
+
+ -- Revision of the CPU
+ constant REVISION : integer := 13;
+ constant WORD_WIDTH : integer := 32;
+ constant TLB_PAGE_SIZE : positive := 4096;
+ constant TLB_NUM_ASIDS : positive := 64;
+ constant TLB_NUM_ENTRIES : positive := 32;
+
+ --Types
+ subtype instr_name_t is string(1 to 12);
+ type instr_name_array_t is array (0 to 63) of instr_name_t;
+ subtype opcode_t is unsigned (5 downto 0);
+ subtype word_t is unsigned (WORD_WIDTH-1 downto 0);
+ subtype reg_ptr_t is unsigned (4 downto 0);
+ subtype shamt_t is unsigned(4 downto 0);
+ subtype sa_t is natural range 0 to 63;
+ subtype func_t is unsigned(5 downto 0);
+
+ type chip_debug_t is record
+ imem_err : std_logic;
+ imem_addr_reg : word_t;
+ imem_din_reg : word_t;
+ imem_din_vld : std_logic;
+ dmem_err : std_logic;
+ dmem_addr_reg : word_t;
+ dmem_din_reg : word_t;
+ dmem_din_vld : std_logic;
+ dmem_dout_reg : word_t;
+ dmem_dout_vld : std_logic;
+ end record;
+
+ type op_t is
+ (
+ op_illegal,
+ op_nop,
+ op_sll,
+ op_srl,
+ op_sra,
+ op_sllv,
+ op_srlv,
+ op_srav,
+ op_jr,
+ op_jalr,
+ op_syscall,
+ op_break,
+ op_mfhi,
+ op_mthi,
+ op_mflo,
+ op_mtlo,
+ op_mult,
+ op_multu,
+ op_div,
+ op_divu,
+ op_add,
+ op_addu,
+ op_sub,
+ op_subu,
+ op_and,
+ op_or,
+ op_xor,
+ op_nor,
+ op_slt,
+ op_sltu,
+ op_bltz,
+ op_bgez,
+ op_bltzal,
+ op_bgezal,
+ op_j,
+ op_jal,
+ op_beq,
+ op_bne,
+ op_blez,
+ op_bgtz,
+ op_addi,
+ op_addiu,
+ op_slti,
+ op_sltiu,
+ op_andi,
+ op_ori,
+ op_xori,
+ op_lui,
+ op_lb,
+ op_lh,
+ op_lwl,
+ op_lw,
+ op_lbu,
+ op_lhu,
+ op_lwr,
+ op_sb,
+ op_sh,
+ op_swl,
+ op_sw,
+ op_swr,
+ op_cop0,
+ op_cop1,
+ op_cop2,
+ op_cop3,
+ op_mfc0,
+ op_cfc0,
+ op_mtc0,
+ op_ctc0,
+ op_bcf0,
+ op_bct0,
+ op_mfc1,
+ op_cfc1,
+ op_mtc1,
+ op_ctc1,
+ op_bcf1,
+ op_bct1,
+ op_mfc2,
+ op_cfc2,
+ op_mtc2,
+ op_ctc2,
+ op_bcf2,
+ op_bct2,
+ op_mfc3,
+ op_cfc3,
+ op_mtc3,
+ op_ctc3,
+ op_bcf3,
+ op_bct3,
+ op_lwc0,
+ op_lwc1,
+ op_lwc2,
+ op_lwc3,
+ op_swc0,
+ op_swc1,
+ op_swc2,
+ op_swc3
+ );
+
+ attribute ENUM_ENCODING : string;
+
+ type imm_src_t is (src_imm32, src_imm16, src_imm16_high);
+ type sa_src_t is (sa_src_reg, sa_src_imm);
+ type alu_src1_t is (alu_src_reg);
+ type alu_src2_t is (alu_src_reg, alu_src_imm);
+ type bc_src_t is (bc_eq_ne, bc_lez_gtz, bc_ltz_gez);
+ type shift_opsel_t is (shift_sll, shift_srl, shift_sra);
+ type wptr_src_t is (wptr_src_imm, wptr_src_const);
+
+ type pc_t is record
+ curr : word_t;
+ last : word_t;
+ nxt : word_t;
+ pc_branch : word_t;
+ branch_take : std_logic;
+ end record;
+
+ type alu_outsel_t is
+ (
+ alu_adder,
+ alu_shift2,
+ alu_and,
+ alu_or,
+ alu_xor,
+ alu_nor,
+ alu_ltu,
+ alu_lts
+ );
+
+ type sdu_t is record
+ imem_dep : STD_LOGIC;
+ dmem_dep : STD_LOGIC;
+ mul_dep : STD_LOGIC;
+ ID_nop : STD_LOGIC;
+ EX_nop : STD_LOGIC;
+ MEM_nop : STD_LOGIC;
+ WB_nop : STD_LOGIC;
+ ID_stall : STD_LOGIC;
+ EX_stall : STD_LOGIC;
+ MEM_stall : STD_LOGIC;
+ WB_stall : STD_LOGIC;
+ stall_all : STD_LOGIC;
+ end record;
+
+ type hdu_t is record
+ alu_fwd_a_ex : boolean;
+ alu_fwd_a_mem : boolean;
+ alu_fwd_a_wb : boolean;
+ alu_fwd_b_ex : boolean;
+ alu_fwd_b_mem : boolean;
+ alu_fwd_b_wb : boolean;
+ end record;
+
+ type alu_flags_t is record
+ c : STD_LOGIC;
+ uvf : STD_LOGIC;
+ ovf : STD_LOGIC;
+ ltu : STD_LOGIC;
+ lts : STD_LOGIC;
+ end record;
+
+ type bcu_flags_t is record
+ eq : STD_LOGIC;
+ ltz : STD_LOGIC;
+ end record;
+
+ type event_t is record
+ NMI : STD_LOGIC;
+ Int : STD_LOGIC;
+ data_load_err : STD_LOGIC;
+ data_store_err : STD_LOGIC;
+ inst_load_err : STD_LOGIC;
+ inst_priv_addr : STD_LOGIC;
+ alu_ovf : STD_LOGIC;
+ alu_uvf : STD_LOGIC;
+ syscall : STD_LOGIC;
+ break : STD_LOGIC;
+ illegal : STD_LOGIC;
+ ITLB_MOD : STD_LOGIC;
+ ITLB_LOAD : STD_LOGIC;
+ ITLB_STORE : STD_LOGIC;
+ DTLB_MOD : STD_LOGIC;
+ DTLB_LOAD : STD_LOGIC;
+ DTLB_STORE : STD_LOGIC;
+ end record;
+
+ type exc_flags_t is record
+ Int : STD_LOGIC;
+ DAdEL : STD_LOGIC;
+ DAdES : STD_LOGIC;
+ IAdEL : STD_LOGIC;
+ IAdEK : STD_LOGIC;
+ Ov : STD_LOGIC;
+ Sys : STD_LOGIC;
+ Bp : STD_LOGIC;
+ RI : STD_LOGIC;
+ ITLB_MOD : STD_LOGIC;
+ ITLB_LOAD : STD_LOGIC;
+ ITLB_STORE : STD_LOGIC;
+ DTLB_MOD : STD_LOGIC;
+ DTLB_LOAD : STD_LOGIC;
+ DTLB_STORE : STD_LOGIC;
+ IBE : STD_LOGIC;
+ DBE : STD_LOGIC;
+ end record;
+
+ type except_t is record
+ act : STD_LOGIC;
+ epc : word_t;
+ cause : word_t;
+ end record;
+
+ type cache_ctrl_t is record
+ inv_addr : word_t;
+ inv_at : STD_LOGIC;
+ inv_all : STD_LOGIC;
+ end record;
+
+ type tlb_flags_t is record
+ N : std_logic;
+ D : std_logic;
+ V : std_logic;
+ end record;
+
+ type tlb_entry_lo_t is record
+ PFN : unsigned (31 downto lg2(TLB_PAGE_SIZE));
+ G : std_logic;
+ N : std_logic;
+ D : std_logic;
+ V : std_logic;
+ end record;
+
+ type tlb_entry_hi_t is record
+ VPN : unsigned (31 downto lg2(TLB_PAGE_SIZE));
+ ASID : unsigned (lg2(TLB_NUM_ASIDS)-1 downto 0);
+ end record;
+
+ type tlb_query_in_t is record
+ vld : std_logic;
+ write : std_logic;
+ vaddr : word_t;
+ idx : unsigned (lg2(TLB_NUM_ENTRIES) downto 0);
+ end record;
+
+ type tlb_query_out_t is record
+ vld : std_logic;
+ exc : STD_LOGIC;
+ hit : STD_LOGIC;
+ paddr : word_t;
+ flags : tlb_flags_t;
+ idx : unsigned (lg2(TLB_NUM_ENTRIES) downto 0);
+ end record;
+
+ type tlb_status_t is record
+ exc_vld : std_logic;
+ exc_miss : std_logic;
+ exc_dirty : std_logic;
+ write : std_logic;
+ end record;
+
+ type tlb_ctrl_in_t is record
+ entry_we : STD_LOGIC;
+ entry_re : STD_LOGIC;
+ entry_rd_idx : unsigned (lg2(TLB_NUM_ENTRIES)-1 downto 0);
+ entry_wr_idx : unsigned (lg2(TLB_NUM_ENTRIES)-1 downto 0);
+ entry_lo : tlb_entry_lo_t;
+ entry_hi : tlb_entry_hi_t;
+ end record;
+
+ type tlb_ctrl_out_t is record
+ entry_vld : std_logic;
+ entry_lo : tlb_entry_lo_t;
+ entry_hi : tlb_entry_hi_t;
+ entry_prb_idx : unsigned (lg2(TLB_NUM_ENTRIES)-1 downto 0);
+ stat : tlb_status_t;
+ end record;
+
+ type biu_ctrl_in_t is record
+ itlb : tlb_ctrl_in_t;
+ dtlb : tlb_ctrl_in_t;
+ icache : cache_ctrl_t;
+ dcache : cache_ctrl_t;
+ dtlb_va : word_t;
+ dtlb_en : STD_LOGIC;
+ end record;
+
+ type biu_ctrl_out_t is record
+ itlb : tlb_ctrl_out_t;
+ dtlb : tlb_ctrl_out_t;
+ end record;
+
+ type pipe_ctrl_in_t is record
+ EB : STD_LOGIC;
+ exc_inject : STD_LOGIC;
+ exc_commit : STD_LOGIC;
+ exc_pending : STD_LOGIC;
+ exc_exit : STD_LOGIC;
+ user_mode : STD_LOGIC;
+ NMI : STD_LOGIC;
+ int : STD_LOGIC;
+ exc_vec : word_t;
+ ITLB : tlb_status_t;
+ DTLB : tlb_status_t;
+ end record;
+
+ type pipe_ctrl_out_t is record
+ sdu : sdu_t;
+ events : event_t;
+ bd_wb : STD_LOGIC;
+ epc_wb : word_t;
+ imem_addr : word_t;
+ dmem_addr : word_t;
+ exc_req : STD_LOGIC;
+ exc_ack : STD_LOGIC;
+ dtlb_va : word_t;
+ dtlb_en : STD_LOGIC;
+ end record;
+
+ type cop0_ctrl_in_t is record
+ pipe : pipe_ctrl_out_t;
+ itlb : tlb_ctrl_out_t;
+ dtlb : tlb_ctrl_out_t;
+ end record;
+
+ type cop0_ctrl_out_t is record
+ pipe : pipe_ctrl_in_t;
+ itlb : tlb_ctrl_in_t;
+ dtlb : tlb_ctrl_in_t;
+ icache : cache_ctrl_t;
+ dcache : cache_ctrl_t;
+ end record;
+
+ type alu_ctrl_t is record
+ outsel : alu_outsel_t;
+ add : STD_LOGIC;
+ shift_right : STD_LOGIC;
+ shift_arith : STD_LOGIC;
+ op1_src : alu_src1_t;
+ op2_src : alu_src2_t;
+ end record;
+
+ type shift_ctrl_t is record
+ shamt_nrm : shamt_t;
+ shamt_rnd : shamt_t;
+ shift_right : STD_LOGIC;
+ shift_arith : STD_LOGIC;
+ end record;
+
+ type ctrl_lines_t is record
+ branch : STD_LOGIC;
+ jump_long : STD_LOGIC;
+ jump : STD_LOGIC;
+ bc_not : STD_LOGIC;
+ bc_src : bc_src_t;
+ imm_src : imm_src_t;
+ alu : alu_ctrl_t;
+ reg_write : STD_LOGIC;
+ reg_link : STD_LOGIC;
+ dmem_we : STD_LOGIC;
+ dmem_en : STD_LOGIC;
+ shamt2_srcsel : sa_src_t;
+ wptr_srcsel : wptr_src_t;
+ cop_instr_en : STD_LOGIC;
+ cop_read : STD_LOGIC;
+ shift_offset : unsigned(1 downto 0);
+ shift_byp : STD_LOGIC;
+ byte_en_byp : STD_LOGIC;
+ sign_ext_byp : STD_LOGIC;
+ word4_en : STD_LOGIC;
+ word2_en : STD_LOGIC;
+ align_left : STD_LOGIC;
+ load_signed : STD_LOGIC;
+ mul_access : STD_LOGIC;
+ mul_hilo_we : STD_LOGIC;
+ mul_mul_divn : STD_LOGIC;
+ mul_start : STD_LOGIC;
+ mul_s_un : STD_LOGIC;
+ mul_hilo_sel : STD_LOGIC;
+ exc_break : STD_LOGIC;
+ exc_syscall : STD_LOGIC;
+ exc_illegal : STD_LOGIC;
+ except_en : STD_LOGIC;
+ alu_exc_en : STD_LOGIC;
+ end record;
+
+ type ID_t is record
+ nop : STD_LOGIC;
+ exc : std_logic;
+ op : op_t;
+ IR : word_t;
+ epc : word_t;
+ pcn : word_t;
+ jimm32 : word_t;
+ bimm18 : word_t;
+ imm : word_t;
+ shamt : shamt_t;
+ ctrl : ctrl_lines_t;
+ va : word_t;
+ reg_write : STD_LOGIC;
+ reg_a_rptr : reg_ptr_t;
+ reg_b_rptr : reg_ptr_t;
+ reg_a : word_t;
+ reg_b : word_t;
+ events : event_t;
+ end record;
+
+ type EX_t is record
+ nop : STD_LOGIC;
+ exc : std_logic;
+ op : op_t;
+ IR : word_t;
+ epc : word_t;
+ pcn : word_t;
+ reg_a : word_t;
+ reg_b : word_t;
+ ctrl : ctrl_lines_t;
+ shift_ctrl : shift_ctrl_t;
+ alu_op1 : word_t;
+ alu_op2 : word_t;
+ alu_op2_s : word_t;
+ alu_flags : alu_flags_t;
+ result : word_t;
+ reg_write : STD_LOGIC;
+ reg_we : STD_LOGIC;
+ reg_wptr : reg_ptr_t;
+ reg_a_rptr : reg_ptr_t;
+ reg_b_rptr : reg_ptr_t;
+ va : word_t;
+ pa_off : unsigned(1 downto 0);
+ events_in : event_t;
+ events : event_t;
+ end record;
+
+ type MEM_t is record
+ nop : STD_LOGIC;
+ exc : std_logic;
+ op : op_t;
+ epc : word_t;
+ pcn : word_t;
+ ctrl : ctrl_lines_t;
+ ex_result : word_t;
+ reg_wptr : reg_ptr_t;
+ reg_we : STD_LOGIC;
+ reg_data : word_t;
+ va : word_t;
+ pa_off : unsigned(1 downto 0);
+ events_in : event_t;
+ events : event_t;
+ end record;
+
+ type WB_t is record
+ nop : STD_LOGIC;
+ epc : word_t;
+ epc_last : word_t;
+ bd : STD_LOGIC;
+ exc : std_logic;
+ exc_last : std_logic;
+ events : event_t;
+ op : op_t;
+ reg_wptr : reg_ptr_t;
+ reg_we : STD_LOGIC;
+ reg_data : word_t;
+ va : word_t;
+ end record;
+
+
+ type rom_special_t is array (0 to 2**func_t'length-1) of ctrl_lines_t;
+ type rom_regimm_t is array (0 to 2**reg_ptr_t'length-1) of ctrl_lines_t;
+ type rom_opcode_t is array (0 to 2**opcode_t'length-1) of ctrl_lines_t;
+
+ function store_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t;
+ function store_be(va : unsigned(1 downto 0); be_src, word2_en, word4_en, align_left, bypass : std_logic) return unsigned;
+ function load_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t;
+ function load_be(va : unsigned(1 downto 0); align_left, bypass : std_logic) return unsigned;
+ function load_sign_ext(x : word_t; bypass, signed, word2_en, word4_en : std_logic) return word_t;
+ function events_clr return event_t;
+ function event_is_active(e : event_t) return std_logic;
+ function "or" (a, b : event_t) return event_t;
+ function "or" (a, b : tlb_flags_t) return tlb_flags_t;
+
+end mips_types;
+
+--------------------------------------------------------------------------
+package body mips_types is
+
+ function store_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t is
+ variable stage1 : word_t;
+ variable result : word_t;
+ variable sa : unsigned(1 downto 0);
+ begin
+
+ if bypass = '1' then
+ sa := "00";
+ else
+ sa := va + shift_off;
+ end if;
+
+ stage1 := x;
+ if sa(0) = '1' then
+ stage1 := x(23 downto 0) & x(31 downto 24);
+ end if;
+ result := stage1;
+ if sa(1) = '1' then
+ result := stage1(15 downto 0) & stage1(31 downto 16);
+ end if;
+
+ return result;
+ end store_shift;
+
+--------------------------------------------------------------------------
+ function store_be(va : unsigned(1 downto 0); be_src, word2_en, word4_en, align_left, bypass : std_logic) return unsigned is
+ variable result : unsigned(3 downto 0);
+ begin
+ result := (3 downto 0 => be_src);
+ if bypass = '0' then
+ if word2_en = '1' then
+ case va is
+ when "00" =>
+ result := "00" & be_src & be_src;
+ when "10" =>
+ result := be_src & be_src & "00";
+ when others => null;
+ end case;
+ elsif word4_en = '1' then
+ case va is
+ when "00" =>
+ result := "000" & be_src;
+ when "01" =>
+ result := "00" & be_src & '0';
+ when "10" =>
+ result := '0' & be_src & "00";
+ when "11" =>
+ result := be_src & "000";
+ when others => null;
+ end case;
+ elsif align_left = '1' then
+ case va is
+ when "00" =>
+ result := be_src & be_src & be_src & be_src;
+ when "01" =>
+ result := be_src & be_src & be_src & '0';
+ when "10" =>
+ result := be_src & be_src & "00";
+ when "11" =>
+ result := be_src & "000";
+ when others => null;
+ end case;
+ else
+ case va is
+ when "00" =>
+ result := "000" & be_src;
+ when "01" =>
+ result := "00" & be_src & be_src;
+ when "10" =>
+ result := '0' & be_src & be_src & be_src;
+ when "11" =>
+ result := be_src & be_src & be_src & be_src;
+ when others => null;
+ end case;
+ end if;
+ end if;
+
+ return result;
+
+ end store_be;
+
+--------------------------------------------------------------------------
+ function load_shift(x : word_t; va, shift_off : unsigned(1 downto 0); bypass : std_logic) return word_t is
+ variable stage1 : word_t;
+ variable result : word_t;
+ variable sa : unsigned(1 downto 0);
+
+ begin
+ if bypass = '1' then
+ sa := "00";
+ else
+ sa := va + shift_off;
+ end if;
+
+ stage1 := x;
+ if sa(0) = '1' then
+ stage1 := x(7 downto 0) & x(31 downto 8);
+ end if;
+ result := stage1;
+ if sa(1) = '1' then
+ result := stage1(15 downto 0) & stage1(31 downto 16);
+ end if;
+
+ return result;
+ end load_shift;
+
+--------------------------------------------------------------------------
+ function load_be(va : unsigned(1 downto 0); align_left, bypass : std_logic) return unsigned is
+ variable result : unsigned(3 downto 0);
+ begin
+ result := (3 downto 0 => '1');
+ if bypass = '0' then
+ if align_left = '1' then
+ case va is
+ when "00" =>
+ result := "1000";
+ when "01" =>
+ result := "1100";
+ when "10" =>
+ result := "1110";
+ when "11" =>
+ result := "1111";
+ when others => null;
+ end case;
+ else
+ case va is
+ when "00" =>
+ result := "1111";
+ when "01" =>
+ result := "0111";
+ when "10" =>
+ result := "0011";
+ when "11" =>
+ result := "0001";
+ when others => null;
+ end case;
+ end if;
+ end if;
+
+ return result;
+
+ end load_be;
+
+--------------------------------------------------------------------------
+ function load_sign_ext(x : word_t; bypass, signed, word2_en, word4_en : std_logic) return word_t is
+ variable result : word_t;
+ variable sign : std_logic;
+
+ begin
+ if bypass = '1' then
+ result := x;
+ elsif word2_en = '1' then
+ sign := signed and x(15);
+ result := (31 downto 16 => sign) & x(15 downto 0);
+ else
+ sign := signed and x(7);
+ result := (31 downto 8 => sign) & x(7 downto 0);
+ end if;
+
+ return result;
+ end load_sign_ext;
+
+--------------------------------------------------------------------------
+ function events_clr return event_t is
+ variable result : event_t;
+ begin
+ result.NMI := '0';
+ result.Int := '0';
+ result.data_load_err := '0';
+ result.data_store_err := '0';
+ result.inst_load_err := '0';
+ result.inst_priv_addr := '0';
+ result.alu_ovf := '0';
+ result.alu_uvf := '0';
+ result.syscall := '0';
+ result.break := '0';
+ result.illegal := '0';
+ result.ITLB_MOD := '0';
+ result.ITLB_LOAD := '0';
+ result.ITLB_STORE := '0';
+ result.DTLB_MOD := '0';
+ result.DTLB_LOAD := '0';
+ result.DTLB_STORE := '0';
+
+ return result;
+
+ end events_clr;
+
+--------------------------------------------------------------------------
+ function event_is_active(e : event_t) return std_logic is
+ variable result : std_logic;
+ begin
+ result := '0';
+
+ result := result or e.NMI;
+ result := result or e.Int;
+ result := result or e.data_load_err;
+ result := result or e.data_store_err;
+ result := result or e.inst_load_err;
+ result := result or e.inst_priv_addr;
+ result := result or e.alu_ovf;
+ result := result or e.alu_uvf;
+ result := result or e.syscall;
+ result := result or e.break;
+ result := result or e.illegal;
+ result := result or e.ITLB_MOD;
+ result := result or e.ITLB_LOAD;
+ result := result or e.ITLB_STORE;
+ result := result or e.DTLB_MOD;
+ result := result or e.DTLB_LOAD;
+ result := result or e.DTLB_STORE;
+
+ return result;
+
+ end event_is_active;
+
+--------------------------------------------------------------------------
+ function "or" (a, b : event_t) return event_t is
+ variable result : event_t;
+ begin
+ result.NMI := a.NMI or b.NMI;
+ result.Int := a.Int or b.Int;
+ result.data_load_err := a.data_load_err or b.data_load_err;
+ result.data_store_err := a.data_store_err or b.data_store_err;
+ result.inst_load_err := a.inst_load_err or b.inst_load_err;
+ result.inst_priv_addr := a.inst_priv_addr or b.inst_priv_addr;
+ result.alu_ovf := a.alu_ovf or b.alu_ovf;
+ result.alu_uvf := a.alu_uvf or b.alu_uvf;
+ result.syscall := a.syscall or b.syscall;
+ result.break := a.break or b.break;
+ result.illegal := a.illegal or b.illegal;
+ result.ITLB_MOD := a.ITLB_MOD or b.ITLB_MOD;
+ result.ITLB_LOAD := a.ITLB_LOAD or b.ITLB_LOAD;
+ result.ITLB_STORE := a.ITLB_STORE or b.ITLB_STORE;
+ result.DTLB_MOD := a.DTLB_MOD or b.DTLB_MOD;
+ result.DTLB_LOAD := a.DTLB_LOAD or b.DTLB_LOAD;
+ result.DTLB_STORE := a.DTLB_STORE or b.DTLB_STORE;
+
+ return result;
+
+ end "or";
+
+--------------------------------------------------------------------------
+ function "or" (a, b : tlb_flags_t) return tlb_flags_t is
+ variable result : tlb_flags_t;
+ begin
+ result.N := a.N or b.N;
+ result.D := a.D or b.D;
+ result.V := a.V or b.V;
+
+ return result;
+
+ end "or";
+
+--------------------------------------------------------------------------
+end mips_types;
+
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/mips_util_pkg.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_util_pkg.vhd
new file mode 100644
index 0000000..07d3118
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/mips_util_pkg.vhd
@@ -0,0 +1,68 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: Types, constants and functions for JIPS
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+--------------------------------------------------------------------------
+package mips_util_pkg is
+
+
+ function to_mips_01(x : unsigned) return unsigned;
+ function lg2(x : natural) return natural;
+ function po2(x : natural) return natural;
+
+end mips_util_pkg;
+
+--------------------------------------------------------------------------
+package body mips_util_pkg is
+
+ function to_mips_01(x : unsigned) return unsigned is
+ variable result : unsigned (x'left downto x'right);
+ begin
+ for i in x'left downto x'right loop
+ if x(i) = '1' then
+ result(i) := '1';
+ else
+ result(i) := '0';
+ end if;
+ end loop;
+ return result;
+ end to_mips_01;
+
+ function lg2(x : natural) return natural is
+ begin
+ return natural(ceil(log2(real(x))));
+ end lg2;
+
+ function po2(x : natural) return natural is
+ begin
+
+ return 2**lg2(x);
+ end po2;
+
+--------------------------------------------------------------------------
+end mips_util_pkg;
+
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache.vhd
new file mode 100644
index 0000000..49141e1
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache.vhd
@@ -0,0 +1,696 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ write_fifo_size : natural := 4;
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ be : in unsigned(3 downto 0);
+ addr : in word_t;
+ din : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ bus_dout : out word_t;
+ bus_dout_vld : out std_logic;
+ bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_ctrl2_state_t is (init, ready, refill_pre, refill, refill_post, read_nofill);
+ signal cache_ctrl2_state, cache_ctrl2_state_next : cache_ctrl2_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, single_valid);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal cache_req_wr : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal read_rdy : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_dout : word_t;
+ signal data_reg : word_t;
+ signal be_reg : unsigned(3 downto 0);
+ signal we_reg : std_logic;
+ signal ctrl_data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal data_ram_we : unsigned(3 downto 0);
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal write_hit : std_logic;
+ signal instant_raw : std_logic;
+ signal ram_write_en : std_logic;
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+ signal write_data_avail : std_logic;
+ signal read_write_buffer : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal write_through_en : std_logic;
+ signal tlb_exc_miss : std_logic;
+ signal tlb_exc_read : std_logic;
+ signal tlb_exc_write : std_logic;
+ signal tlb_exc_dirty : std_logic;
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= write_fifo_addr_out when read_write_buffer = '1' else to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= read_write_buffer;
+ bus_cmd_out.sel <= write_fifo_sel_out when read_write_buffer = '1' else (others => '1');
+ bus_dout <= write_fifo_data_out;
+ bus_dout_vld <= read_write_buffer and write_data_avail;
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc_miss <= not tlb_result.hit;
+ tlb_exc_read <= tlb_exc_miss and not we_reg;
+ tlb_exc_write <= tlb_exc_miss and we_reg;
+ tlb_exc_dirty <= tlb_result.hit and tlb_result.flags.D and we_reg;
+ tlb_exc <= tlb_exc_read or tlb_exc_write or tlb_exc_dirty;
+
+ tlb_exc_type <= "10" when tlb_exc_read = '1' else "01" when tlb_exc_write = '1' else "11" when tlb_exc_dirty = '1' else "00";
+
+ write_hit <= we_reg and cache_hit and not tlb_exc;
+
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => lg2(write_fifo_size),
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ write_fifo_data_in <= data_reg;
+ write_fifo_addr_in <= request_pa;
+ write_fifo_sel_in <= be_reg;
+ write_fifo_re <= read_write_buffer and bus_dout_rdy and bus_cmd_rdy;
+ write_fifo_we <= write_through_en;
+ write_data_avail <= not write_fifo_empty;
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+-- single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+-- single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+-- single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ cache_req_rd <= en and not we;
+ cache_req_wr <= en and we;
+ end if;
+ end if;
+ end process;
+
+request_register2:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ we_reg <= '0';
+ elsif cache_rdy = '1' then
+ data_reg <= din;
+ be_reg <= be;
+ we_reg <= we;
+ if we = '1' then
+ hit_cache_index <= to_cache_index(addr);
+ end if;
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ instant_raw <= '0';
+ if to_word_index(addr) = fill_word_index and to_cache_index(addr) = hit_cache_index then
+ instant_raw <= write_hit and en and not we;
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => data_ram_addr,
+ din_a => data_reg(8*(i+1)-1 downto 8*i),
+ din_b => bus_din(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_ctrl2_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_ctrl2_state <= cache_ctrl2_state_next;
+ end if;
+ end if;
+ end process;
+
+ cache_rdy <= read_rdy and not write_fifo_full and not instant_raw;
+ rdy <= cache_rdy;
+
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_dout;
+
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when (was_miss = '0' and instant_raw = '0') else to_cache_index(request_va);
+
+ cache_entry_out <= to_dcache_entry(tag_ram_dout);
+ cache_entry_out_inv <= to_dcache_entry(tag_ram_dout_inv);
+
+ data_ram_addr <= (to_cache_index(addr) & to_word_index(addr)) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (to_cache_index(request_va) & fill_word_index);
+ ctrl_data_ram_addr <= to_cache_index(request_va) & fill_word_index;
+ ctrl_data_ram_we <= (others => ram_write_en and bus_din_vld);
+ data_ram_we <= be_reg when (write_hit = '1') else (others => '0');
+
+ write_through_en <= cache_req_wr and tlb_result.hit and not tlb_result.flags.D;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, cache_req_rd, cache_hit, single_read_reg_vld, tlb_result, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, bus_din_vld, invalidate_req, invalidate_all, write_data_avail)
+ begin
+ read_rdy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ single_read_reg_vld <= '0';
+ read_write_buffer <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+ read_rdy <= '1';
+
+ when ready =>
+ read_rdy <= (tlb_result.hit and (not tlb_result.flags.N or cache_hit)) or not cache_req_rd;
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif write_data_avail = '1' then
+ cache_ctrl_state_next <= ready;
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ read_write_buffer <= '1';
+ bus_cmd_we <= '1';
+ end if;
+ elsif cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' or cache_hit = '0' then
+ read_rdy <= '0';
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+ end if;
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if tlb_result.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= single_valid;
+ end if;
+
+ when single_valid =>
+ read_rdy <= '1';
+ single_read_reg_vld <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130728.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130728.vhd
new file mode 100644
index 0000000..aec932f
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130728.vhd
@@ -0,0 +1,743 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ be : in unsigned(3 downto 0);
+ addr : in word_t;
+ din : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ bus_dout : out word_t;
+ bus_dout_vld : out std_logic;
+ bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_ctrl_state_t is (init, ready, refill_pre, refill, refill_post, read_nofill);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ type cache_mgmt_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, mem_write_through);
+ signal cache_mgmt_state, cache_mgmt_state_next : cache_mgmt_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal cache_req_wr : std_logic;
+ signal cache_refill_en : std_logic;
+ signal cache_refill_bsy : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_dout : word_t;
+ signal data_reg : word_t;
+ signal be_reg : unsigned(3 downto 0);
+ signal we_reg : std_logic;
+ signal ctrl_data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal data_ram_we : unsigned(3 downto 0);
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal write_hit : std_logic;
+ signal instant_raw : std_logic;
+ signal ram_write_en : std_logic;
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+ signal write_data_avail : std_logic;
+ signal read_write_buffer : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal write_through_en : std_logic;
+ signal tlb_exc_miss : std_logic;
+ signal tlb_exc_read : std_logic;
+ signal tlb_exc_write : std_logic;
+ signal tlb_exc_dirty : std_logic;
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= write_fifo_addr_out when read_write_buffer = '1' else to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= read_write_buffer;
+ bus_cmd_out.sel <= write_fifo_sel_out when read_write_buffer = '1' else (others => '1');
+ bus_dout <= write_fifo_data_out;
+ bus_dout_vld <= read_write_buffer and write_data_avail;
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc_miss <= not tlb_result.hit;
+ tlb_exc_read <= tlb_exc_miss and not we_reg;
+ tlb_exc_write <= tlb_exc_miss and we_reg;
+ tlb_exc_dirty <= tlb_result.hit and tlb_result.flags.D and we_reg;
+ tlb_exc <= tlb_exc_read or tlb_exc_write or tlb_exc_dirty;
+
+ tlb_exc_type <= "10" when tlb_exc_read = '1' else "01" when tlb_exc_write = '1' else "11" when tlb_exc_dirty = '1' else "00";
+
+ write_hit <= we_reg and cache_hit and not tlb_exc;
+
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => 4,
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ write_fifo_data_in <= data_reg;
+ write_fifo_addr_in <= request_pa;
+ write_fifo_sel_in <= be_reg;
+ write_fifo_re <= read_write_buffer and bus_dout_rdy and bus_cmd_rdy;
+ write_fifo_we <= write_through_en;
+ write_data_avail <= not write_fifo_empty;
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+ single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ cache_req_rd <= en and not we;
+ cache_req_wr <= en and we;
+ end if;
+ end process;
+
+request_register2:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ we_reg <= '0';
+ elsif cache_rdy = '1' then
+ data_reg <= din;
+ be_reg <= be;
+ we_reg <= we;
+ if we = '1' then
+ hit_cache_index <= to_cache_index(addr);
+ end if;
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ instant_raw <= '0';
+ if to_word_index(addr) = fill_word_index and to_cache_index(addr) = hit_cache_index then
+ instant_raw <= write_hit and en and not we;
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => data_ram_addr,
+ din_a => data_reg(8*(i+1)-1 downto 8*i),
+ din_b => bus_din(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_mgmt_state <= init;
+ cache_ctrl_state <= init;
+ else
+ cache_mgmt_state <= cache_mgmt_state_next;
+ cache_ctrl_state <= cache_ctrl_state_next;
+ end if;
+ end if;
+ end process;
+
+ rdy <= cache_rdy and not write_fifo_full;
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_dout;
+
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when (was_miss = '0' and instant_raw = '0') else to_cache_index(request_va);
+
+ cache_entry_out <= to_dcache_entry(tag_ram_dout);
+ cache_entry_out_inv <= to_dcache_entry(tag_ram_dout_inv);
+
+ data_ram_addr <= (to_cache_index(addr) & to_word_index(addr)) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (to_cache_index(request_va) & fill_word_index);
+ ctrl_data_ram_addr <= to_cache_index(request_va) & fill_word_index;
+ ctrl_data_ram_we <= (others => ram_write_en and bus_din_vld);
+ data_ram_we <= be_reg when (write_hit = '1') else (others => '0');
+
+ write_through_en <= cache_req_wr and tlb_result.hit and not tlb_result.flags.D;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, tlb_result, cache_req_rd, cache_hit, cache_refill_bsy, instant_raw, we_reg, bus_dout_rdy, bus_cmd_rdy)
+ begin
+
+ cache_rdy <= '0';
+ cache_refill_en <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_rdy <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ cache_rdy <= not (instant_raw and cache_hit);
+ if cache_req_rd = '1' then
+ if tlb_result.flags.N = '1' then
+ cache_rdy <= '0';
+ cache_ctrl_state_next <= refill_pre;
+ elsif cache_hit = '0' and tlb_result.hit = '1' then
+ cache_rdy <= '0';
+ cache_ctrl_state_next <= refill_pre;
+ end if;
+ end if;
+
+ when refill_pre =>
+ cache_refill_en <= '1';
+ if cache_refill_bsy = '1' then
+ cache_ctrl_state_next <= refill;
+ end if;
+
+ when refill =>
+ if cache_refill_bsy = '0' then
+ cache_ctrl_state_next <= refill_post;
+ end if;
+
+ when refill_post =>
+ cache_rdy <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when read_nofill =>
+ cache_rdy <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_state:
+ process(cache_mgmt_state, cache_refill_en, tlb_result, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, bus_din_vld, invalidate_req, invalidate_all, write_data_avail)
+ begin
+ cache_refill_bsy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ read_write_buffer <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_mgmt_state_next <= cache_mgmt_state;
+
+ case cache_mgmt_state is
+
+ when init =>
+ cache_mgmt_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_mgmt_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif write_data_avail = '1' then
+ cache_mgmt_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ elsif cache_refill_en = '1' then
+ cache_mgmt_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_mgmt_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_mgmt_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_mgmt_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_mgmt_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_mgmt_state_next <= mem_read;
+ if write_data_avail = '1' then
+ cache_mgmt_state_next <= mem_write_through;
+ elsif tlb_result.flags.N = '1' then
+ cache_refill_bsy <= '1';
+ cache_mgmt_state_next <= mem_read_single;
+ end if;
+ end if;
+ when mem_write_through =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ read_write_buffer <= '1';
+ if write_data_avail = '0' then
+ read_write_buffer <= '0';
+ bus_cmd_we <= '0';
+ cache_mgmt_state_next <= ready;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_mgmt_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ cache_mgmt_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_mgmt_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ if bus_din_vld = '1' then
+ cache_mgmt_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_mgmt_state_next <= ready;
+
+ when others =>
+ cache_mgmt_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130729.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130729.vhd
new file mode 100644
index 0000000..b84b402
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130729.vhd
@@ -0,0 +1,754 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ write_fifo_size : natural := 4;
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ be : in unsigned(3 downto 0);
+ addr : in word_t;
+ din : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ bus_dout : out word_t;
+ bus_dout_vld : out std_logic;
+ bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_ctrl2_state_t is (init, ready, refill_pre, refill, refill_post, read_nofill);
+ signal cache_ctrl2_state, cache_ctrl2_state_next : cache_ctrl2_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, mem_write_through);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal cache_req_wr : std_logic;
+ signal cache_refill_en : std_logic;
+ signal cache_refill_bsy : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal read_rdy : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_dout : word_t;
+ signal data_reg : word_t;
+ signal be_reg : unsigned(3 downto 0);
+ signal we_reg : std_logic;
+ signal ctrl_data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal data_ram_we : unsigned(3 downto 0);
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal write_hit : std_logic;
+ signal instant_raw : std_logic;
+ signal ram_write_en : std_logic;
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+ signal write_data_avail : std_logic;
+ signal read_write_buffer : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal write_through_en : std_logic;
+ signal tlb_exc_miss : std_logic;
+ signal tlb_exc_read : std_logic;
+ signal tlb_exc_write : std_logic;
+ signal tlb_exc_dirty : std_logic;
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= write_fifo_addr_out when read_write_buffer = '1' else to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= read_write_buffer;
+ bus_cmd_out.sel <= write_fifo_sel_out when read_write_buffer = '1' else (others => '1');
+ bus_dout <= write_fifo_data_out;
+ bus_dout_vld <= read_write_buffer and write_data_avail;
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc_miss <= not tlb_result.hit;
+ tlb_exc_read <= tlb_exc_miss and not we_reg;
+ tlb_exc_write <= tlb_exc_miss and we_reg;
+ tlb_exc_dirty <= tlb_result.hit and tlb_result.flags.D and we_reg;
+ tlb_exc <= tlb_exc_read or tlb_exc_write or tlb_exc_dirty;
+
+ tlb_exc_type <= "10" when tlb_exc_read = '1' else "01" when tlb_exc_write = '1' else "11" when tlb_exc_dirty = '1' else "00";
+
+ write_hit <= we_reg and cache_hit and not tlb_exc;
+
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => lg2(write_fifo_size),
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ write_fifo_data_in <= data_reg;
+ write_fifo_addr_in <= request_pa;
+ write_fifo_sel_in <= be_reg;
+ write_fifo_re <= read_write_buffer and bus_dout_rdy and bus_cmd_rdy;
+ write_fifo_we <= write_through_en;
+ write_data_avail <= not write_fifo_empty;
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+ single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ cache_req_rd <= en and not we;
+ cache_req_wr <= en and we;
+ end if;
+ end if;
+ end process;
+
+request_register2:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ we_reg <= '0';
+ elsif cache_rdy = '1' then
+ data_reg <= din;
+ be_reg <= be;
+ we_reg <= we;
+ if we = '1' then
+ hit_cache_index <= to_cache_index(addr);
+ end if;
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ instant_raw <= '0';
+ if to_word_index(addr) = fill_word_index and to_cache_index(addr) = hit_cache_index then
+ instant_raw <= write_hit and en and not we;
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => data_ram_addr,
+ din_a => data_reg(8*(i+1)-1 downto 8*i),
+ din_b => bus_din(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_ctrl2_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_ctrl2_state <= cache_ctrl2_state_next;
+ end if;
+ end if;
+ end process;
+
+ cache_rdy <= read_rdy and not write_fifo_full and not instant_raw;
+ rdy <= cache_rdy;
+
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_dout;
+
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when (was_miss = '0' and instant_raw = '0') else to_cache_index(request_va);
+
+ cache_entry_out <= to_dcache_entry(tag_ram_dout);
+ cache_entry_out_inv <= to_dcache_entry(tag_ram_dout_inv);
+
+ data_ram_addr <= (to_cache_index(addr) & to_word_index(addr)) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (to_cache_index(request_va) & fill_word_index);
+ ctrl_data_ram_addr <= to_cache_index(request_va) & fill_word_index;
+ ctrl_data_ram_we <= (others => ram_write_en and bus_din_vld);
+ data_ram_we <= be_reg when (write_hit = '1') else (others => '0');
+
+ write_through_en <= cache_req_wr and tlb_result.hit and not tlb_result.flags.D;
+
+cache_ctrl2_state_fsm:
+ process(cache_ctrl2_state, tlb_result, cache_req_rd, cache_hit, cache_refill_bsy)
+ begin
+
+ read_rdy <= '0';
+ cache_refill_en <= '0';
+ cache_ctrl2_state_next <= cache_ctrl2_state;
+
+ case cache_ctrl2_state is
+
+ when init =>
+ read_rdy <= '1';
+ cache_ctrl2_state_next <= ready;
+
+ when ready =>
+ read_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' then
+ read_rdy <= '0';
+ cache_ctrl2_state_next <= refill_pre;
+ elsif cache_hit = '0' then
+ read_rdy <= '0';
+ cache_ctrl2_state_next <= refill_pre;
+ end if;
+ end if;
+ end if;
+
+ when refill_pre =>
+ cache_refill_en <= '1';
+ if cache_refill_bsy = '1' then
+ cache_ctrl2_state_next <= refill;
+ end if;
+
+ when refill =>
+ if cache_refill_bsy = '0' then
+ cache_ctrl2_state_next <= refill_post;
+ end if;
+
+ when refill_post =>
+ read_rdy <= '1';
+ cache_ctrl2_state_next <= ready;
+
+ when read_nofill =>
+ read_rdy <= '1';
+ cache_ctrl2_state_next <= ready;
+
+ when others =>
+ cache_ctrl2_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, cache_refill_en, tlb_result, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, bus_din_vld, invalidate_req, invalidate_all, write_data_avail)
+ begin
+ cache_refill_bsy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ read_write_buffer <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif write_data_avail = '1' then
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ read_write_buffer <= '1';
+ bus_cmd_we <= '1';
+ end if;
+ elsif cache_refill_en = '1' then
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if write_data_avail = '1' then
+ cache_ctrl_state_next <= mem_write_through;
+ elsif tlb_result.flags.N = '1' then
+ cache_refill_bsy <= '1';
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+ when mem_write_through =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ read_write_buffer <= '1';
+ if write_data_avail = '0' then
+ read_write_buffer <= '0';
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130729_works.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130729_works.vhd
new file mode 100644
index 0000000..b84b402
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130729_works.vhd
@@ -0,0 +1,754 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ write_fifo_size : natural := 4;
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ be : in unsigned(3 downto 0);
+ addr : in word_t;
+ din : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ bus_dout : out word_t;
+ bus_dout_vld : out std_logic;
+ bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_ctrl2_state_t is (init, ready, refill_pre, refill, refill_post, read_nofill);
+ signal cache_ctrl2_state, cache_ctrl2_state_next : cache_ctrl2_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, mem_write_through);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal cache_req_wr : std_logic;
+ signal cache_refill_en : std_logic;
+ signal cache_refill_bsy : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal read_rdy : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_dout : word_t;
+ signal data_reg : word_t;
+ signal be_reg : unsigned(3 downto 0);
+ signal we_reg : std_logic;
+ signal ctrl_data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal data_ram_we : unsigned(3 downto 0);
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal write_hit : std_logic;
+ signal instant_raw : std_logic;
+ signal ram_write_en : std_logic;
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+ signal write_data_avail : std_logic;
+ signal read_write_buffer : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal write_through_en : std_logic;
+ signal tlb_exc_miss : std_logic;
+ signal tlb_exc_read : std_logic;
+ signal tlb_exc_write : std_logic;
+ signal tlb_exc_dirty : std_logic;
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= write_fifo_addr_out when read_write_buffer = '1' else to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= read_write_buffer;
+ bus_cmd_out.sel <= write_fifo_sel_out when read_write_buffer = '1' else (others => '1');
+ bus_dout <= write_fifo_data_out;
+ bus_dout_vld <= read_write_buffer and write_data_avail;
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc_miss <= not tlb_result.hit;
+ tlb_exc_read <= tlb_exc_miss and not we_reg;
+ tlb_exc_write <= tlb_exc_miss and we_reg;
+ tlb_exc_dirty <= tlb_result.hit and tlb_result.flags.D and we_reg;
+ tlb_exc <= tlb_exc_read or tlb_exc_write or tlb_exc_dirty;
+
+ tlb_exc_type <= "10" when tlb_exc_read = '1' else "01" when tlb_exc_write = '1' else "11" when tlb_exc_dirty = '1' else "00";
+
+ write_hit <= we_reg and cache_hit and not tlb_exc;
+
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => lg2(write_fifo_size),
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ write_fifo_data_in <= data_reg;
+ write_fifo_addr_in <= request_pa;
+ write_fifo_sel_in <= be_reg;
+ write_fifo_re <= read_write_buffer and bus_dout_rdy and bus_cmd_rdy;
+ write_fifo_we <= write_through_en;
+ write_data_avail <= not write_fifo_empty;
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+ single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ cache_req_rd <= en and not we;
+ cache_req_wr <= en and we;
+ end if;
+ end if;
+ end process;
+
+request_register2:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ we_reg <= '0';
+ elsif cache_rdy = '1' then
+ data_reg <= din;
+ be_reg <= be;
+ we_reg <= we;
+ if we = '1' then
+ hit_cache_index <= to_cache_index(addr);
+ end if;
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ instant_raw <= '0';
+ if to_word_index(addr) = fill_word_index and to_cache_index(addr) = hit_cache_index then
+ instant_raw <= write_hit and en and not we;
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => data_ram_addr,
+ din_a => data_reg(8*(i+1)-1 downto 8*i),
+ din_b => bus_din(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_ctrl2_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_ctrl2_state <= cache_ctrl2_state_next;
+ end if;
+ end if;
+ end process;
+
+ cache_rdy <= read_rdy and not write_fifo_full and not instant_raw;
+ rdy <= cache_rdy;
+
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_dout;
+
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when (was_miss = '0' and instant_raw = '0') else to_cache_index(request_va);
+
+ cache_entry_out <= to_dcache_entry(tag_ram_dout);
+ cache_entry_out_inv <= to_dcache_entry(tag_ram_dout_inv);
+
+ data_ram_addr <= (to_cache_index(addr) & to_word_index(addr)) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (to_cache_index(request_va) & fill_word_index);
+ ctrl_data_ram_addr <= to_cache_index(request_va) & fill_word_index;
+ ctrl_data_ram_we <= (others => ram_write_en and bus_din_vld);
+ data_ram_we <= be_reg when (write_hit = '1') else (others => '0');
+
+ write_through_en <= cache_req_wr and tlb_result.hit and not tlb_result.flags.D;
+
+cache_ctrl2_state_fsm:
+ process(cache_ctrl2_state, tlb_result, cache_req_rd, cache_hit, cache_refill_bsy)
+ begin
+
+ read_rdy <= '0';
+ cache_refill_en <= '0';
+ cache_ctrl2_state_next <= cache_ctrl2_state;
+
+ case cache_ctrl2_state is
+
+ when init =>
+ read_rdy <= '1';
+ cache_ctrl2_state_next <= ready;
+
+ when ready =>
+ read_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' then
+ read_rdy <= '0';
+ cache_ctrl2_state_next <= refill_pre;
+ elsif cache_hit = '0' then
+ read_rdy <= '0';
+ cache_ctrl2_state_next <= refill_pre;
+ end if;
+ end if;
+ end if;
+
+ when refill_pre =>
+ cache_refill_en <= '1';
+ if cache_refill_bsy = '1' then
+ cache_ctrl2_state_next <= refill;
+ end if;
+
+ when refill =>
+ if cache_refill_bsy = '0' then
+ cache_ctrl2_state_next <= refill_post;
+ end if;
+
+ when refill_post =>
+ read_rdy <= '1';
+ cache_ctrl2_state_next <= ready;
+
+ when read_nofill =>
+ read_rdy <= '1';
+ cache_ctrl2_state_next <= ready;
+
+ when others =>
+ cache_ctrl2_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, cache_refill_en, tlb_result, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, bus_din_vld, invalidate_req, invalidate_all, write_data_avail)
+ begin
+ cache_refill_bsy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ read_write_buffer <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif write_data_avail = '1' then
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ read_write_buffer <= '1';
+ bus_cmd_we <= '1';
+ end if;
+ elsif cache_refill_en = '1' then
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if write_data_avail = '1' then
+ cache_ctrl_state_next <= mem_write_through;
+ elsif tlb_result.flags.N = '1' then
+ cache_refill_bsy <= '1';
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+ when mem_write_through =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ read_write_buffer <= '1';
+ if write_data_avail = '0' then
+ read_write_buffer <= '0';
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130730.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130730.vhd
new file mode 100644
index 0000000..49141e1
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_20130730.vhd
@@ -0,0 +1,696 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ write_fifo_size : natural := 4;
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ be : in unsigned(3 downto 0);
+ addr : in word_t;
+ din : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ bus_dout : out word_t;
+ bus_dout_vld : out std_logic;
+ bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_ctrl2_state_t is (init, ready, refill_pre, refill, refill_post, read_nofill);
+ signal cache_ctrl2_state, cache_ctrl2_state_next : cache_ctrl2_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, single_valid);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal cache_req_wr : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal read_rdy : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_dout : word_t;
+ signal data_reg : word_t;
+ signal be_reg : unsigned(3 downto 0);
+ signal we_reg : std_logic;
+ signal ctrl_data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal data_ram_we : unsigned(3 downto 0);
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal write_hit : std_logic;
+ signal instant_raw : std_logic;
+ signal ram_write_en : std_logic;
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+ signal write_data_avail : std_logic;
+ signal read_write_buffer : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal write_through_en : std_logic;
+ signal tlb_exc_miss : std_logic;
+ signal tlb_exc_read : std_logic;
+ signal tlb_exc_write : std_logic;
+ signal tlb_exc_dirty : std_logic;
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= write_fifo_addr_out when read_write_buffer = '1' else to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= read_write_buffer;
+ bus_cmd_out.sel <= write_fifo_sel_out when read_write_buffer = '1' else (others => '1');
+ bus_dout <= write_fifo_data_out;
+ bus_dout_vld <= read_write_buffer and write_data_avail;
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc_miss <= not tlb_result.hit;
+ tlb_exc_read <= tlb_exc_miss and not we_reg;
+ tlb_exc_write <= tlb_exc_miss and we_reg;
+ tlb_exc_dirty <= tlb_result.hit and tlb_result.flags.D and we_reg;
+ tlb_exc <= tlb_exc_read or tlb_exc_write or tlb_exc_dirty;
+
+ tlb_exc_type <= "10" when tlb_exc_read = '1' else "01" when tlb_exc_write = '1' else "11" when tlb_exc_dirty = '1' else "00";
+
+ write_hit <= we_reg and cache_hit and not tlb_exc;
+
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => lg2(write_fifo_size),
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ write_fifo_data_in <= data_reg;
+ write_fifo_addr_in <= request_pa;
+ write_fifo_sel_in <= be_reg;
+ write_fifo_re <= read_write_buffer and bus_dout_rdy and bus_cmd_rdy;
+ write_fifo_we <= write_through_en;
+ write_data_avail <= not write_fifo_empty;
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+-- single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+-- single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+-- single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ cache_req_rd <= en and not we;
+ cache_req_wr <= en and we;
+ end if;
+ end if;
+ end process;
+
+request_register2:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ we_reg <= '0';
+ elsif cache_rdy = '1' then
+ data_reg <= din;
+ be_reg <= be;
+ we_reg <= we;
+ if we = '1' then
+ hit_cache_index <= to_cache_index(addr);
+ end if;
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ instant_raw <= '0';
+ if to_word_index(addr) = fill_word_index and to_cache_index(addr) = hit_cache_index then
+ instant_raw <= write_hit and en and not we;
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => '1',
+ we_a => data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => data_ram_addr,
+ din_a => data_reg(8*(i+1)-1 downto 8*i),
+ din_b => bus_din(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_ctrl2_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_ctrl2_state <= cache_ctrl2_state_next;
+ end if;
+ end if;
+ end process;
+
+ cache_rdy <= read_rdy and not write_fifo_full and not instant_raw;
+ rdy <= cache_rdy;
+
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_dout;
+
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when (was_miss = '0' and instant_raw = '0') else to_cache_index(request_va);
+
+ cache_entry_out <= to_dcache_entry(tag_ram_dout);
+ cache_entry_out_inv <= to_dcache_entry(tag_ram_dout_inv);
+
+ data_ram_addr <= (to_cache_index(addr) & to_word_index(addr)) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (to_cache_index(request_va) & fill_word_index);
+ ctrl_data_ram_addr <= to_cache_index(request_va) & fill_word_index;
+ ctrl_data_ram_we <= (others => ram_write_en and bus_din_vld);
+ data_ram_we <= be_reg when (write_hit = '1') else (others => '0');
+
+ write_through_en <= cache_req_wr and tlb_result.hit and not tlb_result.flags.D;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, cache_req_rd, cache_hit, single_read_reg_vld, tlb_result, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, bus_din_vld, invalidate_req, invalidate_all, write_data_avail)
+ begin
+ read_rdy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ single_read_reg_vld <= '0';
+ read_write_buffer <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+ read_rdy <= '1';
+
+ when ready =>
+ read_rdy <= (tlb_result.hit and (not tlb_result.flags.N or cache_hit)) or not cache_req_rd;
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif write_data_avail = '1' then
+ cache_ctrl_state_next <= ready;
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ read_write_buffer <= '1';
+ bus_cmd_we <= '1';
+ end if;
+ elsif cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' or cache_hit = '0' then
+ read_rdy <= '0';
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+ end if;
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if tlb_result.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= single_valid;
+ end if;
+
+ when single_valid =>
+ read_rdy <= '1';
+ single_read_reg_vld <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_new.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_new.vhd
new file mode 100644
index 0000000..58e074b
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_dcache_new.vhd
@@ -0,0 +1,782 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ CACHE_SIZE : natural := 1024; -- words
+ LINE_SIZE : natural := 8; -- words
+ WRITE_FIFO_SIZE : natural := 4;
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ be : in unsigned(3 downto 0);
+ addr : in word_t;
+ din : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ bus_dout : out word_t;
+ bus_dout_vld : out std_logic;
+ bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(LINE_SIZE);
+ constant cache_index_width : natural := lg2(CACHE_SIZE) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_busy_state_t is (init, ready, busy);
+ signal cache_busy_state, cache_busy_state_next : cache_busy_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, invalidate_post, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ type debug_t is record
+ ready : std_logic;
+ req_strobe : std_logic;
+ req_read : std_logic;
+ req_write : std_logic;
+ req_va : word_t;
+ req_pa : word_t;
+ dout_reg : word_t;
+ din_reg : word_t;
+ end record;
+
+ signal debug : debug_t;
+
+ signal req_strobe : std_logic;
+ signal cache_req_rd : std_logic;
+ signal cache_req_wr : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal read_rdy : std_logic;
+ signal write_rdy : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+
+ signal mem_fetch_req : std_logic;
+ signal mem_fetch_ack : std_logic;
+ signal single_read_en : std_logic;
+ signal single_read_set : std_logic;
+ signal single_read_reg_vld : std_logic;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal data_ram_addr : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal data_ram_dout : word_t;
+ signal din_reg : word_t;
+ signal be_reg : unsigned(3 downto 0);
+ signal ctrl_data_ram_addr : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal data_ram_we : unsigned(3 downto 0);
+ signal single_read_reg : word_t;
+ signal cache_dout : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal write_hit : std_logic;
+ signal instant_raw : std_logic;
+ signal ram_write_en : std_logic;
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+ signal write_data_avail : std_logic;
+ signal read_write_buffer : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal write_through_en : std_logic;
+ signal tlb_exc_miss : std_logic;
+ signal tlb_exc_read : std_logic;
+ signal tlb_exc_write : std_logic;
+ signal tlb_exc_dirty : std_logic;
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ bus_din_rdy <= fill_count_en or single_read_en;
+ bus_cmd_out.addr <= write_fifo_addr_out when read_write_buffer = '1' else to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= read_write_buffer;
+ bus_cmd_out.sel <= write_fifo_sel_out when read_write_buffer = '1' else (others => '1');
+ bus_dout <= write_fifo_data_out;
+ bus_dout_vld <= read_write_buffer and write_data_avail;
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc_miss <= not tlb_result.hit;
+ tlb_exc_read <= tlb_exc_miss and not cache_req_wr;
+ tlb_exc_write <= tlb_exc_miss and cache_req_wr;
+ tlb_exc_dirty <= tlb_result.hit and tlb_result.flags.D and cache_req_wr;
+ tlb_exc <= tlb_exc_read or tlb_exc_write or tlb_exc_dirty;
+
+ tlb_exc_type <= "10" when tlb_exc_read = '1' else "01" when tlb_exc_write = '1' else "11" when tlb_exc_dirty = '1' else "00";
+
+ write_hit <= cache_req_wr and cache_hit and not tlb_exc;
+
+ debug.req_strobe <= req_strobe;
+ debug.req_read <= cache_req_rd;
+ debug.req_write <= cache_req_wr;
+ debug.req_va <= request_va;
+ debug.req_pa <= request_pa;
+ debug.din_reg <= din_reg;
+ debug.dout_reg <= cache_dout;
+ debug.ready <= cache_rdy;
+
+-------------------------------------------------
+-- ctrl
+-------------------------------------------------
+req_strobe <= cache_rdy and en;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_req_rd <= '0';
+ cache_req_wr <= '0';
+ elsif cache_rdy = '1' then
+ cache_req_rd <= en and not we;
+ cache_req_wr <= en and we;
+ if we = '1' then
+ hit_cache_index <= to_cache_index(addr);
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ din_reg <= din;
+ be_reg <= be;
+ request_va <= addr;
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ instant_raw <= '0';
+ if to_word_index(addr) = fill_word_index and to_cache_index(addr) = hit_cache_index then
+ instant_raw <= write_hit and en and not we;
+ end if;
+ end if;
+ end process;
+
+-------------------------------------------------
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => lg2(WRITE_FIFO_SIZE),
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ write_fifo_data_in <= din_reg;
+ write_fifo_addr_in <= request_pa;
+ write_fifo_sel_in <= be_reg;
+ write_fifo_re <= read_write_buffer and bus_dout_rdy and bus_cmd_rdy;
+ write_fifo_we <= write_through_en;
+ write_data_avail <= not write_fifo_empty;
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+bus_request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ elsif single_read_en = '0' then
+ if single_read_set = '1' then
+ single_read_en <= '1';
+ end if;
+ elsif single_read_reg_vld = '1' then
+ if en = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ end if;
+ elsif bus_din_vld = '1' and single_read_en = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= '1';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(CACHE_SIZE),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => data_ram_addr,
+ din_a => din_reg(8*(i+1)-1 downto 8*i),
+ din_b => bus_din(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_busy_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_busy_state <= cache_busy_state_next;
+ end if;
+ end if;
+ end process;
+
+ cache_rdy <= read_rdy and not instant_raw and write_rdy;
+ write_rdy <= not (write_fifo_full and cache_req_wr);
+ rdy <= cache_rdy;
+
+ cache_dout <= single_read_reg when single_read_en = '1' else data_ram_dout;
+ dout <= cache_dout;
+
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when (was_miss = '0' and instant_raw = '0') else to_cache_index(request_va);
+
+ cache_entry_out <= to_dcache_entry(tag_ram_dout);
+ cache_entry_out_inv <= to_dcache_entry(tag_ram_dout_inv);
+
+ ram_read_en <= en or was_miss or fill_count_en;
+ data_ram_addr <= (to_cache_index(addr) & to_word_index(addr)) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (to_cache_index(request_va) & fill_word_index);
+ ctrl_data_ram_addr <= to_cache_index(request_va) & fill_word_index;
+ ctrl_data_ram_we <= (others => ram_write_en and bus_din_vld);
+ data_ram_we <= be_reg when (write_hit = '1') else (others => '0');
+
+ write_through_en <= cache_rdy and cache_req_wr and tlb_result.hit and not tlb_result.flags.D;
+
+cache_busy_state_fsm:
+ process(cache_busy_state, tlb_result, cache_req_rd, cache_hit, mem_fetch_ack, single_read_en, single_read_reg_vld)
+ begin
+
+ read_rdy <= '0';
+ mem_fetch_req <= '0';
+ single_read_set <= '0';
+ cache_busy_state_next <= cache_busy_state;
+
+ case cache_busy_state is
+
+ when init =>
+ cache_busy_state_next <= ready;
+
+ when ready =>
+ if single_read_en = '1' then
+ read_rdy <= single_read_reg_vld;
+ else
+ read_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' or cache_hit = '0' then
+ mem_fetch_req <= '1';
+ read_rdy <= '0';
+ cache_busy_state_next <= busy;
+ end if;
+ end if;
+ end if;
+ end if;
+
+ when busy =>
+ mem_fetch_req <= '1';
+ if mem_fetch_ack = '1' then
+ single_read_set <= tlb_result.flags.N;
+ cache_busy_state_next <= ready;
+ end if;
+
+ when others =>
+ cache_busy_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, mem_fetch_req, tlb_result, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, bus_din_vld, invalidate_req, invalidate_all, write_data_avail)
+ begin
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ mem_fetch_ack <= '0';
+ read_write_buffer <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif mem_fetch_req = '1' or write_data_avail = '1' then
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when invalidate_post =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ if write_data_avail = '1' then
+ read_write_buffer <= '1';
+ bus_cmd_we <= '1';
+ elsif mem_fetch_req = '1' then
+ if tlb_result.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ else
+ cache_ctrl_state_next <= mem_read;
+ end if;
+ else
+ cache_ctrl_state_next <= ready;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ mem_fetch_ack <= '1';
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ mem_fetch_ack <= '1';
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache.vhd
new file mode 100644
index 0000000..57cc03d
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache.vhd
@@ -0,0 +1,583 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ CACHE_ALL : boolean := true;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ -- CPU control/data
+ en : in STD_LOGIC;
+ addr : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, single_valid);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal ram_write_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ ram_read_en <= en or was_miss;
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc <= cache_req_rd and not tlb_result.hit;
+ tlb_exc_type <= "10" when tlb_exc = '1' else "00";
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+-- single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+-- single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+-- single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ cache_req_rd <= en;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ end if;
+ end if;
+ end process;
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= '0';
+ bus_cmd_out.sel <= (others => '1');
+
+ rdy <= cache_rdy;
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_data_rd;
+
+ cache_entry_out <= to_icache_entry(tag_ram_data_rd);
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+
+ cache_entry_out_inv <= to_icache_entry(tag_ram_data_rd_inv);
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when was_miss = '0' else to_cache_index(request_va);
+ data_ram_addr_rd <= (to_cache_index(addr) & to_word_index(addr)) when was_miss = '0' else (to_cache_index(request_va) & fill_word_index);
+ data_ram_addr_wr <= to_cache_index(request_va) & fill_word_index;
+ data_ram_data_wr <= bus_din;
+ data_ram_we <= ram_write_en and bus_din_vld;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, cache_req_rd, tlb_result, bus_din_vld, cache_hit, cache_hit_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, invalidate_req, invalidate_all)
+ begin
+ cache_rdy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ single_read_reg_vld <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+ cache_rdy <= '1';
+
+ when ready =>
+ cache_rdy <= tlb_result.hit and (not tlb_result.flags.N or cache_hit);
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' or cache_hit = '0' then
+ cache_rdy <= '0';
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+ end if;
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if tlb_result.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= single_valid;
+ end if;
+
+ when single_valid =>
+ cache_rdy <= '1';
+ single_read_reg_vld <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130728.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130728.vhd
new file mode 100644
index 0000000..afa2147
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130728.vhd
@@ -0,0 +1,637 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ -- CPU control/data
+ en : in STD_LOGIC;
+ addr : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+
+ type cache_ctrl_state_t is (init, ready, refill_pre, refill, refill_post, read_nofill);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ type cache_mgmt_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache);
+ signal cache_mgmt_state, cache_mgmt_state_next : cache_mgmt_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal cache_refill_en : std_logic;
+ signal cache_refill_bsy : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal ram_write_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ ram_read_en <= en or was_miss;
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc <= cache_req_rd and not tlb_result.hit;
+ tlb_exc_type <= "10" when tlb_exc = '1' else "00";
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+ single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ cache_req_rd <= en;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_mgmt_state <= init;
+ cache_ctrl_state <= init;
+ else
+ cache_mgmt_state <= cache_mgmt_state_next;
+ cache_ctrl_state <= cache_ctrl_state_next;
+ end if;
+ end if;
+ end process;
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= '0';
+ bus_cmd_out.sel <= (others => '1');
+
+ rdy <= cache_rdy;
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_data_rd;
+
+ cache_entry_out <= to_icache_entry(tag_ram_data_rd);
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+
+ cache_entry_out_inv <= to_icache_entry(tag_ram_data_rd_inv);
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when was_miss = '0' else to_cache_index(request_va);
+ data_ram_addr_rd <= (to_cache_index(addr) & to_word_index(addr)) when was_miss = '0' else (to_cache_index(request_va) & fill_word_index);
+ data_ram_addr_wr <= to_cache_index(request_va) & fill_word_index;
+ data_ram_data_wr <= bus_din;
+ data_ram_we <= ram_write_en and bus_din_vld;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, tlb_result, cache_req_rd, cache_hit, cache_refill_bsy)
+ begin
+
+ cache_rdy <= '0';
+ cache_refill_en <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_rdy <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ cache_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' then
+ cache_rdy <= '0';
+ cache_ctrl_state_next <= refill_pre;
+ elsif cache_hit = '0' then
+ cache_rdy <= '0';
+ cache_ctrl_state_next <= refill_pre;
+ end if;
+ end if;
+ end if;
+
+ when refill_pre =>
+ cache_refill_en <= '1';
+ if cache_refill_bsy = '1' then
+ cache_ctrl_state_next <= refill;
+ end if;
+
+ when refill =>
+ if cache_refill_bsy = '0' then
+ cache_ctrl_state_next <= refill_post;
+ end if;
+
+ when refill_post =>
+ cache_rdy <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when read_nofill =>
+ cache_rdy <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_mgmt_state_fsm:
+ process(cache_mgmt_state, cache_refill_en, tlb_result, bus_din_vld, cache_hit_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, invalidate_req, invalidate_all)
+ begin
+ cache_refill_bsy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_mgmt_state_next <= cache_mgmt_state;
+
+ case cache_mgmt_state is
+
+ when init =>
+ cache_mgmt_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_mgmt_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif cache_refill_en = '1' then
+ cache_mgmt_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_mgmt_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_mgmt_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_mgmt_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_mgmt_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_mgmt_state_next <= mem_read;
+ if tlb_result.flags.N = '1' then
+ cache_refill_bsy <= '1';
+ cache_mgmt_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_mgmt_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_refill_bsy <= '1';
+ cache_mgmt_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_mgmt_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ cache_refill_bsy <= '1';
+ if bus_din_vld = '1' then
+ cache_mgmt_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_mgmt_state_next <= ready;
+
+ when others =>
+ cache_mgmt_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130730.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130730.vhd
new file mode 100644
index 0000000..0e14c0d
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130730.vhd
@@ -0,0 +1,583 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := false;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ -- CPU control/data
+ en : in STD_LOGIC;
+ addr : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache, single_valid);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal ram_write_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ ram_read_en <= en or was_miss;
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc <= cache_req_rd and not tlb_result.hit;
+ tlb_exc_type <= "10" when tlb_exc = '1' else "00";
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' and en = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+-- single_read_reg_vld <= '0';
+ elsif bus_din_vld = '1' then
+ single_read_reg <= bus_din;
+-- single_read_reg_vld <= tlb_result.flags.N;
+ elsif cache_rdy = '1' then
+-- single_read_reg_vld <= '0';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ cache_req_rd <= en;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ end if;
+ end if;
+ end process;
+
+ bus_din_rdy <= bus_din_vld;
+ bus_cmd_out.addr <= to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= '0';
+ bus_cmd_out.sel <= (others => '1');
+
+ rdy <= cache_rdy;
+ dout <= single_read_reg when single_read_reg_vld = '1' else data_ram_data_rd;
+
+ cache_entry_out <= to_icache_entry(tag_ram_data_rd);
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+
+ cache_entry_out_inv <= to_icache_entry(tag_ram_data_rd_inv);
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when was_miss = '0' else to_cache_index(request_va);
+ data_ram_addr_rd <= (to_cache_index(addr) & to_word_index(addr)) when was_miss = '0' else (to_cache_index(request_va) & fill_word_index);
+ data_ram_addr_wr <= to_cache_index(request_va) & fill_word_index;
+ data_ram_data_wr <= bus_din;
+ data_ram_we <= ram_write_en and bus_din_vld;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, cache_req_rd, tlb_result, bus_din_vld, cache_hit, cache_hit_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, invalidate_req, invalidate_all)
+ begin
+ cache_rdy <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ single_read_reg_vld <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+ cache_rdy <= '1';
+
+ when ready =>
+ cache_rdy <= tlb_result.hit and (not tlb_result.flags.N or cache_hit);
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' or cache_hit = '0' then
+ cache_rdy <= '0';
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+ end if;
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if tlb_result.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= single_valid;
+ end if;
+
+ when single_valid =>
+ cache_rdy <= '1';
+ single_read_reg_vld <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when rd_cache =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130801_works.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130801_works.vhd
new file mode 100644
index 0000000..d9a02cf
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_20130801_works.vhd
@@ -0,0 +1,640 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8; -- words
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := false;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ -- CPU control/data
+ en : in STD_LOGIC;
+ addr : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+ type cache_busy_state_t is (init, ready, busy);
+ signal cache_busy_state, cache_busy_state_next : cache_busy_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, invalidate_post, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ signal cache_req_rd : std_logic;
+ signal mem_fetch_req : std_logic;
+ signal mem_fetch_ack : std_logic;
+ signal single_read_en : std_logic;
+ signal single_read_set : std_logic;
+ signal single_read_reg_vld : std_logic;
+ signal read_rdy : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+ signal single_read_reg : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal ram_write_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ ram_read_en <= en or was_miss;
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc <= cache_req_rd and not tlb_result.hit;
+ tlb_exc_type <= "10" when tlb_exc = '1' else "00";
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if (cache_rdy = '1' and en = '1') or (cache_req_rd = '0' and en = '1') then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if (cache_rdy = '1' and en = '1') or (cache_req_rd = '0' and en = '1') then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ elsif single_read_en = '0' then
+ if single_read_set = '1' then
+ single_read_en <= '1';
+ end if;
+ elsif single_read_reg_vld = '1' then
+ if en = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ end if;
+ elsif bus_din_vld = '1' and single_read_en = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= '1';
+ end if;
+ end if;
+ end process;
+
+request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ cache_req_rd <= en;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_busy_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_busy_state <= cache_busy_state_next;
+ end if;
+ end if;
+ end process;
+
+ bus_din_rdy <= fill_count_en or single_read_en;
+ bus_cmd_out.addr <= to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= '0';
+ bus_cmd_out.sel <= (others => '1');
+
+ cache_rdy <= read_rdy;
+ rdy <= cache_rdy;
+
+ dout <= single_read_reg when single_read_en = '1' else data_ram_data_rd;
+
+ cache_entry_out <= to_icache_entry(tag_ram_data_rd);
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+
+ cache_entry_out_inv <= to_icache_entry(tag_ram_data_rd_inv);
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when was_miss = '0' else to_cache_index(request_va);
+ data_ram_addr_rd <= (to_cache_index(addr) & to_word_index(addr)) when was_miss = '0' else (to_cache_index(request_va) & fill_word_index);
+ data_ram_addr_wr <= to_cache_index(request_va) & fill_word_index;
+ data_ram_data_wr <= bus_din;
+ data_ram_we <= ram_write_en and bus_din_vld;
+
+cache_busy_state_fsm:
+ process(cache_busy_state, tlb_result, cache_req_rd, cache_hit, mem_fetch_ack, single_read_en, single_read_reg_vld)
+ begin
+
+ read_rdy <= '0';
+ mem_fetch_req <= '0';
+ single_read_set <= '0';
+ cache_busy_state_next <= cache_busy_state;
+
+ case cache_busy_state is
+
+ when init =>
+ cache_busy_state_next <= ready;
+
+ when ready =>
+ if single_read_en = '1' then
+ read_rdy <= single_read_reg_vld;
+ else
+ read_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' or cache_hit = '0' then
+ mem_fetch_req <= '1';
+ read_rdy <= '0';
+ single_read_set <= tlb_result.flags.N;
+ cache_busy_state_next <= busy;
+ end if;
+ end if;
+ end if;
+ end if;
+
+ when busy =>
+ mem_fetch_req <= '1';
+ if mem_fetch_ack = '1' then
+ cache_busy_state_next <= ready;
+ end if;
+
+ when others =>
+ cache_busy_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, mem_fetch_req, tlb_result, bus_din_vld, cache_hit_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, invalidate_req, invalidate_all)
+ begin
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ mem_fetch_ack <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif mem_fetch_req = '1' then
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when invalidate_post =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if tlb_result.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ mem_fetch_ack <= '1';
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ mem_fetch_ack <= '1';
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_new.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_new.vhd
new file mode 100644
index 0000000..ea470e8
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_new.vhd
@@ -0,0 +1,671 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ CACHE_SIZE : natural := 1024; -- words
+ LINE_SIZE : natural := 8; -- words
+ CACHE_ALL : boolean := false;
+ USE_CACHE : boolean := true;
+ USE_TLB : boolean := false
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ -- CPU control/data
+ en : in STD_LOGIC;
+ addr : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(LINE_SIZE);
+ constant cache_index_width : natural := lg2(CACHE_SIZE) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ function to_word_index(x : word_t) return unsigned is
+ variable result : unsigned(word_index_width-1 downto 0);
+ begin
+ result := x(word_index_width+1 downto 2);
+
+ return result;
+
+ end to_word_index;
+
+
+ function to_cache_index(x : word_t) return unsigned is
+ variable result : unsigned(cache_index_width-1 downto 0);
+ begin
+ result := x(cache_index_width+word_index_width+1 downto word_index_width+2);
+
+ return result;
+
+ end to_cache_index;
+
+ function to_tag(x : word_t) return unsigned is
+ variable result : unsigned(tag_width-1 downto 0);
+ begin
+ result := x(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ return result;
+
+ end to_tag;
+
+ type cache_busy_state_t is (init, ready, busy);
+ signal cache_busy_state, cache_busy_state_next : cache_busy_state_t;
+
+ type cache_ctrl_state_t is (init, ready, invalidate, invalidate_post, flush, bus_request, mem_read, mem_read_single, mem_read_data, mem_read_data_single, rd_cache, upd_cache);
+ signal cache_ctrl_state, cache_ctrl_state_next : cache_ctrl_state_t;
+
+ type debug_t is record
+ ready : std_logic;
+ req_strobe : std_logic;
+ req_read : std_logic;
+ req_va : word_t;
+ req_pa : word_t;
+ dout_reg : word_t;
+ end record;
+
+ signal debug : debug_t;
+
+ signal req_strobe : std_logic;
+ signal cache_req_rd : std_logic;
+ signal read_rdy : std_logic;
+ signal cache_rdy : std_logic;
+ signal cache_hit : std_logic;
+ signal request_va : word_t;
+ signal request_pa : word_t;
+
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+
+ signal mem_fetch_req : std_logic;
+ signal mem_fetch_ack : std_logic;
+ signal single_read_en : std_logic;
+ signal single_read_set : std_logic;
+ signal single_read_reg_vld : std_logic;
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(CACHE_SIZE)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+ signal single_read_reg : word_t;
+ signal cache_dout : word_t;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal ram_write_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ signal fill_word_index : unsigned(word_index_width-1 downto 0);
+ signal req_word_index : unsigned(word_index_width-1 downto 0);
+
+ signal tlb_exc : std_logic;
+ signal tlb_exc_type : unsigned(1 downto 0);
+
+ signal tlb_result_no_translate : tlb_query_out_t;
+ signal tlb_result : tlb_query_out_t;
+
+begin
+
+ tlb_query_out.vaddr <= request_va;
+ tlb_result_no_translate.paddr <= request_va;
+ tlb_result_no_translate.hit_idx <= (others => '0');
+ tlb_result_no_translate.hit <= '1';
+ tlb_result_no_translate.flags.N <= '0' when CACHE_ALL = true else '1' when USE_CACHE = false else '1' when request_va(31 downto 29) = "101" else '0';
+ tlb_result_no_translate.flags.D <= '0';
+ tlb_result_no_translate.flags.V <= '1';
+
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ tlb_result <= tlb_query_in when USE_TLB else tlb_result_no_translate;
+ request_pa <= tlb_result.paddr;
+
+ tlb_exc <= cache_req_rd and not tlb_result.hit;
+ tlb_exc_type <= "10" when tlb_exc = '1' else "00";
+
+ debug.req_strobe <= req_strobe;
+ debug.req_read <= cache_req_rd;
+ debug.req_va <= request_va;
+ debug.req_pa <= request_pa;
+ debug.dout_reg <= cache_dout;
+ debug.ready <= cache_rdy;
+
+-------------------------------------------------
+-- ctrl
+-------------------------------------------------
+req_strobe <= cache_rdy and en;
+
+ctrl_request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if cache_rdy = '1' then
+ cache_req_rd <= en;
+ end if;
+ end if;
+ end process;
+
+-------------------------------------------------
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ request_va <= addr;
+ fill_word_index <= to_word_index(addr);
+ elsif bus_din_vld = '1' and fill_count_en = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+bus_request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if req_strobe = '1' then
+ req_word_index <= to_word_index(addr);
+ elsif request_count_en = '1' and bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ end if;
+ end process;
+
+single_read_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ elsif single_read_en = '0' then
+ if single_read_set = '1' then
+ single_read_en <= '1';
+ end if;
+ elsif single_read_reg_vld = '1' then
+ if en = '1' then
+ single_read_en <= '0';
+ single_read_reg_vld <= '0';
+ end if;
+ elsif bus_din_vld = '1' and single_read_en = '1' then
+ single_read_reg <= bus_din;
+ single_read_reg_vld <= '1';
+ end if;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(CACHE_SIZE),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_ctrl_state <= init;
+ cache_busy_state <= init;
+ else
+ cache_ctrl_state <= cache_ctrl_state_next;
+ cache_busy_state <= cache_busy_state_next;
+ end if;
+ end if;
+ end process;
+
+ bus_din_rdy <= fill_count_en or single_read_en;
+ bus_cmd_out.addr <= to_tag(request_pa) & to_cache_index(request_pa) & req_word_index & "00";
+ bus_cmd_out.rw <= '0';
+ bus_cmd_out.sel <= (others => '1');
+
+ cache_rdy <= read_rdy;
+ rdy <= cache_rdy;
+
+ cache_dout <= single_read_reg when single_read_en = '1' else data_ram_data_rd;
+ dout <= cache_dout;
+
+ cache_entry_out <= to_icache_entry(tag_ram_data_rd);
+ tag_match <= '1' when to_tag(request_pa) = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+
+ cache_entry_out_inv <= to_icache_entry(tag_ram_data_rd_inv);
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+
+ ram_read_en <= en or was_miss;
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else to_cache_index(request_va);
+ tag_ram_addr_rd <= to_cache_index(addr) when was_miss = '0' else to_cache_index(request_va);
+ data_ram_addr_rd <= (to_cache_index(addr) & to_word_index(addr)) when was_miss = '0' else (to_cache_index(request_va) & fill_word_index);
+ data_ram_addr_wr <= to_cache_index(request_va) & fill_word_index;
+ data_ram_data_wr <= bus_din;
+ data_ram_we <= ram_write_en and bus_din_vld;
+
+cache_busy_state_fsm:
+ process(cache_busy_state, tlb_result, cache_req_rd, cache_hit, mem_fetch_ack, single_read_en, single_read_reg_vld)
+ begin
+
+ read_rdy <= '0';
+ mem_fetch_req <= '0';
+ single_read_set <= '0';
+ cache_busy_state_next <= cache_busy_state;
+
+ case cache_busy_state is
+
+ when init =>
+ cache_busy_state_next <= ready;
+
+ when ready =>
+ if single_read_en = '1' then
+ read_rdy <= single_read_reg_vld;
+ else
+ read_rdy <= '1';
+ if cache_req_rd = '1' then
+ if tlb_result.hit = '1' then
+ if tlb_result.flags.N = '1' or cache_hit = '0' then
+ mem_fetch_req <= '1';
+ read_rdy <= '0';
+ single_read_set <= tlb_result.flags.N;
+ cache_busy_state_next <= busy;
+ end if;
+ end if;
+ end if;
+ end if;
+
+ when busy =>
+ mem_fetch_req <= '1';
+ if mem_fetch_ack = '1' then
+ cache_busy_state_next <= ready;
+ end if;
+
+ when others =>
+ cache_busy_state_next <= ready;
+
+ end case;
+
+ end process;
+
+cache_ctrl_state_fsm:
+ process(cache_ctrl_state, mem_fetch_req, tlb_result, bus_din_vld, cache_hit_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, request_pa, bus_cmd_rdy, invalidate_req, invalidate_all)
+ begin
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ ram_write_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+ mem_fetch_ack <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= to_tag(request_pa);
+ cache_entry_in.valid <= '0';
+ cache_ctrl_state_next <= cache_ctrl_state;
+
+ case cache_ctrl_state is
+
+ when init =>
+ cache_ctrl_state_next <= ready;
+
+ when ready =>
+ if invalidate_req = '1' then
+ cache_ctrl_state_next <= invalidate;
+ invalidate_en <= '1';
+ elsif mem_fetch_req = '1' then
+ cache_ctrl_state_next <= bus_request;
+ bus_cmd_cycle_en <= '1';
+ end if;
+
+ when invalidate =>
+ cache_ctrl_state_next <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ cache_ctrl_state_next <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ cache_ctrl_state_next <= invalidate_post;
+ end if;
+
+ when invalidate_post =>
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when bus_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ cache_ctrl_state_next <= mem_read;
+ if tlb_result.flags.N = '1' then
+ cache_ctrl_state_next <= mem_read_single;
+ end if;
+ end if;
+
+ when mem_read =>
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ request_count_en <= '1';
+ ram_write_en <= '1';
+ fill_count_en <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ cache_ctrl_state_next <= mem_read_data;
+ end if;
+
+ when mem_read_single =>
+ mem_fetch_ack <= '1';
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ cache_ctrl_state_next <= mem_read_data_single;
+
+ when mem_read_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ ram_write_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ cache_ctrl_state_next <= rd_cache;
+ end if;
+
+ when mem_read_data_single =>
+ bus_cmd_cycle_en <= '1';
+ if bus_din_vld = '1' then
+ cache_ctrl_state_next <= ready;
+ end if;
+
+ when rd_cache =>
+ mem_fetch_ack <= '1';
+ was_miss <= '1';
+ cache_ctrl_state_next <= ready;
+
+ when others =>
+ cache_ctrl_state_next <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_orig.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_orig.vhd
new file mode 100644
index 0000000..5be317f
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_icache_orig.vhd
@@ -0,0 +1,513 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_util_pkg.all;
+use work.mips_types.all;
+use work.busmaster_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8 -- words
+ );
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+
+ -- CPU control/data
+ en : in STD_LOGIC;
+ addr : in word_t;
+ dout : out word_t;
+ rdy : out STD_LOGIC;
+
+ -- Cache control
+ ctrl_in : in cache_ctrl_t;
+
+ tlb_query_out : out tlb_query_in_t;
+ tlb_query_in : in tlb_query_out_t;
+
+ -- busmaster arbitration
+ bus_req : out std_logic;
+ bus_gnt : in std_logic;
+
+ -- busmaster data
+ bus_din : in word_t;
+ bus_din_rdy : out std_logic;
+ bus_din_vld : in std_logic;
+
+-- bus_dout : out word_t;
+-- bus_dout_vld : out std_logic;
+-- bus_dout_rdy : in std_logic;
+
+ -- busmaster command
+ bus_cmd_rdy : in std_logic;
+ bus_cmd_we : out std_logic;
+ bus_cmd_cycle_en : out std_logic;
+ bus_cmd_out : out bm_cmd_t;
+ bus_cyc_complete : in std_logic
+
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ type cache_state_t is (init, ready, invalidate, flush, mem_request, mem_access, mem_data, rd_cache, upd_cache);
+ signal s, sn : cache_state_t;
+
+ signal cache_req : std_logic;
+ signal cache_ack : std_logic;
+ signal cache_busy : std_logic;
+ signal cache_miss : std_logic;
+ signal tag_match : std_logic;
+ signal cache_miss_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_addr : unsigned(addr_width-1 downto 0);
+ signal fill_addr : unsigned(addr_width-1 downto 0);
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ alias cpu_word_index is addr(word_index_width+1 downto 2);
+ alias cpu_cache_index is addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias cpu_tag is addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ alias fill_word_index is fill_addr(word_index_width+1 downto 2);
+ alias fill_cache_index is fill_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias fill_tag is fill_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ alias req_word_index is request_addr(word_index_width+1 downto 2);
+ alias req_cache_index is request_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias req_tag is request_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+begin
+
+ ram_read_en <= en or was_miss;
+ cache_index_inv <= ctrl_in.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl_in.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+
+fill_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '1' then
+ if bus_din_vld = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ elsif cache_busy = '0' then
+ fill_addr <= addr(addr_width-1 downto 2) & "00";
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '1'then
+ if bus_cmd_rdy = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ elsif cache_busy = '0' then
+ request_addr <= addr(addr_width-1 downto 2) & "00";
+ end if;
+ end if;
+ end process;
+
+cpu_request_register:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ cache_req <= '0';
+ elsif en = '1' then
+ if cache_busy = '0' then
+ cache_req <= '1';
+ end if;
+ elsif cache_ack = '1' then
+ cache_req <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' or ctrl_in.inv_all = '1' or ctrl_in.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl_in.inv_all or rst;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => clk,
+ clk_b => clk,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ s <= init;
+ else
+ s <= sn;
+ end if;
+ end if;
+ end process;
+
+ bus_din_rdy <= fill_count_en;
+ bus_cmd_out.addr <= fill_tag & fill_cache_index & req_word_index & "00";
+ bus_cmd_out.rw <= '0';
+ bus_cmd_out.sel <= (others => '0');
+
+ rdy <= not cache_busy;
+ dout <= data_ram_data_rd;
+
+ cache_entry_out <= to_icache_entry(tag_ram_data_rd);
+ tag_match <= '1' when fill_tag = cache_entry_out.tag else '0';
+ cache_miss <= not (tag_match and cache_entry_out.valid);
+
+ cache_entry_out_inv <= to_icache_entry(tag_ram_data_rd_inv);
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_miss_inv <= not (tag_match_inv and cache_entry_out_inv.valid);
+
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else fill_cache_index;
+ tag_ram_addr_rd <= cpu_cache_index when was_miss = '0' else fill_cache_index;
+ data_ram_addr_rd <= (cpu_cache_index & cpu_word_index) when was_miss = '0' else (fill_cache_index & fill_word_index);
+ data_ram_addr_wr <= fill_cache_index & fill_word_index;
+ data_ram_data_wr <= bus_din;
+ data_ram_we <= fill_count_en and bus_din_vld;
+
+cache_state:
+ process(s, cache_req, cache_miss, cache_miss_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, fill_tag, bus_cmd_rdy, invalidate_req, invalidate_all)
+ begin
+ cache_busy <= cache_req;
+ cache_ack <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ bus_cmd_cycle_en <= '0';
+ bus_cmd_we <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= fill_tag;
+ cache_entry_in.valid <= '0';
+ sn <= s;
+
+ case s is
+ when init =>
+ sn <= ready;
+ when ready =>
+ if invalidate_req = '1' then
+ sn <= invalidate;
+ invalidate_en <= '1';
+ elsif cache_req = '1' then
+ if cache_miss = '1' then
+ sn <= mem_request;
+ bus_cmd_cycle_en <= '1';
+ else
+ cache_busy <= '0';
+ cache_ack <= '1';
+ end if;
+ end if;
+ when invalidate =>
+ sn <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ sn <= flush;
+ flush_count_rst <= '1';
+ elsif cache_miss_inv = '0' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ sn <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ sn <= rd_cache;
+ end if;
+ when mem_request =>
+ bus_cmd_cycle_en <= '1';
+ if bus_cmd_rdy = '1' then
+ sn <= mem_access;
+ end if;
+ when mem_access =>
+ request_count_en <= '1';
+ fill_count_en <= '1';
+ bus_cmd_cycle_en <= '1';
+ bus_cmd_we <= '1';
+ if request_count_rdy = '1' then
+ bus_cmd_we <= '0';
+ sn <= mem_data;
+ end if;
+ when mem_data =>
+ bus_cmd_cycle_en <= '1';
+ fill_count_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ sn <= rd_cache;
+ end if;
+ when rd_cache =>
+ was_miss <= '1';
+ sn <= ready;
+ when others =>
+ sn <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if ctrl_in.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if bus_cmd_rdy = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(clk)
+ begin
+ if rising_edge(clk) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if bus_din_vld = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_tlb_types.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_tlb_types.vhd
new file mode 100644
index 0000000..9e6b1fc
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/old/mips_tlb_types.vhd
@@ -0,0 +1,83 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: Types, constants and functions for JIPS
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_util_pkg.all;
+
+--------------------------------------------------------------------------
+package tlb_types is
+
+
+-- constant TLB_PAGE_SIZE : positive := 4096;
+-- constant TLB_NUM_ASIDS : positive := 64;
+-- constant TLB_NUM_ENTRIES : positive := 32;
+
+ --Types
+-- type tlb_flags_t is record
+-- N : std_logic;
+-- D : std_logic;
+-- V : std_logic;
+-- end record;
+--
+-- type tlb_entry_lo_t is record
+-- PFN : unsigned (31 downto lg2(TLB_PAGE_SIZE));
+-- N : std_logic;
+-- D : std_logic;
+-- V : std_logic;
+-- end record;
+--
+-- type tlb_entry_hi_t is record
+-- VPN : unsigned (31 downto lg2(TLB_PAGE_SIZE));
+-- ASID : unsigned (lg2(TLB_NUM_ASIDS)-1 downto 0);
+-- G : std_logic;
+-- end record;
+
+ -- Functions
+ function "or" (a, b : tlb_flags_t) return tlb_flags_t;
+
+end tlb_types;
+
+--------------------------------------------------------------------------
+package body tlb_types is
+
+ function "or" (a, b : tlb_flags_t) return tlb_flags_t is
+ variable result : tlb_flags_t;
+ begin
+ result.N := a.N or b.N;
+ result.D := a.D or b.D;
+ result.V := a.V or b.V;
+
+ return result;
+
+ end "or";
+
+end tlb_types;
+
+--------------------------------------------------------------------------
+
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/test.vhd b/lib/CPUs/MIPS/src/core/MMU/TLB/test.vhd
new file mode 100644
index 0000000..44a4c4a
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/test.vhd
@@ -0,0 +1,73 @@
+
+entity dpram_1w1r2c_ra is
+ Generic (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ Port (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+end dpram_1w1r2c_ra;
+
+
+
+
+
+-------------------------------------------
+-- to_component
+-------------------------------------------
+-- case insensitive
+-- regexp
+-- text
+
+GENERIC
+GENERIC
+
+PORT
+PORT
+
+^ENTITY
+COMPONENT
+
+ +IS
+{empty}
+
+
+^.*END.*
+END COMPONENT;
+
+-------------------------------------------
+-- to_portmap
+-------------------------------------------
+-- case insensitive
+-- regexp
+-- text
+
+GENERIC
+GENERIC MAP
+
+PORT
+PORT MAP
+
+: +.*;
+=>,
+
+: +.*
+=>
+
+\(\<.*[^ \t]*.*\>\)[ \t,]*=>
+\1\t=>\t\1
+
+^ENTITY[ \t]+\([^ ].*[^ ]\) .*IS
+inst_\1: \1
+
+^END +.*$
+{empty}
diff --git a/lib/CPUs/MIPS/src/core/MMU/TLB/todo_txt.txt b/lib/CPUs/MIPS/src/core/MMU/TLB/todo_txt.txt
new file mode 100644
index 0000000..2e42e95
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/TLB/todo_txt.txt
@@ -0,0 +1,9 @@
+pipeline:
+ - privileged_address exc. also for dmem
+
+cop:
+- assign badVaddr for exc. SYS, RI, BP
+
+libsys.c, xcpt.c
+- INT exc. handler nicht hard-codieren
+- Bei libsys_init als standard int. exc. handler registrieren
\ No newline at end of file
diff --git a/lib/CPUs/MIPS/src/core/MMU/mips_biu.vhd b/lib/CPUs/MIPS/src/core/MMU/mips_biu.vhd
new file mode 100644
index 0000000..874ac5c
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/mips_biu.vhd
@@ -0,0 +1,552 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.numeric_std.ALL;
+
+library work;
+use work.mips_types.all;
+
+entity biu is
+ Generic
+ (
+ icache_size : natural := 2048; -- words
+ icache_line : natural := 8; -- words
+ dcache_size : natural := 2048; -- words
+ dcache_line : natural := 8 -- words
+ );
+ Port
+ (
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ ADDR_O : out unsigned(31 downto 0);
+ DAT_I : in unsigned(31 downto 0);
+ DAT_O : out unsigned(31 downto 0);
+ WE_O : out STD_LOGIC;
+ SEL_O : out unsigned(3 downto 0);
+ CYC_O : out STD_LOGIC;
+ STB_O : out STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+ cop0_ctrl_in : in cop0_ctrl_out_t;
+ cpu_clk : in STD_LOGIC;
+ cpu_imem_err : out STD_LOGIC;
+ cpu_imem_rdy : out STD_LOGIC;
+ cpu_imem_en : in STD_LOGIC;
+ cpu_imem_addr : in word_t;
+ cpu_imem_din : out word_t;
+ cpu_dmem_err : out STD_LOGIC;
+ cpu_dmem_rdy : out STD_LOGIC;
+ cpu_dmem_en : in STD_LOGIC;
+ cpu_dmem_we : in STD_LOGIC;
+ cpu_dmem_be : in unsigned(3 downto 0);
+ cpu_dmem_dout : in word_t;
+ cpu_dmem_din : out word_t;
+ cpu_dmem_addr : in word_t
+ );
+end biu;
+
+architecture behavior of biu is
+
+ COMPONENT icache
+ GENERIC
+ (
+ cache_size : natural; -- words
+ line_size : natural -- words
+ );
+ PORT
+ (
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+ ADDR_O : out word_t;
+ DAT_I : in word_t;
+ STB_O : out STD_LOGIC;
+ CYC_O : out STD_LOGIC;
+ ctrl : in cache_ctrl_t;
+ cpu_en : in STD_LOGIC;
+ cpu_addr : in word_t;
+ cpu_dout : out word_t;
+ cpu_busy : out STD_LOGIC
+ );
+ END COMPONENT;
+
+ COMPONENT dcache
+ GENERIC
+ (
+ cache_size : natural; -- words
+ line_size : natural -- words
+ );
+ PORT
+ (
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+ ADDR_O : out word_t;
+ DAT_I : in word_t;
+ STB_O : out STD_LOGIC;
+ CYC_O : out STD_LOGIC;
+ ctrl : in cache_ctrl_t;
+ cpu_en : in STD_LOGIC;
+ cpu_we : in STD_LOGIC;
+ cpu_be : in unsigned(3 downto 0);
+ cpu_addr : in word_t;
+ cpu_din : in word_t;
+ cpu_dout : out word_t;
+ cpu_busy : out STD_LOGIC
+ );
+ END COMPONENT;
+
+ type bus_state_t is (init, ready, icache_bus_access, dcache_bus_access, write_bus, read_bus, read_finish);
+
+ signal s, sn : bus_state_t;
+ signal bus_idle : std_logic;
+ signal busy : std_logic;
+ signal dmem_be : unsigned(3 downto 0);
+ signal dcache_dout : word_t;
+ signal dcache_mem_gnt : std_logic;
+ signal icache_mem_gnt : std_logic;
+ signal dmem_mem_wr_gnt : std_logic;
+ signal dmem_mem_rd_gnt : std_logic;
+ signal dcache_busy : std_logic;
+ signal icache_busy : std_logic;
+ signal CYC_O_icache : std_logic;
+ signal CYC_O_dcache : std_logic;
+ signal CYC_O_dmem_rd : std_logic;
+ signal CYC_O_dmem_wr : std_logic;
+ signal SRDY_I_icache : std_logic;
+ signal SRDY_I_dcache : std_logic;
+ signal MRDY_O_icache : std_logic;
+ signal MRDY_O_dcache : std_logic;
+ signal ADDR_O_icache : word_t;
+ signal ADDR_O_dcache : word_t;
+ signal ADDR_O_dmem_rd : word_t;
+ signal ADDR_O_dmem_wr : word_t;
+ signal STB_O_icache : std_logic;
+ signal STB_O_dcache : std_logic;
+ signal STB_O_dmem_rd : std_logic;
+ signal STB_O_dmem_wr : std_logic;
+ signal DAT_I_dmem_rd : word_t;
+ signal DAT_O_dmem_wr : word_t;
+ signal SEL_O_dmem_wr : unsigned(3 downto 0);
+ signal SEL_O_dmem_rd : unsigned(3 downto 0);
+ signal dcached : std_logic;
+ signal dcache_en2 : std_logic;
+ signal dcache_en : std_logic;
+ signal uncached_access : std_logic;
+ signal ACK : std_logic;
+ signal DAT : unsigned(31 downto 0);
+
+ type timeout_cnt_t is range 0 to 1E5-1;
+ signal bus_timeout_cnt : timeout_cnt_t;
+ signal bus_timeout : std_logic;
+
+ signal bout_fifo_din : unsigned(68 downto 0);
+ signal bout_fifo_dout : unsigned(68 downto 0);
+ signal bout_fifo_re : std_logic;
+ signal bout_fifo_we : std_logic;
+ signal bout_fifo_full : std_logic;
+ signal bout_fifo_empty : std_logic;
+ signal bout_rdy : std_logic;
+
+ signal bin_fifo_din : unsigned(31 downto 0);
+ signal bin_fifo_dout : unsigned(31 downto 0);
+ signal bin_fifo_re : std_logic;
+ signal bin_fifo_we : std_logic;
+ signal bin_fifo_full : std_logic;
+ signal bin_fifo_empty : std_logic;
+
+ alias bout_fifo_addr_in is bout_fifo_din(31 downto 0);
+ alias bout_fifo_data_in is bout_fifo_din(63 downto 32);
+ alias bout_fifo_sel_in is bout_fifo_din(67 downto 64);
+ alias bout_fifo_we_in is bout_fifo_din(68);
+ alias bout_fifo_addr_out is bout_fifo_dout(31 downto 0);
+ alias bout_fifo_data_out is bout_fifo_dout(63 downto 32);
+ alias bout_fifo_sel_out is bout_fifo_dout(67 downto 64);
+ alias bout_fifo_we_out is bout_fifo_dout(68);
+
+ signal write_fifo_din : unsigned(67 downto 0);
+ signal write_fifo_dout : unsigned(67 downto 0);
+ signal write_fifo_re : std_logic;
+ signal write_fifo_we : std_logic;
+ signal write_fifo_full : std_logic;
+ signal write_fifo_empty : std_logic;
+
+ alias write_fifo_addr_in is write_fifo_din(31 downto 0);
+ alias write_fifo_data_in is write_fifo_din(63 downto 32);
+ alias write_fifo_sel_in is write_fifo_din(67 downto 64);
+ alias write_fifo_addr_out is write_fifo_dout(31 downto 0);
+ alias write_fifo_data_out is write_fifo_dout(63 downto 32);
+ alias write_fifo_sel_out is write_fifo_dout(67 downto 64);
+
+ signal read_cycle : std_logic;
+
+begin
+
+read_cyc_register:
+ process(cpu_clk)
+ begin
+ if rising_edge(cpu_clk) then
+ if RST_I = '1' then
+ read_cycle <= '0';
+ else
+ read_cycle <= (dmem_mem_rd_gnt and CYC_O_dmem_rd)
+ or (dcache_mem_gnt and CYC_O_dcache)
+ or (icache_mem_gnt and CYC_O_icache);
+ end if;
+ end if;
+ end process;
+
+ MRDY_O <= not bin_fifo_full;
+ CYC_O <= not bout_fifo_empty or read_cycle;
+ STB_O <= not bout_fifo_empty;
+ ADDR_O <= bout_fifo_addr_out;
+ DAT_O <= bout_fifo_data_out;
+ SEL_O <= bout_fifo_sel_out;
+ WE_O <= bout_fifo_we_out;
+
+ cpu_imem_rdy <= not icache_busy after 4.5 ns;
+ busy <= CYC_O_dmem_rd or dcache_busy or (write_fifo_full);
+ cpu_dmem_rdy <= not busy after 4.5 ns;
+
+inst_icache : icache
+ GENERIC MAP
+ (
+ cache_size => icache_size, -- words
+ line_size => icache_line -- words
+ )
+ PORT MAP
+ (
+ CLK_I => cpu_clk,
+ RST_I => RST_I,
+ STB_O => STB_O_icache,
+ CYC_O => CYC_O_icache,
+ ADDR_O => ADDR_O_icache,
+ MRDY_O => MRDY_O_icache,
+ DAT_I => DAT,
+ ACK_I => ACK,
+ SRDY_I => SRDY_I_icache,
+ ctrl => cop0_ctrl_in.icache,
+ cpu_en => cpu_imem_en,
+ cpu_addr => cpu_imem_addr,
+ cpu_dout => cpu_imem_din,
+ cpu_busy => icache_busy
+ );
+
+ SRDY_I_icache <= bout_rdy and icache_mem_gnt;
+
+inst_dcache : dcache
+ GENERIC MAP
+ (
+ cache_size => dcache_size, -- words
+ line_size => dcache_line -- words
+ )
+ PORT MAP
+ (
+ CLK_I => cpu_clk,
+ RST_I => RST_I,
+ CYC_O => CYC_O_dcache,
+ STB_O => STB_O_dcache,
+ ADDR_O => ADDR_O_dcache,
+ MRDY_O => MRDY_O_dcache,
+ DAT_I => DAT,
+ ACK_I => ACK,
+ SRDY_I => SRDY_I_dcache,
+ ctrl => cop0_ctrl_in.dcache,
+ cpu_en => dcache_en,
+ cpu_we => cpu_dmem_we,
+ cpu_be => cpu_dmem_be,
+ cpu_addr => cpu_dmem_addr,
+ cpu_din => cpu_dmem_dout,
+ cpu_dout => dcache_dout,
+ cpu_busy => dcache_busy
+ );
+
+ SRDY_I_dcache <= bout_rdy and dcache_mem_gnt;
+
+ dcached <= '1' when cpu_dmem_addr(31 downto 29) /= "101" else '0';
+ cpu_dmem_din <= dcache_dout when uncached_access = '0' else DAT_I_dmem_rd;
+ dcache_en <= dcached and cpu_dmem_en and dcache_en2; -- or write_fifo_full);
+
+-- Instantiate synchronous FIFO
+inst_bin_fifo: entity work.fifo_async
+ GENERIC MAP
+ (
+ addr_width => 4,
+ data_width => 32,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => RST_I,
+ clk_w => CLK_I,
+ clk_r => cpu_clk,
+ we => bin_fifo_we,
+ re => bin_fifo_re,
+ fifo_full => bin_fifo_full,
+ fifo_empty => bin_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => bin_fifo_din,
+ data_r => bin_fifo_dout
+ );
+
+ bin_fifo_din <= DAT_I;
+ DAT <= bin_fifo_dout;
+ ACK <= not bin_fifo_empty;
+ bin_fifo_we <= ACK_I;
+ bin_fifo_re <= dmem_mem_rd_gnt or MRDY_O_icache or MRDY_O_dcache;
+
+-- Instantiate synchronous FIFO
+inst_bout_fifo: entity work.fifo_async
+ GENERIC MAP
+ (
+ addr_width => 4,
+ data_width => 69,
+ do_last_read_update => false
+ )
+ PORT MAP
+ (
+ rst => RST_I,
+ clk_w => cpu_clk,
+ clk_r => CLK_I,
+ we => bout_fifo_we,
+ re => bout_fifo_re,
+ fifo_full => bout_fifo_full,
+ fifo_empty => bout_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => bout_fifo_din,
+ data_r => bout_fifo_dout
+ );
+ bout_rdy <= not bout_fifo_full;
+ bout_fifo_re <= SRDY_I and not bin_fifo_full;
+
+ bout_fifo_we <= STB_O_dmem_wr or STB_O_dmem_rd or STB_O_dcache or STB_O_icache;
+
+ bout_fifo_data_in <= DAT_O_dmem_wr when dmem_mem_wr_gnt = '1' else (others => '-');
+
+ bout_fifo_addr_in <= ADDR_O_dmem_wr when dmem_mem_wr_gnt = '1' else
+ ADDR_O_dmem_rd when dmem_mem_rd_gnt = '1' else
+ ADDR_O_dcache when dcache_mem_gnt = '1' else
+ ADDR_O_icache when icache_mem_gnt = '1' else (others => '-');
+
+ bout_fifo_sel_in <= SEL_O_dmem_wr when dmem_mem_wr_gnt = '1' else
+ SEL_O_dmem_rd when dmem_mem_rd_gnt = '1' else (others => '1');
+
+ bout_fifo_we_in <= '1' when dmem_mem_wr_gnt = '1' else '0';
+
+-- Instantiate synchronous FIFO
+inst_write_fifo: entity work.fifo_sync
+ GENERIC MAP
+ (
+ addr_width => 4,
+ data_width => 68,
+ do_last_read_update => true
+ )
+ PORT MAP
+ (
+ rst => RST_I,
+ clk => cpu_clk,
+ we => write_fifo_we,
+ re => write_fifo_re,
+ fifo_full => write_fifo_full,
+ fifo_empty => write_fifo_empty,
+ fifo_afull => open,
+ fifo_aempty => open,
+ data_w => write_fifo_din,
+ data_r => write_fifo_dout
+ );
+
+ CYC_O_dmem_wr <= not write_fifo_empty;
+ DAT_O_dmem_wr <= write_fifo_data_out;
+ ADDR_O_dmem_wr <= write_fifo_addr_out;
+ SEL_O_dmem_wr <= write_fifo_sel_out;
+
+ write_fifo_data_in <= cpu_dmem_dout;
+ write_fifo_addr_in <= cpu_dmem_addr;
+ write_fifo_sel_in <= cpu_dmem_be;
+ write_fifo_re <= STB_O_dmem_wr;
+ write_fifo_we <= cpu_dmem_en and not busy and cpu_dmem_we;
+
+dmem_rd_flags:
+ process(cpu_clk)
+ begin
+ if rising_edge(cpu_clk) then
+ uncached_access <= '0';
+ if RST_I = '1' then
+ CYC_O_dmem_rd <= '0';
+ dcache_en2 <= '1';
+ else
+ if ACK = '1' and dmem_mem_rd_gnt = '1' then
+ uncached_access <= '1';
+ CYC_O_dmem_rd <= '0';
+ dcache_en2 <= '1';
+ end if;
+ if cpu_dmem_en = '1' and busy = '0' and cpu_dmem_we = '0' then
+ if dcached = '0' then
+ CYC_O_dmem_rd <= '1';
+ dcache_en2 <= '0';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+dmem_rd_data:
+ process(cpu_clk)
+ begin
+ if rising_edge(cpu_clk) then
+ if RST_I = '1' then
+ DAT_I_dmem_rd <= (others => '0');
+ elsif ACK = '1' and CYC_O_dmem_rd = '1' then
+ DAT_I_dmem_rd <= DAT;
+ end if;
+ end if;
+ end process;
+
+dmem_rd_regs:
+ process(cpu_clk)
+ begin
+ if rising_edge(cpu_clk) then
+ if cpu_dmem_en = '1' and busy = '0' then
+ ADDR_O_dmem_rd <= cpu_dmem_addr;
+ SEL_O_dmem_rd <= cpu_dmem_be;
+ end if;
+ end if;
+ end process;
+
+bus_state_next:
+ process(cpu_clk)
+ begin
+ if rising_edge(cpu_clk) then
+ if RST_I = '1' then
+ s <= init;
+ else
+ s <= sn;
+ end if;
+ end if;
+ end process;
+
+bus_state:
+ process(s, CYC_O_icache, CYC_O_dcache, CYC_O_dmem_wr, CYC_O_dmem_rd, bout_rdy, ACK)
+ begin
+
+ icache_mem_gnt <= '0';
+ dcache_mem_gnt <= '0';
+ dmem_mem_rd_gnt <= '0';
+ dmem_mem_wr_gnt <= '0';
+ STB_O_dmem_rd <= '0';
+ STB_O_dmem_wr <= '0';
+ bus_idle <= '0';
+ sn <= s;
+ case s is
+ when init =>
+ sn <= ready;
+ when ready =>
+ bus_idle <= '1';
+ if CYC_O_dmem_wr = '1' then
+ sn <= write_bus;
+ elsif CYC_O_dmem_rd = '1' then
+ sn <= read_bus;
+ elsif CYC_O_icache = '1' then
+ sn <= icache_bus_access;
+ elsif CYC_O_dcache = '1' then
+ sn <= dcache_bus_access;
+ end if;
+ when icache_bus_access =>
+ icache_mem_gnt <= '1';
+ if CYC_O_icache = '0' then
+ sn <= ready;
+ end if;
+ when dcache_bus_access =>
+ dcache_mem_gnt <= '1';
+ if CYC_O_dcache = '0' then
+ sn <= ready;
+ end if;
+ when write_bus =>
+ dmem_mem_wr_gnt <= '1';
+ if CYC_O_dmem_wr = '1' then
+ if bout_rdy = '1' then
+ STB_O_dmem_wr <= '1';
+ end if;
+ else
+ sn <= ready;
+ end if;
+ when read_bus =>
+ dmem_mem_rd_gnt <= '1';
+ if bout_rdy = '1' then
+ STB_O_dmem_rd <= '1';
+ sn <= read_finish;
+ end if;
+ when read_finish =>
+ dmem_mem_rd_gnt <= '1';
+ if ACK = '1' then
+ sn <= ready;
+ end if;
+ when others =>
+ sn <= ready;
+ end case;
+
+ end process;
+
+bus_timeout_counter:
+ process(cpu_clk)
+ begin
+ if rising_edge(cpu_clk) then
+ if bus_idle = '0' then
+ if bus_timeout_cnt /= 0 then
+ bus_timeout_cnt <= bus_timeout_cnt - 1;
+ else
+ bus_timeout <= '1';
+ end if;
+ else
+ bus_timeout_cnt <= timeout_cnt_t'high;
+ bus_timeout <= '0';
+ end if;
+ end if;
+ end process;
+
+bus_err:
+ process(cpu_clk)
+ begin
+ if rising_edge(cpu_clk) then
+ if RST_I = '1' then
+ cpu_imem_err <= '0';
+ cpu_dmem_err <= '0';
+ elsif bus_timeout = '1' then
+ cpu_imem_err <= icache_mem_gnt;
+ cpu_dmem_err <= dcache_mem_gnt or dmem_mem_wr_gnt or dmem_mem_rd_gnt;
+ end if;
+ end if;
+ end process;
+
+-------------------------------------------------------------------
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/mips_dcache.vhd b/lib/CPUs/MIPS/src/core/MMU/mips_dcache.vhd
new file mode 100644
index 0000000..61aca40
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/mips_dcache.vhd
@@ -0,0 +1,513 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+
+ENTITY dcache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8 -- words
+ );
+ Port
+ (
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+ ADDR_O : out word_t;
+ DAT_I : in word_t;
+ STB_O : out STD_LOGIC;
+ CYC_O : out STD_LOGIC;
+ ctrl : in cache_ctrl_t;
+ cpu_en : in STD_LOGIC;
+ cpu_we : in STD_LOGIC;
+ cpu_be : in unsigned(3 downto 0);
+ cpu_addr : in word_t;
+ cpu_din : in word_t;
+ cpu_dout : out word_t;
+ cpu_busy : out STD_LOGIC
+ );
+END dcache;
+
+ARCHITECTURE behavior OF dcache IS
+
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type dcache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_dcache_entry(x : tag_ram_data_t) return dcache_entry_t is
+ variable result : dcache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_dcache_entry;
+
+ function to_tag_ram_data(x : dcache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ type cache_state_t is (init, ready, invalidate, flush, mem_request, mem_access, mem_data, rd_cache);
+ signal s, sn : cache_state_t;
+
+ signal cache_req : std_logic;
+ signal cache_ack : std_logic;
+ signal cache_busy : std_logic;
+ signal cache_hit : std_logic;
+ signal tag_match : std_logic;
+ signal cache_hit_inv : std_logic;
+ signal tag_match_inv : std_logic;
+
+ signal request_addr : unsigned(addr_width-1 downto 0);
+ signal fill_addr : unsigned(addr_width-1 downto 0);
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : dcache_entry_t;
+ signal cache_entry_out : dcache_entry_t;
+ signal cache_entry_out_inv : dcache_entry_t;
+ signal cpu_data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal cpu_data_ram_dout : word_t;
+ signal cpu_data_reg : word_t;
+ signal cpu_be_reg : unsigned(3 downto 0);
+ signal cpu_we_reg : std_logic;
+ signal ctrl_data_ram_addr : unsigned(lg2(cache_size)-1 downto 0);
+ signal ctrl_data_ram_we : unsigned(3 downto 0);
+ signal cpu_data_ram_we : unsigned(3 downto 0);
+ signal cpu_we2 : std_logic;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_dout : tag_ram_data_t;
+ signal tag_ram_dout_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_din : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+ signal cpu_hit_we : std_logic;
+ signal instant_raw : std_logic;
+ signal hit_cache_index : unsigned(cache_index_width-1 downto 0);
+
+ alias cpu_word_index is cpu_addr(word_index_width+1 downto 2);
+ alias cpu_cache_index is cpu_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias cpu_tag is cpu_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ alias fill_word_index is fill_addr(word_index_width+1 downto 2);
+ alias fill_cache_index is fill_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias fill_tag is fill_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ alias req_word_index is request_addr(word_index_width+1 downto 2);
+ alias req_cache_index is request_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias req_tag is request_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+begin
+
+ cache_index_inv <= ctrl.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ cpu_hit_we <= cpu_we2 and cache_hit;
+
+fill_address_register:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if fill_count_en = '1' then
+ if ACK_I = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ elsif cache_busy = '0' then
+ fill_addr <= cpu_addr(addr_width-1 downto 2) & "00";
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if request_count_en = '1'then
+ if SRDY_I = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ elsif cache_busy = '0' then
+ request_addr <= cpu_addr(addr_width-1 downto 2) & "00";
+ end if;
+ end if;
+ end process;
+
+cpu_request_register:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if RST_I = '1' then
+ cpu_we_reg <= '0';
+ cache_req <= '0';
+ elsif cpu_en = '1' then
+ if cache_busy = '0' then
+ cpu_we2 <= cpu_we;
+ cache_req <= '1';
+ cpu_data_reg <= cpu_din;
+ cpu_be_reg <= cpu_be;
+ cpu_we_reg <= cpu_we;
+ if cpu_we = '1' then
+ hit_cache_index <= cpu_cache_index;
+ end if;
+ end if;
+ elsif cache_ack = '1' then
+ cache_req <= '0';
+ cpu_we2 <= '0';
+ end if;
+ end if;
+ end process;
+
+instant_raw_logic:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ instant_raw <= '0';
+ if cpu_word_index = fill_word_index and cpu_cache_index = hit_cache_index then
+ instant_raw <= cpu_hit_we and cpu_en and not cpu_we;
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => CLK_I,
+ clk_b => CLK_I,
+ en_a => '1',
+ en_b => '1',
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_din,
+ din_b => tag_ram_din,
+ dout_a => tag_ram_dout_inv,
+ dout_b => tag_ram_dout
+ );
+
+gen_data_ram:
+ for i in 0 to 3 generate
+ begin
+
+ inst_data_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length/4
+ )
+ PORT MAP
+ (
+ clk_a => CLK_I,
+ clk_b => CLK_I,
+ en_a => '1',
+ en_b => '1',
+ we_a => cpu_data_ram_we(i),
+ we_b => ctrl_data_ram_we(i),
+ addr_a => ctrl_data_ram_addr,
+ addr_b => cpu_data_ram_addr,
+ din_a => cpu_data_reg(8*(i+1)-1 downto 8*i),
+ din_b => DAT_I(8*(i+1)-1 downto 8*i),
+ dout_a => open,
+ dout_b => cpu_data_ram_dout(8*(i+1)-1 downto 8*i)
+ );
+ end generate;
+
+
+
+cache_invalidate_request:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if RST_I = '1' or ctrl.inv_all = '1' or ctrl.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl.inv_all or RST_I;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_state_next:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if RST_I = '1' then
+ s <= init;
+ else
+ s <= sn;
+ end if;
+ end if;
+ end process;
+
+ MRDY_O <= fill_count_en;
+ ADDR_O <= request_addr;
+
+ cpu_busy <= cache_busy;
+ cpu_dout <= cpu_data_ram_dout;
+
+ tag_match <= '1' when fill_tag = cache_entry_out.tag else '0';
+ cache_hit <= tag_match and cache_entry_out.valid;
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_hit_inv <= tag_match_inv and cache_entry_out_inv.valid;
+ tag_ram_din <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else fill_cache_index;
+ tag_ram_addr_rd <= cpu_cache_index when (was_miss = '0' and instant_raw = '0') else fill_cache_index;
+
+ cache_entry_out <= to_dcache_entry(tag_ram_dout);
+ cache_entry_out_inv <= to_dcache_entry(tag_ram_dout_inv);
+
+ cpu_data_ram_addr <= (cpu_cache_index & cpu_word_index) when (was_miss = '0' and instant_raw = '0' and fill_count_en = '0') else (fill_cache_index & fill_word_index);
+ ctrl_data_ram_addr <= fill_cache_index & fill_word_index;
+ ctrl_data_ram_we <= (others => fill_count_en and ACK_I);
+ cpu_data_ram_we <= cpu_be_reg when (cpu_hit_we = '1') else (others => '0');
+
+cache_state:
+ process(s, cache_req, instant_raw, cache_hit, cache_hit_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, fill_tag, SRDY_I, cpu_we_reg, invalidate_req, invalidate_all)
+ begin
+ cache_busy <= cache_req;
+ cache_ack <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ CYC_O <= '0';
+ STB_O <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= fill_tag;
+ cache_entry_in.valid <= '0';
+ sn <= s;
+
+ case s is
+ when init =>
+ sn <= ready;
+ when ready =>
+ if invalidate_req = '1' then
+ sn <= invalidate;
+ invalidate_en <= '1';
+ else
+ if cache_req = '1' then
+ if cache_hit = '0' and cpu_we_reg = '0' then
+ sn <= mem_request;
+ CYC_O <= '1';
+ else
+ cache_busy <= instant_raw;
+ cache_ack <= not instant_raw;
+ end if;
+ end if;
+ end if;
+ when invalidate =>
+ sn <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ sn <= flush;
+ flush_count_rst <= '1';
+ elsif cache_hit_inv = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ sn <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ sn <= rd_cache;
+ end if;
+ when mem_request =>
+ CYC_O <= '1';
+ if SRDY_I = '1' then
+ sn <= mem_access;
+ end if;
+ when mem_access =>
+ fill_count_en <= '1';
+ request_count_en <= '1';
+ CYC_O <= '1';
+ STB_O <= '1';
+ if request_count_rdy = '1' then
+ STB_O <= '0';
+ sn <= mem_data;
+ end if;
+ when mem_data =>
+ CYC_O <= '1';
+ fill_count_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ sn <= rd_cache;
+ end if;
+ when rd_cache =>
+ was_miss <= '1';
+ sn <= ready;
+
+ when others =>
+ sn <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if ctrl.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if SRDY_I = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if ACK_I = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/mips_icache.vhd b/lib/CPUs/MIPS/src/core/MMU/mips_icache.vhd
new file mode 100644
index 0000000..0d93e18
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/mips_icache.vhd
@@ -0,0 +1,488 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: JIPS top file
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.mips_types.all;
+
+ENTITY icache IS
+ Generic
+ (
+ cache_size : natural := 2048; -- words
+ line_size : natural := 8 -- words
+ );
+ Port
+ (
+ RST_I : in STD_LOGIC;
+ CLK_I : in STD_LOGIC;
+ ACK_I : in STD_LOGIC;
+ SRDY_I : in STD_LOGIC;
+ MRDY_O : out STD_LOGIC;
+ ADDR_O : out word_t;
+ DAT_I : in word_t;
+ STB_O : out STD_LOGIC;
+ CYC_O : out STD_LOGIC;
+ ctrl : in cache_ctrl_t;
+ cpu_en : in STD_LOGIC;
+ cpu_addr : in word_t;
+ cpu_dout : out word_t;
+ cpu_busy : out STD_LOGIC
+ );
+END icache;
+
+ARCHITECTURE behavior OF icache IS
+
+COMPONENT dpram_1w1r2c_ra
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+COMPONENT dpram_2w2r2c_ra is
+ GENERIC
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ PORT
+ (
+ clk_a : in STD_LOGIC;
+ clk_b : in STD_LOGIC;
+ en_a : in STD_LOGIC;
+ en_b : in STD_LOGIC;
+ we_a : in STD_LOGIC;
+ we_b : in STD_LOGIC;
+ addr_a : in unsigned (addr_width-1 downto 0);
+ addr_b : in unsigned (addr_width-1 downto 0);
+ din_a : in unsigned (data_width-1 downto 0);
+ din_b : in unsigned (data_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+END COMPONENT;
+
+ constant addr_width : natural := 32;
+ constant word_index_width : natural := lg2(line_size);
+ constant cache_index_width : natural := lg2(cache_size) - word_index_width;
+ constant tag_width : natural := addr_width - word_index_width - cache_index_width - 2;
+ constant tag_parity_width : natural := 3;
+ constant tag_ram_data_width : natural := 1 + tag_parity_width + tag_width;
+ constant tag_ram_addr_width : natural := cache_index_width;
+
+ subtype tag_ram_data_t is unsigned (tag_ram_data_width-1 downto 0);
+
+ type icache_entry_t is record
+ valid : std_logic;
+ tv_p : unsigned(tag_parity_width-1 downto 0);
+ tag : unsigned(tag_width-1 downto 0);
+ end record;
+
+ function to_icache_entry(x : tag_ram_data_t) return icache_entry_t is
+ variable result : icache_entry_t;
+ begin
+ result.valid := x(0);
+ result.tv_p := x(3 downto 1);
+ result.tag := x(tag_width+3 downto 4);
+
+ return result;
+ end to_icache_entry;
+
+ function to_tag_ram_data(x : icache_entry_t) return tag_ram_data_t is
+ variable result : tag_ram_data_t;
+ begin
+ result(0) := x.valid;
+ result(3 downto 1) := x.tv_p;
+ result(tag_width+3 downto 4) := x.tag;
+
+ return result;
+ end to_tag_ram_data;
+
+ type cache_state_t is (init, ready, invalidate, flush, mem_request, mem_access, mem_data, rd_cache, upd_cache);
+ signal s, sn : cache_state_t;
+
+ signal cache_req : std_logic;
+ signal cache_ack : std_logic;
+ signal cache_busy : std_logic;
+ signal cache_miss : std_logic;
+ signal tag_match : std_logic;
+ signal cache_miss_inv : std_logic;
+ signal tag_match_inv : std_logic;
+ signal request_addr : unsigned(addr_width-1 downto 0);
+ signal fill_addr : unsigned(addr_width-1 downto 0);
+
+ signal cache_index_inv : unsigned(cache_index_width-1 downto 0);
+ signal tag_inv : unsigned(tag_width-1 downto 0);
+ signal tag_reg_inv : unsigned(tag_width-1 downto 0);
+
+ signal cache_entry_in : icache_entry_t;
+ signal cache_entry_out : icache_entry_t;
+ signal cache_entry_out_inv : icache_entry_t;
+ signal data_ram_addr_rd : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_rd : word_t;
+ signal data_ram_addr_wr : unsigned(lg2(cache_size)-1 downto 0);
+ signal data_ram_data_wr : word_t;
+ signal data_ram_we : std_logic;
+
+ signal tag_ram_addr_rd : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_rd : tag_ram_data_t;
+ signal tag_ram_data_rd_inv : tag_ram_data_t;
+ signal tag_ram_addr_wr : unsigned(cache_index_width-1 downto 0);
+ signal tag_ram_data_wr : tag_ram_data_t;
+ signal tag_ram_we : std_logic;
+
+ signal fill_count : natural range 0 to 2**word_index_width-1;
+ signal fill_count_en : std_logic;
+ signal fill_count_rdy : std_logic;
+ signal flush_count : natural range 0 to 2**cache_index_width-1;
+ signal flush_count_rst : std_logic;
+ signal flush_count_en : std_logic;
+ signal flush_count_rdy : std_logic;
+ signal request_count : natural range 0 to 2**word_index_width-1;
+ signal request_count_en : std_logic;
+ signal request_count_rdy : std_logic;
+ signal ram_read_en : std_logic;
+ signal was_miss : std_logic;
+ signal invalidate_all : std_logic;
+ signal invalidate_ack : std_logic;
+ signal invalidate_en : std_logic;
+ signal invalidate_req : std_logic;
+
+ alias cpu_word_index is cpu_addr(word_index_width+1 downto 2);
+ alias cpu_cache_index is cpu_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias cpu_tag is cpu_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ alias fill_word_index is fill_addr(word_index_width+1 downto 2);
+ alias fill_cache_index is fill_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias fill_tag is fill_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+ alias req_word_index is request_addr(word_index_width+1 downto 2);
+ alias req_cache_index is request_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ alias req_tag is request_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+begin
+
+ ram_read_en <= cpu_en or was_miss;
+ cache_index_inv <= ctrl.inv_addr(cache_index_width+word_index_width+1 downto word_index_width+2);
+ tag_inv <= ctrl.inv_addr(tag_width+cache_index_width+word_index_width+1 downto cache_index_width+word_index_width+2);
+
+
+fill_address_register:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if fill_count_en = '1' then
+ if ACK_I = '1' then
+ fill_word_index <= fill_word_index + 1;
+ end if;
+ elsif cache_busy = '0' then
+ fill_addr <= cpu_addr(addr_width-1 downto 2) & "00";
+ end if;
+ end if;
+ end process;
+
+request_address_register:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if request_count_en = '1'then
+ if SRDY_I = '1' then
+ req_word_index <= req_word_index + 1;
+ end if;
+ elsif cache_busy = '0' then
+ request_addr <= cpu_addr(addr_width-1 downto 2) & "00";
+ end if;
+ end if;
+ end process;
+
+cpu_request_register:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if RST_I = '1' then
+ cache_req <= '0';
+ elsif cpu_en = '1' then
+ if cache_busy = '0' then
+ cache_req <= '1';
+ end if;
+ elsif cache_ack = '1' then
+ cache_req <= '0';
+ end if;
+ end if;
+ end process;
+
+cache_invalidate_request:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if RST_I = '1' or ctrl.inv_all = '1' or ctrl.inv_at = '1' then
+ invalidate_req <= '1';
+ invalidate_all <= ctrl.inv_all or RST_I;
+ tag_reg_inv <= tag_inv;
+ elsif invalidate_ack = '1' then
+ invalidate_req <= '0';
+ invalidate_all <= '0';
+ end if;
+ end if;
+ end process;
+
+inst_tag_ram : dpram_2w2r2c_ra
+ GENERIC MAP
+ (
+ addr_width => tag_ram_addr_width,
+ data_width => tag_ram_data_width
+ )
+ PORT MAP
+ (
+ clk_a => CLK_I,
+ clk_b => CLK_I,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => tag_ram_we,
+ we_b => '0',
+ addr_a => tag_ram_addr_wr,
+ addr_b => tag_ram_addr_rd,
+ din_a => tag_ram_data_wr,
+ din_b => tag_ram_data_wr,
+ dout_a => tag_ram_data_rd_inv,
+ dout_b => tag_ram_data_rd
+ );
+
+inst_data_ram : dpram_1w1r2c_ra
+ GENERIC MAP
+ (
+ addr_width => lg2(cache_size),
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_a => CLK_I,
+ clk_b => CLK_I,
+ en_a => '1',
+ en_b => ram_read_en,
+ we_a => data_ram_we,
+ addr_a => data_ram_addr_wr,
+ addr_b => data_ram_addr_rd,
+ din_a => data_ram_data_wr,
+ dout_b => data_ram_data_rd
+ );
+
+cache_state_next:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if RST_I = '1' then
+ s <= init;
+ else
+ s <= sn;
+ end if;
+ end if;
+ end process;
+
+ MRDY_O <= fill_count_en;
+ ADDR_O <= fill_tag & fill_cache_index & req_word_index & "00";
+
+ cpu_busy <= cache_busy;
+ cpu_dout <= data_ram_data_rd;
+
+ cache_entry_out <= to_icache_entry(tag_ram_data_rd);
+ tag_match <= '1' when fill_tag = cache_entry_out.tag else '0';
+ cache_miss <= not (tag_match and cache_entry_out.valid);
+
+ cache_entry_out_inv <= to_icache_entry(tag_ram_data_rd_inv);
+ tag_match_inv <= '1' when tag_reg_inv = cache_entry_out_inv.tag else '0';
+ cache_miss_inv <= not (tag_match_inv and cache_entry_out_inv.valid);
+
+ tag_ram_data_wr <= to_tag_ram_data(cache_entry_in);
+ tag_ram_addr_wr <= to_unsigned(flush_count, cache_index_width) when invalidate_en = '1' else fill_cache_index;
+ tag_ram_addr_rd <= cpu_cache_index when was_miss = '0' else fill_cache_index;
+ data_ram_addr_rd <= (cpu_cache_index & cpu_word_index) when was_miss = '0' else (fill_cache_index & fill_word_index);
+ data_ram_addr_wr <= fill_cache_index & fill_word_index;
+ data_ram_data_wr <= DAT_I;
+ data_ram_we <= fill_count_en and ACK_I;
+
+cache_state:
+ process(s, cache_req, cache_miss, cache_miss_inv, flush_count_rdy, fill_count_rdy, request_count_rdy, fill_tag, SRDY_I, invalidate_req, invalidate_all)
+ begin
+ cache_busy <= cache_req;
+ cache_ack <= '0';
+ tag_ram_we <= '0';
+ flush_count_en <= '0';
+ flush_count_rst <= '0';
+ invalidate_en <= '0';
+ request_count_en <= '0';
+ fill_count_en <= '0';
+ CYC_O <= '0';
+ STB_O <= '0';
+ was_miss <= '0';
+ invalidate_ack <= '0';
+
+ cache_entry_in.tv_p <= (others => '0');
+ cache_entry_in.tag <= fill_tag;
+ cache_entry_in.valid <= '0';
+ sn <= s;
+
+ case s is
+ when init =>
+ sn <= ready;
+ when ready =>
+ if invalidate_req = '1' then
+ sn <= invalidate;
+ invalidate_en <= '1';
+ elsif cache_req = '1' then
+ if cache_miss = '1' then
+ sn <= mem_request;
+ CYC_O <= '1';
+ else
+ cache_busy <= '0';
+ cache_ack <= '1';
+ end if;
+ end if;
+ when invalidate =>
+ sn <= rd_cache;
+ invalidate_en <= '1';
+ invalidate_ack <= '1';
+ if invalidate_all = '1' then
+ sn <= flush;
+ flush_count_rst <= '1';
+ elsif cache_miss_inv = '0' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ sn <= rd_cache;
+ end if;
+
+ when flush =>
+ flush_count_en <= '1';
+ invalidate_en <= '1';
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '0';
+ cache_entry_in.tag <= (others => '0');
+ if flush_count_rdy = '1' then
+ tag_ram_we <= '0';
+ sn <= rd_cache;
+ end if;
+ when mem_request =>
+ CYC_O <= '1';
+ if SRDY_I = '1' then
+ sn <= mem_access;
+ end if;
+ when mem_access =>
+ request_count_en <= '1';
+ fill_count_en <= '1';
+ CYC_O <= '1';
+ STB_O <= '1';
+ if request_count_rdy = '1' then
+ STB_O <= '0';
+ sn <= mem_data;
+ end if;
+ when mem_data =>
+ CYC_O <= '1';
+ fill_count_en <= '1';
+ if fill_count_rdy = '1' then
+ tag_ram_we <= '1';
+ cache_entry_in.valid <= '1';
+ sn <= rd_cache;
+ end if;
+ when rd_cache =>
+ was_miss <= '1';
+ sn <= ready;
+ when others =>
+ sn <= ready;
+ end case;
+
+ end process;
+
+flush_counter:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if ctrl.inv_at = '1' then
+ flush_count <= to_integer(cache_index_inv);
+ elsif flush_count_rst = '1' then
+ flush_count_rdy <= '0';
+ flush_count <= 2**cache_index_width-1;
+ elsif flush_count_en = '1' then
+ if flush_count /= 0 then
+ flush_count <= flush_count - 1;
+ else
+ flush_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+request_counter:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if request_count_en = '0' then
+ request_count_rdy <= '0';
+ request_count <= 2**word_index_width-1;
+ else
+ if SRDY_I = '1' then
+ if request_count /= 0 then
+ request_count <= request_count - 1;
+ else
+ request_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+fill_counter:
+ process(CLK_I)
+ begin
+ if rising_edge(CLK_I) then
+ if fill_count_en = '0' then
+ fill_count_rdy <= '0';
+ fill_count <= 2**word_index_width-1;
+ else
+ if ACK_I = '1' then
+ if fill_count /= 0 then
+ fill_count <= fill_count - 1;
+ else
+ fill_count_rdy <= '1';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end behavior;
diff --git a/lib/CPUs/MIPS/src/core/MMU/mips_pipeline_nofwd.vhd b/lib/CPUs/MIPS/src/core/MMU/mips_pipeline_nofwd.vhd
new file mode 100644
index 0000000..6477d95
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/MMU/mips_pipeline_nofwd.vhd
@@ -0,0 +1,867 @@
+--------------------------------------------------------------------------
+-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
+-- This file: The pipeline
+--
+-- Copyright (C) 2008 J. Ahrensfeld
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- For questions and ideas, please contact the author at jens@jayfield.org
+--
+--------------------------------------------------------------------------
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.numeric_std.ALL;
+
+library work;
+use work.mips_types.all;
+use work.mips_instr.all;
+
+entity pipeline is
+ Port
+ (
+ rst : in STD_LOGIC;
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+ imem_err : in STD_LOGIC;
+ imem_rdy : in STD_LOGIC;
+ imem_en : out STD_LOGIC;
+ imem_addr : out word_t;
+ imem_data : in word_t;
+ dmem_err : in STD_LOGIC;
+ dmem_rdy : in STD_LOGIC;
+ dmem_en : out STD_LOGIC;
+ dmem_we : out STD_LOGIC;
+ dmem_be : out unsigned(3 downto 0);
+ dmem_addr : out word_t;
+ dmem_din : in word_t;
+ dmem_dout : out word_t;
+ cop_ir : out word_t;
+ cop_ir_en : out STD_LOGIC;
+ cop_din : in word_t;
+ cop_dout : out word_t;
+ c0_ctrl_out : out cop0_ctrl_in_t;
+ c0_ctrl_in : in cop0_ctrl_out_t
+
+ );
+end pipeline;
+
+architecture Behavioral of pipeline is
+
+--------------------------------------------------------------------------
+ COMPONENT reg_dual is
+ Generic
+ (
+ addr_width : integer := 3;
+ data_width : integer := 8
+ );
+ Port
+ (
+ clk_w : in STD_LOGIC;
+ en : in STD_LOGIC;
+ we : in STD_LOGIC;
+ wptr : in unsigned (addr_width-1 downto 0);
+ din : in unsigned (data_width-1 downto 0);
+ rptr_a : in unsigned (addr_width-1 downto 0);
+ rptr_b : in unsigned (addr_width-1 downto 0);
+ dout_a : out unsigned (data_width-1 downto 0);
+ dout_b : out unsigned (data_width-1 downto 0)
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT shifter is
+ Generic
+ (
+ data_width : integer
+ );
+ Port
+ (
+ shift_ctrl : in shift_ctrl_t;
+ din : in unsigned (data_width-1 downto 0);
+ dout : out unsigned (data_width-1 downto 0)
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT alu is
+ Generic
+ (
+ data_width : integer
+ );
+ Port
+ (
+ op1_in : in unsigned (data_width-1 downto 0);
+ op2_in : in unsigned (data_width-1 downto 0);
+ op2_shifted : in unsigned (data_width-1 downto 0);
+ ctrl : in alu_ctrl_t;
+ result : out unsigned (data_width-1 downto 0);
+ flags : out alu_flags_t
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT bcu is
+ Generic
+ (
+ data_width : integer
+ );
+ Port
+ (
+ op1_in : in unsigned (data_width-1 downto 0);
+ op2_in : in unsigned (data_width-1 downto 0);
+ flags : out bcu_flags_t
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ COMPONENT muldiv is
+ Port
+ (
+ rst : in std_logic;
+ clk : in std_logic;
+ hilo_we : in std_logic;
+ din_hi : in word_t;
+ din_lo : in word_t;
+ mul_divn : in std_logic;
+ start : in std_logic;
+ s_un : in std_logic;
+ hilo_sel : in std_logic;
+ busy : out std_logic;
+ dout : out word_t
+ );
+ END COMPONENT;
+
+--------------------------------------------------------------------------
+ signal ID_stage : ID_t;
+ signal EX_stage : EX_t;
+ signal MEM_stage : MEM_t;
+ signal WB_stage : WB_t;
+ signal clk_2, clk_1 : STD_LOGIC;
+ signal hdu : hdu_t;
+ signal sdu : sdu_t;
+ signal reg_a : word_t;
+ signal reg_b : word_t;
+ signal branch_ce : STD_LOGIC;
+ signal cpu_run : STD_LOGIC;
+ signal alu_result : word_t;
+ signal mul_result : word_t;
+ signal mul_busy : STD_LOGIC;
+ signal EX_events_instr : event_t;
+ signal EX_events_alu : event_t;
+ signal EX_events_mem : event_t;
+ signal EX_events : event_t;
+ signal MEM_events : event_t;
+ signal bcu_op_a : word_t;
+ signal bcu_op_b : word_t;
+ signal bcu_flags : bcu_flags_t;
+ signal vaddr : word_t;
+ signal dmem_src : word_t;
+ signal stage_rst : unsigned(3 downto 0);
+ signal pipe_rst : STD_LOGIC;
+
+ signal pc : pc_t;
+
+--------------------------------------------------------------------------
+begin
+
+ clk_1 <= clk;
+ clk_2 <= not clk;
+ cpu_run <= ce;
+
+ -- Stall Detection Unit ---------------------------------------------------
+ sdu.ID_nop <= sdu.imem_dep or c0_ctrl_in.exc_pending or ID_stage.exc or EX_stage.exc or MEM_stage.exc;
+ sdu.EX_nop <= sdu.mul_dep or ID_stage.nop or ID_stage.exc;
+ sdu.MEM_nop <= EX_stage.nop or EX_stage.exc;
+ sdu.WB_nop <= sdu.dmem_dep or MEM_stage.nop;
+
+ sdu.stall_all <= sdu.dmem_dep;
+ sdu.ID_stall <= sdu.stall_all or sdu.imem_dep or sdu.mul_dep or c0_ctrl_in.exc_exit;
+ sdu.EX_stall <= sdu.stall_all;
+ sdu.MEM_stall <= sdu.stall_all;
+ sdu.WB_stall <= '0';
+
+ sdu.mul_dep <= ID_stage.ctrl.mul_access and (EX_stage.ctrl.mul_start or mul_busy);
+ sdu.imem_dep <= not imem_rdy;
+ sdu.dmem_dep <= not dmem_rdy and MEM_stage.ctrl.dmem_en;
+ ---------------------------------------------------------------------------
+ imem_en <= cpu_run and not (sdu.mul_dep or sdu.dmem_dep or c0_ctrl_in.exc_commit);
+
+--------------------------------------------------------------------------
+-- Coprocessor assignments
+--------------------------------------------------------------------------
+ c0_ctrl_out.bd_wb <= WB_stage.bd;
+ c0_ctrl_out.epc_mem <= MEM_stage.pcn;
+ c0_ctrl_out.epc_wb <= MEM_stage.epc;
+ c0_ctrl_out.imem_addr <= EX_stage.epc;
+ c0_ctrl_out.dmem_addr <= MEM_stage.va;
+ c0_ctrl_out.sdu <= sdu;
+ c0_ctrl_out.events <= WB_stage.events;
+ c0_ctrl_out.exc_req <= MEM_stage.exc;
+ c0_ctrl_out.exc_ack <= WB_stage.exc;
+ cop_ir <= ID_stage.IR;
+ cop_ir_en <= ID_stage.ctrl.cop_instr_en;
+ cop_dout <= dmem_din when MEM_stage.ctrl.dmem_en = '1' else MEM_stage.ex_result;
+
+--------------------------------------------------------------------------
+-- Muldiv
+--------------------------------------------------------------------------
+inst_muldiv: muldiv
+ PORT MAP
+ (
+ rst => rst,
+ clk => clk,
+ hilo_we => EX_stage.ctrl.mul_hilo_we,
+ din_hi => EX_stage.reg_a,
+ din_lo => EX_stage.reg_b,
+ mul_divn => EX_stage.ctrl.mul_mul_divn,
+ start => EX_stage.ctrl.mul_start,
+ s_un => EX_stage.ctrl.mul_s_un,
+ hilo_sel => EX_stage.ctrl.mul_hilo_sel,
+ busy => mul_busy,
+ dout => mul_result
+ );
+
+--------------------------------------------------------------------------
+-- IF stage
+--------------------------------------------------------------------------
+ imem_addr <= pc.curr;
+
+ pipe_rst <= stage_rst(0);
+
+proc_stage_reset:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if rst = '1' then
+ stage_rst <= (others => '1');
+ else
+ stage_rst <= stage_rst(stage_rst'left-1 downto 0) & '0';
+ end if;
+ end if;
+ end process;
+
+proc_stage_pc:
+ process(pc)
+ begin
+ if pc.branch_take = '1' then
+ pc.curr <= pc.pc_branch after 2 ns;
+ else
+ pc.curr <= pc.nxt after 2 ns;
+ end if;
+ end process;
+
+proc_stage_pc_branch:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if sdu.ID_stall = '0' then
+ pc.pc_branch <= pc.curr + ID_stage.bimm18;
+ end if;
+ end if;
+ end process;
+
+proc_stage_branch_ce:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if pipe_rst = '1' then
+ branch_ce <= '1';
+ else
+ branch_ce <= c0_ctrl_in.exc_pending;
+ if sdu.ID_stall = '0' and c0_ctrl_in.exc_inject = '0' then
+ branch_ce <= '1';
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_pc_next:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if c0_ctrl_in.exc_inject = '1' then
+ pc.nxt <= c0_ctrl_in.exc_vec;
+ elsif sdu.ID_stall = '0' then
+ pc.last <= pc.curr;
+ if ID_stage.ctrl.jump = '1' then
+ pc.nxt <= ID_stage.jimm32;
+ elsif ID_stage.ctrl.jump_long = '1' then
+ pc.nxt <= ID_stage.reg_a;
+ else
+ pc.nxt <= pc.curr + 4;
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_branch:
+ process(clk_2)
+ begin
+ if rising_edge(clk_2) and branch_ce = '1' then
+ pc.branch_take <= '0';
+ if EX_stage.ctrl.branch = '1' then
+
+ case EX_stage.ctrl.bc_src is
+
+ when bc_eq_ne =>
+ pc.branch_take <= EX_stage.ctrl.bc_not xor bcu_flags.eq;
+
+ when bc_lez_gtz =>
+ pc.branch_take <= EX_stage.ctrl.bc_not xor (bcu_flags.eq or bcu_flags.ltz);
+
+ when bc_ltz_gez =>
+ pc.branch_take <= EX_stage.ctrl.bc_not xor bcu_flags.ltz;
+
+ when others => null;
+ end case;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+-- ID stage
+--------------------------------------------------------------------------
+ ID_stage.IR <= to_01(imem_data);
+ ID_stage.pcn <= pc.curr;
+ ID_stage.op <= decode_op(ID_stage.IR);
+ ID_stage.jimm32 <= extract_jimm32(ID_stage.IR, ID_stage.pcn);
+ ID_stage.bimm18 <= extract_bimm18(ID_stage.IR, ID_stage.pcn);
+ ID_stage.shamt <= extract_shamt(ID_stage.IR);
+ ID_stage.reg_a_rptr <= extract_rs(ID_stage.IR);
+ ID_stage.reg_b_rptr <= extract_rt(ID_stage.IR);
+ ID_stage.ctrl <= opcode_ctrl_lines(ID_stage.IR) when sdu.ID_nop = '0' else ctrl_lines_default;
+ ID_stage.reg_write <= ID_stage.ctrl.reg_write;
+ ID_stage.epc <= pc.last;
+ ID_stage.exc <= event_is_active(ID_stage.events); -- Todo: works
+ ID_stage.nop <= sdu.ID_nop;
+
+proc_ID_except:
+ process(ID_stage, c0_ctrl_in, pc)
+ begin
+ ID_stage.events <= events_clr;
+ ID_stage.events.inst_load_err <= not c0_ctrl_in.exc_pending and (pc.nxt(1) or pc.nxt(0));
+ ID_stage.events.inst_priv_addr <= not c0_ctrl_in.exc_pending and (pc.nxt(word_t'left) and c0_ctrl_in.user_mode);
+ end process;
+
+proc_stage_hdu:
+ process(ID_stage, EX_stage, MEM_stage, WB_stage)
+ variable read_a, read_b : boolean;
+ variable raw_a_EX, raw_a_MEM, raw_a_WB : boolean;
+ variable raw_b_EX, raw_b_MEM, raw_b_WB : boolean;
+ variable reg_ptr_a : reg_ptr_t;
+ variable reg_ptr_b : reg_ptr_t;
+ begin
+
+ reg_ptr_a := ID_stage.reg_a_rptr;
+ reg_ptr_b := ID_stage.reg_b_rptr;
+ raw_a_EX := reg_ptr_a = EX_stage.reg_wptr and EX_stage.wreg_we = '1';
+ raw_a_MEM := reg_ptr_a = MEM_stage.reg_wptr and MEM_stage.wreg_we = '1';
+ raw_a_WB := reg_ptr_a = WB_stage.reg_wptr and WB_stage.wreg_we = '1';
+ raw_b_EX := reg_ptr_b = EX_stage.reg_wptr and EX_stage.wreg_we = '1';
+ raw_b_MEM := reg_ptr_b = MEM_stage.reg_wptr and MEM_stage.wreg_we = '1';
+ raw_b_WB := reg_ptr_b = WB_stage.reg_wptr and WB_stage.wreg_we = '1';
+
+ hdu.alu_fwd_a_ex <= raw_a_EX after 1 ns;
+ hdu.alu_fwd_a_mem <= raw_a_MEM after 1 ns;
+ hdu.alu_fwd_a_wb <= raw_a_WB after 1 ns;
+ hdu.alu_fwd_b_ex <= raw_b_EX after 1 ns;
+ hdu.alu_fwd_b_mem <= raw_b_MEM after 1 ns;
+ hdu.alu_fwd_b_wb <= raw_b_WB after 1 ns;
+
+ end process;
+
+proc_stage_fwd_a:
+ process(reg_a, hdu, EX_stage, MEM_stage, WB_stage)
+ variable data : word_t;
+ begin
+ data := reg_a;
+-- if hdu.alu_fwd_a_ex then
+-- data := EX_stage.result;
+-- elsif hdu.alu_fwd_a_mem then
+-- data := MEM_stage.data;
+-- elsif hdu.alu_fwd_a_wb then
+-- data := WB_stage.data;
+-- end if;
+
+ for i in 0 to 31 loop
+ if data(i) = '1' then
+ ID_stage.reg_a(i) <= '1' after 2 ns;
+ else
+ ID_stage.reg_a(i) <= '0' after 2 ns;
+ end if;
+ end loop;
+
+ end process;
+
+proc_stage_fwd_b:
+ process(reg_b, hdu, EX_stage, MEM_stage, WB_stage)
+ variable data : word_t;
+ begin
+ data := reg_b;
+-- if hdu.alu_fwd_b_ex then
+-- data := EX_stage.result;
+-- elsif hdu.alu_fwd_b_mem then
+-- data := MEM_stage.data;
+-- elsif hdu.alu_fwd_b_wb then
+-- data := WB_stage.data;
+-- end if;
+
+ for i in 0 to 31 loop
+ if data(i) = '1' then
+ ID_stage.reg_b(i) <= '1' after 2 ns;
+ else
+ ID_stage.reg_b(i) <= '0' after 2 ns;
+ end if;
+ end loop;
+
+ end process;
+
+proc_imm_mux:
+ process(ID_stage)
+ variable data : word_t;
+ begin
+ data := extract_uimm16(ID_stage.IR);
+
+ case ID_stage.ctrl.imm_src is
+
+ when src_imm32 =>
+ data := extract_simm32(ID_stage.IR);
+
+ when src_imm16 =>
+ data := extract_uimm16(ID_stage.IR);
+
+ when src_imm16_high =>
+ data := ID_stage.IR(word_t'length/2-1 downto 0) & (word_t'length/2-1 downto 0 => '0');
+
+ when others => null;
+
+ end case;
+
+ ID_stage.imm <= data after 2 ns;
+
+ end process;
+
+--------------------------------------------------------------------------
+inst_reg_dual: reg_dual
+ GENERIC MAP
+ (
+ addr_width => reg_ptr_t'length,
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ clk_w => clk_1,
+ we => WB_stage.wreg_we,
+ en => '1',
+ wptr => WB_stage.reg_wptr,
+ din => WB_stage.data,
+ rptr_a => ID_stage.reg_a_rptr,
+ rptr_b => ID_stage.reg_b_rptr,
+ dout_a => reg_a,
+ dout_b => reg_b
+ );
+
+--------------------------------------------------------------------------
+-- EX stage
+--------------------------------------------------------------------------
+ EX_stage.reg_a_rptr <= extract_rs(EX_stage.IR);
+ EX_stage.reg_b_rptr <= extract_rt(EX_stage.IR);
+ EX_stage.result <= alu_result when EX_stage.ctrl.mul_access = '0' else mul_result;
+
+proc_stage_ID_EX_1:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if stage_rst(1) = '1' then
+ EX_stage.op <= NOP;
+ EX_stage.IR <= (others => '0');
+ EX_stage.ctrl <= ctrl_lines_default;
+ EX_stage.reg_write <= '0';
+ EX_stage.epc <= (others => '0');
+ EX_stage.pcn <= (others => '0');
+ EX_stage.events_in <= events_clr;
+ elsif sdu.EX_stall = '0' then
+ EX_stage.reg_a <= ID_stage.reg_a;
+ EX_stage.reg_b <= ID_stage.reg_b;
+ EX_stage.events_in <= ID_stage.events;
+ EX_stage.op <= ID_stage.op;
+ EX_stage.ctrl <= ID_stage.ctrl;
+ EX_stage.reg_write <= ID_stage.reg_write;
+ EX_stage.nop <= sdu.EX_nop;
+ EX_stage.IR <= ID_stage.IR;
+ EX_stage.pcn <= ID_stage.pcn;
+ EX_stage.epc <= ID_stage.epc;
+ if sdu.EX_nop = '1' then
+ EX_stage.op <= NOP;
+ EX_stage.IR <= (others => '0');
+ EX_stage.ctrl <= ctrl_lines_default;
+ EX_stage.reg_write <= '0';
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_EX_instr_except:
+ process(EX_stage)
+ begin
+ EX_events_instr <= events_clr;
+ EX_events_instr.illegal <= EX_stage.ctrl.exc_illegal;
+ EX_events_instr.break <= EX_stage.ctrl.exc_break;
+ EX_events_instr.syscall <= EX_stage.ctrl.exc_syscall;
+ end process;
+
+proc_stage_EX_alu_except:
+ process(EX_stage)
+ begin
+ EX_events_alu <= events_clr;
+ if EX_stage.ctrl.alu_exc_en = '1' then
+ if EX_stage.alu_flags.ovf = '1' then
+ EX_events_alu.alu_ovf <= '1';
+ end if;
+ if EX_stage.alu_flags.uvf = '1' then
+ EX_events_alu.alu_uvf <= '1';
+ end if;
+ end if;
+ end process;
+
+ vaddr <= ID_stage.reg_a + extract_simm32(ID_stage.IR);
+
+proc_stage_EX_mem_except:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if pipe_rst = '1' then
+ dmem_en <= '0';
+ elsif sdu.EX_stall = '0' then
+ EX_events_mem <= events_clr;
+ dmem_en <= '0';
+ if ID_stage.ctrl.dmem_en = '1' then
+ dmem_en <= '1';
+ if ID_stage.ctrl.except_en = '1' then
+ if ID_stage.ctrl.word2_en = '1' then
+ if vaddr(0) = '1' then
+ EX_events_mem.data_load_err <= not ID_stage.ctrl.dmem_we;
+ EX_events_mem.data_store_err <= ID_stage.ctrl.dmem_we;
+ dmem_en <= '0';
+ end if;
+ elsif vaddr(1 downto 0) /= "00" then
+ EX_events_mem.data_load_err <= not ID_stage.ctrl.dmem_we;
+ EX_events_mem.data_store_err <= ID_stage.ctrl.dmem_we;
+ dmem_en <= '0';
+ end if;
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_DMEM_ADDR:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if sdu.EX_stall = '0' then
+ EX_stage.va <= vaddr;
+ if c0_ctrl_in.EB = '1' then
+ if ID_stage.ctrl.word2_en = '0' then
+ EX_stage.pa_off <= not vaddr(1 downto 0);
+ else
+ EX_stage.pa_off <= not vaddr(1) & vaddr(0);
+ end if;
+ else
+ EX_stage.pa_off <= vaddr(1 downto 0);
+ end if;
+ end if;
+ end if;
+ end process;
+ dmem_src <= cop_din when EX_stage.ctrl.cop_instr_en = '1' else EX_stage.reg_b;
+ dmem_be <= store_be(EX_stage.pa_off, EX_stage.ctrl.dmem_en, EX_stage.ctrl.word2_en, EX_stage.ctrl.word4_en, EX_stage.ctrl.align_left, EX_stage.ctrl.shift_byp) after 1 ns;
+ dmem_we <= EX_stage.ctrl.dmem_we;
+ dmem_dout <= store_shift(dmem_src, EX_stage.pa_off, EX_stage.ctrl.shift_offset, EX_stage.ctrl.shift_byp) after 1ns;
+ dmem_addr <= EX_stage.va;
+ EX_stage.events <= EX_events_instr or EX_events_mem or EX_events_alu or EX_stage.events_in;
+ EX_stage.exc <= event_is_active(EX_stage.events);
+
+--------------------------------------------------------------------------
+proc_wptr_mux:
+ process(EX_stage)
+ variable opclass : opcode_t;
+ variable reg_wptr : reg_ptr_t;
+ begin
+
+ opclass := extract_opc(EX_stage.IR);
+ case opclass is
+ when "000000" =>
+ reg_wptr := extract_rd(EX_stage.IR);
+ when others =>
+ reg_wptr := extract_rt(EX_stage.IR);
+ end case;
+
+ EX_stage.wreg_we <= EX_stage.reg_write after 1 ns;
+ if reg_wptr = "00000" then
+ EX_stage.wreg_we <= '0' after 1 ns;
+ end if;
+
+ EX_stage.reg_wptr <= reg_wptr after 1 ns;
+ case EX_stage.ctrl.wptr_srcsel is
+ when wptr_src_imm =>
+ EX_stage.reg_wptr <= reg_wptr after 1 ns;
+
+ when wptr_src_const =>
+ EX_stage.reg_wptr <= to_unsigned(31, reg_ptr_t'length) after 1 ns;
+ EX_stage.wreg_we <= '1' after 1 ns;
+
+ when others => null;
+ end case;
+
+ end process;
+
+--------------------------------------------------------------------------
+proc_stage_bcu_op:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) and sdu.EX_stall = '0' then
+ bcu_op_a <= ID_stage.reg_a;
+ bcu_op_b <= ID_stage.reg_b;
+ end if;
+ end process;
+
+EX_stage.alu_op1 <= EX_stage.reg_a;
+
+alu_op2_mux:
+ process(clk_1)
+ variable data : word_t;
+ begin
+
+ if rising_edge(clk_1) and sdu.EX_stall = '0' then
+ data := ID_stage.reg_b;
+
+ case ID_stage.ctrl.alu.op2_src is
+
+ when alu_src_reg =>
+ data := ID_stage.reg_b;
+
+ when alu_src_imm =>
+ data := ID_stage.imm;
+
+ when others => null;
+
+ end case;
+
+ EX_stage.alu_op2 <= data;
+ end if;
+
+ end process;
+
+shifter_sa_mux:
+ process(clk_1)
+ variable data : shamt_t;
+ variable data_inv : shamt_t;
+
+ begin
+ if rising_edge(clk_1) and sdu.EX_stall = '0' then
+ data := ID_stage.reg_a(4 downto 0);
+ case ID_stage.ctrl.shamt2_srcsel is
+
+ when sa_src_reg =>
+ data := ID_stage.reg_a(4 downto 0);
+
+ when sa_src_imm =>
+ data := ID_stage.shamt;
+
+ when others => null;
+
+ end case;
+ data_inv := not data + 1;
+ if ID_stage.ctrl.alu.shift_right = '0' then
+ EX_stage.shift_ctrl.shamt_rnd <= data_inv after 2 ns;
+ else
+ EX_stage.shift_ctrl.shamt_rnd <= data after 2 ns;
+ end if;
+ EX_stage.shift_ctrl.shamt_nrm <= data after 1 ns;
+ EX_stage.shift_ctrl.shift_right <= ID_stage.ctrl.alu.shift_right;
+ EX_stage.shift_ctrl.shift_arith <= ID_stage.ctrl.alu.shift_arith;
+ end if;
+
+ end process;
+
+--------------------------------------------------------------------------
+inst_shifter: shifter
+ GENERIC MAP
+ (
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ shift_ctrl => EX_stage.shift_ctrl,
+ din => EX_stage.reg_b,
+ dout => EX_stage.alu_op2_s
+ );
+
+inst_alu: alu
+ GENERIC MAP
+ (
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ op1_in => EX_stage.alu_op1,
+ op2_in => EX_stage.alu_op2,
+ op2_shifted => EX_stage.alu_op2_s,
+ ctrl => EX_stage.ctrl.alu,
+ result => alu_result,
+ flags => EX_stage.alu_flags
+ );
+
+inst_bcu: bcu
+ GENERIC MAP
+ (
+ data_width => word_t'length
+ )
+ PORT MAP
+ (
+ op1_in => bcu_op_a,
+ op2_in => bcu_op_b,
+ flags => bcu_flags
+ );
+
+--------------------------------------------------------------------------
+-- MEM stage
+--------------------------------------------------------------------------
+proc_stage_MEM_n:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if stage_rst(2) = '1' then
+ MEM_stage.op <= NOP;
+ MEM_stage.wreg_we <= '0';
+ MEM_stage.ctrl <= ctrl_lines_default;
+ MEM_stage.pa_off <= (others => '0');
+ MEM_stage.events_in <= events_clr;
+ elsif sdu.MEM_stall = '0' then
+ MEM_stage.events_in <= EX_stage.events;
+ MEM_stage.op <= EX_stage.op;
+ MEM_stage.wreg_we <= EX_stage.wreg_we;
+ MEM_stage.ctrl <= EX_stage.ctrl;
+ if EX_stage.ctrl.dmem_en = '1' then
+ MEM_stage.va <= EX_stage.va;
+ end if;
+ MEM_stage.pa_off <= EX_stage.pa_off;
+ MEM_stage.reg_wptr <= EX_stage.reg_wptr;
+ MEM_stage.nop <= sdu.MEM_nop;
+ if MEM_stage.reg_wptr = EX_stage.reg_wptr then
+ if (EX_stage.ctrl.dmem_en and MEM_stage.ctrl.dmem_en) = '1' then
+ MEM_stage.ex_result <= MEM_stage.data;
+ end if;
+ else
+ MEM_stage.ex_result <= EX_stage.reg_b;
+ end if;
+ if EX_stage.ctrl.cop_instr_en = '1' then
+ if EX_stage.ctrl.cop_read = '1' then
+ MEM_stage.ex_result <= cop_din;
+ end if;
+ elsif EX_stage.ctrl.dmem_en = '0' then
+ MEM_stage.ex_result <= EX_stage.result;
+ end if;
+ if sdu.MEM_nop = '1' then
+ MEM_stage.op <= NOP;
+ MEM_stage.wreg_we <= '0';
+ MEM_stage.ctrl <= ctrl_lines_default;
+ else
+ MEM_stage.pcn <= EX_stage.pcn;
+ MEM_stage.epc <= EX_stage.epc;
+ end if;
+ end if;
+ end if;
+ end process;
+
+proc_stage_MEM_mux:
+ process(MEM_stage, dmem_din)
+ variable temp1 : word_t;
+ variable temp2 : word_t;
+ variable data : word_t;
+ variable be : unsigned(3 downto 0);
+ begin
+ data := MEM_stage.ex_result;
+ if MEM_stage.ctrl.reg_link = '1' then
+ data := MEM_stage.epc + 8;
+ elsif MEM_stage.ctrl.dmem_en = '1' then
+ temp1 := load_shift(dmem_din, MEM_stage.pa_off, MEM_stage.ctrl.shift_offset, MEM_stage.ctrl.shift_byp);
+ temp2 := load_sign_ext(temp1, MEM_stage.ctrl.sign_ext_byp, MEM_stage.ctrl.load_signed, MEM_stage.ctrl.word2_en, MEM_stage.ctrl.word4_en);
+ be := load_be(MEM_stage.pa_off, MEM_stage.ctrl.align_left, MEM_stage.ctrl.byte_en_byp);
+ if be(0) = '1' then
+ data(7 downto 0) := temp2(7 downto 0);
+ end if;
+ if be(1) = '1' then
+ data(15 downto 8) := temp2(15 downto 8);
+ end if;
+ if be(2) = '1' then
+ data(23 downto 16) := temp2(23 downto 16);
+ end if;
+ if be(3) = '1' then
+ data(31 downto 24) := temp2(31 downto 24);
+ end if;
+ end if;
+ MEM_stage.data <= data after 1 ns;
+
+ end process;
+
+proc_stage_MEM_except:
+ process(MEM_stage, c0_ctrl_in)
+ begin
+ MEM_stage.events <= MEM_stage.events_in;
+ MEM_stage.events.Int <= c0_ctrl_in.int;
+ MEM_stage.events.NMI <= c0_ctrl_in.NMI;
+ end process;
+
+ MEM_stage.exc <= event_is_active(MEM_stage.events);
+
+--------------------------------------------------------------------------
+-- WB stage
+--------------------------------------------------------------------------
+proc_stage_WB_p:
+ process(clk_1)
+ begin
+ if rising_edge(clk_1) then
+ if stage_rst(3) = '1' then
+ WB_stage.op <= NOP;
+ WB_stage.wreg_we <= '1';
+ WB_stage.reg_wptr <= (others => '0');
+ WB_stage.data <= (others => '0');
+ WB_stage.events <= events_clr;
+ elsif sdu.WB_stall = '0' then
+ WB_stage.op <= MEM_stage.op;
+ WB_stage.wreg_we <= MEM_stage.wreg_we;
+ WB_stage.reg_wptr <= MEM_stage.reg_wptr;
+ WB_stage.data <= MEM_stage.data;
+ WB_stage.exc <= '0';
+ if sdu.stall_all = '0' then
+ WB_stage.exc <= MEM_stage.exc;
+ if MEM_stage.exc = '1' then
+ WB_stage.events <= MEM_stage.events;
+ end if;
+ end if;
+ WB_stage.nop <= sdu.WB_nop;
+ if sdu.WB_nop = '1' then
+ WB_stage.op <= NOP;
+ WB_stage.wreg_we <= '0';
+ else
+ WB_stage.bd <= MEM_stage.ctrl.branch or MEM_stage.ctrl.jump or MEM_stage.ctrl.jump_long; -- Todo: works
+ end if;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+end Behavioral;