diff --git a/lib/CPUs/MIPS/src/core/mips_cam.vhd b/lib/CPUs/MIPS/src/core/mips_cam.vhd
new file mode 100644
index 0000000..1eff4f3
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/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/mips_func_pkg.vhd b/lib/CPUs/MIPS/src/core/mips_func_pkg.vhd
new file mode 100644
index 0000000..6ff2954
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/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/mips_tlb.vhd b/lib/CPUs/MIPS/src/core/mips_tlb.vhd
new file mode 100644
index 0000000..7fae13d
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/mips_tlb.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/mips_util_pkg.vhd b/lib/CPUs/MIPS/src/core/mips_util_pkg.vhd
new file mode 100644
index 0000000..2dd9e4d
--- /dev/null
+++ b/lib/CPUs/MIPS/src/core/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;
+