From 04bb65792b945276f5fa17817c40ad7603afe5c6 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sun, 18 Aug 2013 08:02:23 +0000 Subject: [PATCH] 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 --- lib/CPUs/MIPS/src/core/mips_cam.vhd | 319 +++++++++++++++++++++ lib/CPUs/MIPS/src/core/mips_func_pkg.vhd | 276 ++++++++++++++++++ lib/CPUs/MIPS/src/core/mips_tlb.vhd | 350 +++++++++++++++++++++++ lib/CPUs/MIPS/src/core/mips_util_pkg.vhd | 68 +++++ 4 files changed, 1013 insertions(+) create mode 100644 lib/CPUs/MIPS/src/core/mips_cam.vhd create mode 100644 lib/CPUs/MIPS/src/core/mips_func_pkg.vhd create mode 100644 lib/CPUs/MIPS/src/core/mips_tlb.vhd create mode 100644 lib/CPUs/MIPS/src/core/mips_util_pkg.vhd 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; +