Initial revision

Committed on the Free edition of March Hare Software CVSNT Server.
Upgrade to CVS Suite for more features and support:
http://march-hare.com/cvsnt/


git-svn-id: http://moon:8086/svn/vhdl/branches/BRANCH_MIPS_TLB@1002 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
2013-08-18 08:02:23 +00:00
parent 06875daf11
commit 04bb65792b
4 changed files with 1013 additions and 0 deletions
+319
View File
@@ -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;
+276
View File
@@ -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 <http://www.gnu.org/licenses/>.
--
-- 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;
+350
View File
@@ -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;
+68
View File
@@ -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 <http://www.gnu.org/licenses/>.
--
-- 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;