|
|
------------------------------------------------------------------------------
|
|
|
-- This file is a part of the GRLIB VHDL IP LIBRARY
|
|
|
-- Copyright (C) 2003 - 2008, Gaisler Research
|
|
|
-- Copyright (C) 2008 - 2010, Aeroflex Gaisler
|
|
|
--
|
|
|
-- 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 2 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, write to the Free Software
|
|
|
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
-----------------------------------------------------------------------------
|
|
|
-- Package: leon3
|
|
|
-- File: leon3.vhd
|
|
|
-- Author: Konrad Eisele, Jiri Gaisler, Gaisler Research
|
|
|
-- Description: MMU component declaration
|
|
|
------------------------------------------------------------------------------
|
|
|
|
|
|
library ieee;
|
|
|
use ieee.std_logic_1164.all;
|
|
|
library grlib;
|
|
|
use grlib.stdlib.all;
|
|
|
library techmap;
|
|
|
use techmap.gencomp.all;
|
|
|
library gaisler;
|
|
|
use gaisler.mmuconfig.all;
|
|
|
use gaisler.mmuiface.all;
|
|
|
|
|
|
package libmmu is
|
|
|
|
|
|
component mmu
|
|
|
generic (
|
|
|
tech : integer range 0 to NTECH := 0;
|
|
|
itlbnum : integer range 2 to 64 := 8;
|
|
|
dtlbnum : integer range 2 to 64 := 8;
|
|
|
tlb_type : integer range 0 to 3 := 1;
|
|
|
tlb_rep : integer range 0 to 1 := 0;
|
|
|
mmupgsz : integer range 0 to 5 := 0
|
|
|
);
|
|
|
port (
|
|
|
rst : in std_logic;
|
|
|
clk : in std_logic;
|
|
|
|
|
|
mmudci : in mmudc_in_type;
|
|
|
mmudco : out mmudc_out_type;
|
|
|
|
|
|
mmuici : in mmuic_in_type;
|
|
|
mmuico : out mmuic_out_type;
|
|
|
|
|
|
mcmmo : in memory_mm_out_type;
|
|
|
mcmmi : out memory_mm_in_type
|
|
|
);
|
|
|
end component;
|
|
|
|
|
|
|
|
|
function TLB_CreateCamWrite( two_data : std_logic_vector(31 downto 0);
|
|
|
read : std_logic;
|
|
|
lvl : std_logic_vector(1 downto 0);
|
|
|
ctx : std_logic_vector(M_CTX_SZ-1 downto 0);
|
|
|
vaddr : std_logic_vector(31 downto 0)
|
|
|
) return tlbcam_reg;
|
|
|
|
|
|
procedure TLB_CheckFault( ACC : in std_logic_vector(2 downto 0);
|
|
|
isid : in mmu_idcache;
|
|
|
su : in std_logic;
|
|
|
read : in std_logic;
|
|
|
fault_pro : out std_logic;
|
|
|
fault_pri : out std_logic );
|
|
|
|
|
|
procedure TLB_MergeData( mmupgsz : in integer range 0 to 5;
|
|
|
mmctrl : in mmctrl_type1;
|
|
|
LVL : in std_logic_vector(1 downto 0);
|
|
|
PTE : in std_logic_vector(31 downto 0);
|
|
|
data : in std_logic_vector(31 downto 0);
|
|
|
transdata : out std_logic_vector(31 downto 0));
|
|
|
|
|
|
function TLB_CreateCamTrans( vaddr : std_logic_vector(31 downto 0);
|
|
|
read : std_logic;
|
|
|
ctx : std_logic_vector(M_CTX_SZ-1 downto 0)
|
|
|
) return tlbcam_tfp;
|
|
|
|
|
|
function TLB_CreateCamFlush( data : std_logic_vector(31 downto 0);
|
|
|
ctx : std_logic_vector(M_CTX_SZ-1 downto 0)
|
|
|
) return tlbcam_tfp;
|
|
|
|
|
|
subtype mmu_gpsz_typ is integer range 0 to 3;
|
|
|
function MMU_getpagesize( mmupgsz : in integer range 0 to 4;
|
|
|
mmctrl : in mmctrl_type1
|
|
|
) return mmu_gpsz_typ;
|
|
|
end;
|
|
|
|
|
|
package body libmmu is
|
|
|
|
|
|
procedure TLB_CheckFault( ACC : in std_logic_vector(2 downto 0);
|
|
|
isid : in mmu_idcache;
|
|
|
su : in std_logic;
|
|
|
read : in std_logic;
|
|
|
fault_pro : out std_logic;
|
|
|
fault_pri : out std_logic ) is
|
|
|
variable c_isd : std_logic;
|
|
|
begin
|
|
|
fault_pro := '0';
|
|
|
fault_pri := '0';
|
|
|
|
|
|
-- use '0' == icache '1' == dcache
|
|
|
if isid = id_icache then
|
|
|
c_isd := '0';
|
|
|
else
|
|
|
c_isd := '1';
|
|
|
end if;
|
|
|
--# fault, todo: should we flush on a fault?
|
|
|
case ACC is
|
|
|
when "000" => fault_pro := (not c_isd) or (not read);
|
|
|
when "001" => fault_pro := (not c_isd);
|
|
|
when "010" => fault_pro := (not read);
|
|
|
when "011" => null;
|
|
|
when "100" => fault_pro := (c_isd);
|
|
|
when "101" => fault_pro := (not c_isd) or ((not read) and (not su));
|
|
|
when "110" => fault_pri := (not su);
|
|
|
fault_pro := (not read);
|
|
|
when "111" => fault_pri := (not su);
|
|
|
when others => null;
|
|
|
end case;
|
|
|
end;
|
|
|
|
|
|
procedure TLB_MergeData( mmupgsz : in integer range 0 to 5;
|
|
|
mmctrl : in mmctrl_type1;
|
|
|
LVL : in std_logic_vector(1 downto 0);
|
|
|
PTE : in std_logic_vector(31 downto 0);
|
|
|
data : in std_logic_vector(31 downto 0);
|
|
|
transdata : out std_logic_vector(31 downto 0) ) is
|
|
|
variable pagesize : integer range 0 to 3;
|
|
|
begin
|
|
|
|
|
|
--# merge data
|
|
|
transdata := (others => '0');
|
|
|
pagesize := MMU_getpagesize(mmupgsz, mmctrl);
|
|
|
case pagesize is
|
|
|
when 1 =>
|
|
|
-- 8k
|
|
|
case LVL is
|
|
|
when LVL_PAGE => transdata := PTE(P8K_PTE_PPN32PAG_U downto P8K_PTE_PPN32PAG_D) & data(P8K_VA_OFFPAG_U downto P8K_VA_OFFPAG_D);
|
|
|
when LVL_SEGMENT => transdata := PTE(P8K_PTE_PPN32SEG_U downto P8K_PTE_PPN32SEG_D) & data(P8K_VA_OFFSEG_U downto P8K_VA_OFFSEG_D);
|
|
|
when LVL_REGION => transdata := PTE(P8K_PTE_PPN32REG_U downto P8K_PTE_PPN32REG_D) & data(P8K_VA_OFFREG_U downto P8K_VA_OFFREG_D);
|
|
|
when LVL_CTX => transdata := data(P8K_VA_OFFCTX_U downto P8K_VA_OFFCTX_D);
|
|
|
when others => transdata := (others => 'X');
|
|
|
end case;
|
|
|
when 2 =>
|
|
|
-- 16k
|
|
|
case LVL is
|
|
|
when LVL_PAGE => transdata := PTE(P16K_PTE_PPN32PAG_U downto P16K_PTE_PPN32PAG_D) & data(P16K_VA_OFFPAG_U downto P16K_VA_OFFPAG_D);
|
|
|
when LVL_SEGMENT => transdata := PTE(P16K_PTE_PPN32SEG_U downto P16K_PTE_PPN32SEG_D) & data(P16K_VA_OFFSEG_U downto P16K_VA_OFFSEG_D);
|
|
|
when LVL_REGION => transdata := PTE(P16K_PTE_PPN32REG_U downto P16K_PTE_PPN32REG_D) & data(P16K_VA_OFFREG_U downto P16K_VA_OFFREG_D);
|
|
|
when LVL_CTX => transdata := data(P16K_VA_OFFCTX_U downto P16K_VA_OFFCTX_D);
|
|
|
when others => transdata := (others => 'X');
|
|
|
end case;
|
|
|
when 3 =>
|
|
|
-- 32k
|
|
|
case LVL is
|
|
|
when LVL_PAGE => transdata := PTE(P32K_PTE_PPN32PAG_U downto P32K_PTE_PPN32PAG_D) & data(P32K_VA_OFFPAG_U downto P32K_VA_OFFPAG_D);
|
|
|
when LVL_SEGMENT => transdata := PTE(P32K_PTE_PPN32SEG_U downto P32K_PTE_PPN32SEG_D) & data(P32K_VA_OFFSEG_U downto P32K_VA_OFFSEG_D);
|
|
|
when LVL_REGION => transdata := PTE(P32K_PTE_PPN32REG_U downto P32K_PTE_PPN32REG_D) & data(P32K_VA_OFFREG_U downto P32K_VA_OFFREG_D);
|
|
|
when LVL_CTX => transdata := data(P32K_VA_OFFCTX_U downto P32K_VA_OFFCTX_D);
|
|
|
when others => transdata := (others => 'X');
|
|
|
end case;
|
|
|
when others =>
|
|
|
-- 4k
|
|
|
case LVL is
|
|
|
when LVL_PAGE => transdata := PTE(PTE_PPN32PAG_U downto PTE_PPN32PAG_D) & data(VA_OFFPAG_U downto VA_OFFPAG_D);
|
|
|
when LVL_SEGMENT => transdata := PTE(PTE_PPN32SEG_U downto PTE_PPN32SEG_D) & data(VA_OFFSEG_U downto VA_OFFSEG_D);
|
|
|
when LVL_REGION => transdata := PTE(PTE_PPN32REG_U downto PTE_PPN32REG_D) & data(VA_OFFREG_U downto VA_OFFREG_D);
|
|
|
when LVL_CTX => transdata := data(VA_OFFCTX_U downto VA_OFFCTX_D);
|
|
|
when others => transdata := (others => 'X');
|
|
|
end case;
|
|
|
end case;
|
|
|
|
|
|
end;
|
|
|
|
|
|
function TLB_CreateCamWrite( two_data : std_logic_vector(31 downto 0);
|
|
|
read : std_logic;
|
|
|
lvl : std_logic_vector(1 downto 0);
|
|
|
ctx : std_logic_vector(M_CTX_SZ-1 downto 0);
|
|
|
vaddr : std_logic_vector(31 downto 0)
|
|
|
) return tlbcam_reg is
|
|
|
variable tlbcam_tagwrite : tlbcam_reg;
|
|
|
begin
|
|
|
|
|
|
tlbcam_tagwrite.ET := two_data(PT_ET_U downto PT_ET_D);
|
|
|
tlbcam_tagwrite.ACC := two_data(PTE_ACC_U downto PTE_ACC_D);
|
|
|
tlbcam_tagwrite.M := two_data(PTE_M) or (not read); -- tw : p-update modified
|
|
|
tlbcam_tagwrite.R := '1';
|
|
|
case tlbcam_tagwrite.ACC is -- tw : p-su ACC >= 6
|
|
|
when "110" | "111" => tlbcam_tagwrite.SU := '1';
|
|
|
when others => tlbcam_tagwrite.SU := '0';
|
|
|
end case;
|
|
|
tlbcam_tagwrite.VALID := '1';
|
|
|
tlbcam_tagwrite.LVL := lvl;
|
|
|
tlbcam_tagwrite.I1 := vaddr(VA_I1_U downto VA_I1_D);
|
|
|
tlbcam_tagwrite.I2 := vaddr(VA_I2_U downto VA_I2_D);
|
|
|
tlbcam_tagwrite.I3 := vaddr(VA_I3_U downto VA_I3_D);
|
|
|
tlbcam_tagwrite.CTX := ctx;
|
|
|
tlbcam_tagwrite.PPN := two_data(PTE_PPN_U downto PTE_PPN_D);
|
|
|
tlbcam_tagwrite.C := two_data(PTE_C);
|
|
|
return tlbcam_tagwrite;
|
|
|
end;
|
|
|
|
|
|
function MMU_getpagesize( mmupgsz : in integer range 0 to 4;
|
|
|
mmctrl : in mmctrl_type1
|
|
|
) return mmu_gpsz_typ is
|
|
|
variable pagesize : mmu_gpsz_typ;
|
|
|
begin
|
|
|
if mmupgsz = 4 then pagesize := conv_integer(mmctrl.pagesize); -- variable
|
|
|
else pagesize := mmupgsz; end if;
|
|
|
return pagesize;
|
|
|
end;
|
|
|
|
|
|
function TLB_CreateCamTrans( vaddr : std_logic_vector(31 downto 0);
|
|
|
read : std_logic;
|
|
|
ctx : std_logic_vector(M_CTX_SZ-1 downto 0)
|
|
|
) return tlbcam_tfp is
|
|
|
variable mtag : tlbcam_tfp;
|
|
|
begin
|
|
|
mtag.TYP := (others => '0');
|
|
|
mtag.I1 := vaddr(VA_I1_U downto VA_I1_D);
|
|
|
mtag.I2 := vaddr(VA_I2_U downto VA_I2_D);
|
|
|
mtag.I3 := vaddr(VA_I3_U downto VA_I3_D);
|
|
|
mtag.CTX := ctx;
|
|
|
mtag.M := not (read);
|
|
|
return mtag;
|
|
|
end;
|
|
|
|
|
|
function TLB_CreateCamFlush( data : std_logic_vector(31 downto 0);
|
|
|
ctx : std_logic_vector(M_CTX_SZ-1 downto 0)
|
|
|
) return tlbcam_tfp is
|
|
|
variable ftag : tlbcam_tfp;
|
|
|
begin
|
|
|
ftag.TYP := data(FPTY_U downto FPTY_D);
|
|
|
ftag.I1 := data(FPA_I1_U downto FPA_I1_D);
|
|
|
ftag.I2 := data(FPA_I2_U downto FPA_I2_D);
|
|
|
ftag.I3 := data(FPA_I3_U downto FPA_I3_D);
|
|
|
ftag.CTX := ctx;
|
|
|
ftag.M := '0';
|
|
|
return ftag;
|
|
|
end;
|
|
|
|
|
|
end;
|
|
|
|
|
|
|