libmmu.vhd
254 lines
| 10.8 KiB
| text/x-vhdl
|
VhdlLexer
martin
|
r284 | ------------------------------------------------------------------------------ | ||
-- 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; | ||||