2016-11-28 01:16:37 +01:00
// See LICENSE.SiFive for license details.
// See LICENSE.Berkeley for license details.
2014-09-13 03:06:41 +02:00
2012-10-10 06:35:03 +02:00
package rocket
2013-07-24 05:26:17 +02:00
import Chisel._
2016-09-28 06:27:07 +02:00
import util._
2016-09-29 01:10:32 +02:00
import Chisel.ImplicitConversions._
2013-07-24 05:26:17 +02:00
import scala.math._
2016-11-18 23:05:14 +01:00
import config._
2016-11-21 20:48:10 +01:00
import diplomacy._
2016-11-22 20:50:41 +01:00
import uncore.util._
2016-11-21 20:48:10 +01:00
import uncore.tilelink2._
2012-10-10 06:35:03 +02:00
2017-01-17 03:24:08 +01:00
case object PAddrBits extends Field [ Int ]
2016-08-17 05:04:02 +02:00
case object PgLevels extends Field [ Int ]
case object ASIdBits extends Field [ Int ]
2015-02-02 05:04:13 +01:00
2016-12-13 02:38:55 +01:00
trait HasTLBParameters extends HasL1CacheParameters {
2016-11-18 21:02:33 +01:00
val entries = p ( p ( CacheName ) ) . nTLBEntries
2015-10-07 03:22:23 +02:00
val camAddrBits = log2Ceil ( entries )
2015-02-02 05:04:13 +01:00
val camTagBits = asIdBits + vpnBits
}
2015-10-06 06:48:05 +02:00
class TLBReq ( implicit p : Parameters ) extends CoreBundle ( ) ( p ) {
2016-03-11 02:32:00 +01:00
val vpn = UInt ( width = vpnBitsExtended )
2012-11-06 17:13:44 +01:00
val passthrough = Bool ( )
2012-10-10 06:35:03 +02:00
val instruction = Bool ( )
2015-03-14 10:49:07 +01:00
val store = Bool ( )
2012-10-10 06:35:03 +02:00
}
2016-07-02 23:26:05 +02:00
class TLBResp ( implicit p : Parameters ) extends CoreBundle ( ) ( p ) {
2012-10-10 06:35:03 +02:00
// lookup responses
val miss = Bool ( OUTPUT )
2015-02-02 05:04:13 +01:00
val ppn = UInt ( OUTPUT , ppnBits )
2012-10-10 06:35:03 +02:00
val xcpt_ld = Bool ( OUTPUT )
val xcpt_st = Bool ( OUTPUT )
val xcpt_if = Bool ( OUTPUT )
2016-07-09 10:08:52 +02:00
val cacheable = Bool ( OUTPUT )
2012-10-10 06:35:03 +02:00
}
2016-12-13 02:38:55 +01:00
class TLB ( implicit edge : TLEdgeOut , val p : Parameters ) extends Module with HasTLBParameters {
2012-10-10 06:35:03 +02:00
val io = new Bundle {
2013-08-12 19:39:11 +02:00
val req = Decoupled ( new TLBReq ) . flip
2015-02-02 05:04:13 +01:00
val resp = new TLBResp
2013-01-07 22:38:59 +01:00
val ptw = new TLBPTWIO
2012-10-10 06:35:03 +02:00
}
2016-07-02 23:26:05 +02:00
val valid = Reg ( init = UInt ( 0 , entries ) )
2016-08-03 00:11:48 +02:00
val ppns = Reg ( Vec ( entries , UInt ( width = ppnBits ) ) )
2016-07-02 23:26:05 +02:00
val tags = Reg ( Vec ( entries , UInt ( width = asIdBits + vpnBits ) ) )
2016-03-31 07:48:31 +02:00
2013-09-10 19:51:35 +02:00
val s_ready : : s_request :: s_wait :: s_wait_invalidate :: Nil = Enum ( UInt ( ) , 4 )
2013-08-16 00:28:15 +02:00
val state = Reg ( init = s_ready )
2016-07-02 23:26:05 +02:00
val r_refill_tag = Reg ( UInt ( width = asIdBits + vpnBits ) )
val r_refill_waddr = Reg ( UInt ( width = log2Ceil ( entries ) ) )
2015-03-14 10:49:07 +01:00
val r_req = Reg ( new TLBReq )
2016-08-03 00:11:48 +02:00
val do_mprv = io . ptw . status . mprv && ! io . req . bits . instruction
val priv = Mux ( do_mprv , io . ptw . status . mpp , io . ptw . status . prv )
val priv_s = priv === PRV . S
val priv_uses_vm = priv <= PRV . S && ! io . ptw . status . debug
// share a single physical memory attribute checker (unshare if critical path)
val passthrough_ppn = io . req . bits . vpn ( ppnBits - 1 , 0 )
val refill_ppn = io . ptw . resp . bits . pte . ppn ( ppnBits - 1 , 0 )
val do_refill = Bool ( usingVM ) && io . ptw . resp . valid
val mpu_ppn = Mux ( do_refill , refill_ppn , passthrough_ppn )
2016-11-27 00:11:42 +01:00
val mpu_physaddr = mpu_ppn << pgIdxBits
val legal_address = edge . manager . findSafe ( mpu_physaddr ) . reduce ( _ || _ )
2016-11-21 20:48:10 +01:00
def fastCheck ( member : TLManagerParameters => Boolean ) =
2016-11-27 00:11:42 +01:00
legal_address && Mux1H ( edge . manager . findFast ( mpu_physaddr ) , edge . manager . managers . map ( m => Bool ( member ( m ) ) ) )
2016-11-21 20:48:10 +01:00
val prot_r = fastCheck ( _ . supportsGet )
val prot_w = fastCheck ( _ . supportsPutFull )
val prot_x = fastCheck ( _ . executable )
2017-01-18 03:52:16 +01:00
val cacheable = fastCheck ( _ . supportsAcquireB )
2016-11-21 20:48:10 +01:00
val allSizes = TransferSizes ( 1 , cacheBlockBytes )
val amoSizes = TransferSizes ( 1 , xLen / 8 )
edge . manager . managers . foreach { m =>
require ( m . minAlignment >= 4096 , s" MemoryMap region ${ m . name } must be page-aligned (is ${ m . minAlignment } ) " )
2017-01-18 03:52:16 +01:00
require ( ! m . supportsGet || m . supportsGet . contains ( allSizes ) , s" MemoryMap region ${ m . name } only supports ${ m . supportsGet } Get, but must support ${ allSizes } " )
require ( ! m . supportsPutFull || m . supportsPutFull . contains ( allSizes ) , s" MemoryMap region ${ m . name } only supports ${ m . supportsPutFull } PutFull, but must support ${ allSizes } " )
require ( ! m . supportsAcquireB || m . supportsAcquireB . contains ( allSizes ) , s" MemoryMap region ${ m . name } only supports ${ m . supportsAcquireB } AcquireB, but must support ${ allSizes } " )
require ( ! m . supportsAcquireT || m . supportsAcquireT . contains ( allSizes ) , s" MemoryMap region ${ m . name } only supports ${ m . supportsAcquireT } AcquireT, but must support ${ allSizes } " )
require ( ! m . supportsLogical || m . supportsLogical . contains ( amoSizes ) , s" MemoryMap region ${ m . name } only supports ${ m . supportsLogical } Logical, but must support ${ amoSizes } " )
2016-11-21 20:48:10 +01:00
require ( ! m . supportsArithmetic || m . supportsArithmetic . contains ( amoSizes ) , s" MemoryMap region ${ m . name } only supports ${ m . supportsArithmetic } Arithmetic, but must support ${ amoSizes } " )
2017-01-18 03:52:16 +01:00
require ( m . supportsAcquireT || ! m . supportsPutFull || ! m . supportsAcquireB , s" MemoryMap region ${ m . name } supports PutFull and AcquireB but not AcquireT " )
2016-08-10 07:14:32 +02:00
}
2016-11-21 20:48:10 +01:00
2016-08-01 02:13:52 +02:00
val lookup_tag = Cat ( io . ptw . ptbr . asid , io . req . bits . vpn ( vpnBits - 1 , 0 ) )
2016-08-03 00:11:48 +02:00
val vm_enabled = Bool ( usingVM ) && io . ptw . status . vm ( 3 ) && priv_uses_vm && ! io . req . bits . passthrough
val hitsVec = ( 0 until entries ) . map ( i => valid ( i ) && vm_enabled && tags ( i ) === lookup_tag ) : + ! vm_enabled
2016-08-01 02:13:52 +02:00
val hits = hitsVec . asUInt
2012-10-10 06:35:03 +02:00
// permission bit arrays
2016-07-06 04:19:49 +02:00
val pte_array = Reg ( new PTE )
val u_array = Reg ( UInt ( width = entries ) ) // user permission
val sw_array = Reg ( UInt ( width = entries ) ) // write permission
val sx_array = Reg ( UInt ( width = entries ) ) // execute permission
val sr_array = Reg ( UInt ( width = entries ) ) // read permission
2016-08-03 00:11:48 +02:00
val xr_array = Reg ( UInt ( width = entries ) ) // read permission to executable page
val cash_array = Reg ( UInt ( width = entries ) ) // cacheable
2016-07-02 23:26:05 +02:00
val dirty_array = Reg ( UInt ( width = entries ) ) // PTE dirty bit
2016-08-03 00:11:48 +02:00
when ( do_refill ) {
2015-03-28 00:20:59 +01:00
val pte = io . ptw . resp . bits . pte
2016-07-02 23:26:05 +02:00
ppns ( r_refill_waddr ) : = pte . ppn
tags ( r_refill_waddr ) : = r_refill_tag
val mask = UIntToOH ( r_refill_waddr )
valid : = valid | mask
2016-07-06 04:19:49 +02:00
u_array : = Mux ( pte . u , u_array | mask , u_array & ~ mask )
2016-11-21 20:48:10 +01:00
sw_array : = Mux ( pte . sw ( ) && prot_w , sw_array | mask , sw_array & ~ mask )
sx_array : = Mux ( pte . sx ( ) && prot_x , sx_array | mask , sx_array & ~ mask )
sr_array : = Mux ( pte . sr ( ) && prot_r , sr_array | mask , sr_array & ~ mask )
xr_array : = Mux ( pte . sx ( ) && prot_r , xr_array | mask , xr_array & ~ mask )
2016-08-03 00:11:48 +02:00
cash_array : = Mux ( cacheable , cash_array | mask , cash_array & ~ mask )
2016-07-02 23:26:05 +02:00
dirty_array : = Mux ( pte . d , dirty_array | mask , dirty_array & ~ mask )
2012-10-10 06:35:03 +02:00
}
val plru = new PseudoLRU ( entries )
2016-07-02 23:26:05 +02:00
val repl_waddr = Mux ( ! valid . andR , PriorityEncoder ( ~ valid ) , plru . replace )
2016-03-03 08:29:58 +01:00
2016-07-06 04:19:49 +02:00
val priv_ok = Mux ( priv_s , ~ Mux ( io . ptw . status . pum , u_array , UInt ( 0 ) ) , u_array )
2016-11-21 20:48:10 +01:00
val w_array = Cat ( prot_w , priv_ok & sw_array )
val x_array = Cat ( prot_x , priv_ok & sx_array )
val r_array = Cat ( prot_r , priv_ok & ( sr_array | Mux ( io . ptw . status . mxr , xr_array , UInt ( 0 ) ) ) )
2016-08-03 00:11:48 +02:00
val c_array = Cat ( cacheable , cash_array )
2015-03-14 10:49:07 +01:00
2016-03-11 02:32:00 +01:00
val bad_va =
if ( vpnBits == vpnBitsExtended ) Bool ( false )
else io . req . bits . vpn ( vpnBits ) =/= io . req . bits . vpn ( vpnBits - 1 )
2015-03-14 10:49:07 +01:00
// it's only a store hit if the dirty bit is set
2016-08-03 00:11:48 +02:00
val tlb_hits = hits ( entries - 1 , 0 ) & ( dirty_array | ~ Mux ( io . req . bits . store , w_array , UInt ( 0 ) ) )
val tlb_hit = tlb_hits . orR
val tlb_miss = vm_enabled && ! bad_va && ! tlb_hit
2015-09-22 18:42:27 +02:00
2016-08-03 00:11:48 +02:00
when ( io . req . valid && ! tlb_miss ) {
plru . access ( OHToUInt ( hits ( entries - 1 , 0 ) ) )
2012-10-10 06:35:03 +02:00
}
io . req . ready : = state === s_ready
2016-08-03 00:11:48 +02:00
io . resp . xcpt_ld : = bad_va || ( ~ r_array & hits ) . orR
io . resp . xcpt_st : = bad_va || ( ~ w_array & hits ) . orR
io . resp . xcpt_if : = bad_va || ( ~ x_array & hits ) . orR
io . resp . cacheable : = ( c_array & hits ) . orR
io . resp . miss : = do_refill || tlb_miss
io . resp . ppn : = Mux1H ( hitsVec , ppns : + passthrough_ppn )
2015-03-14 10:49:07 +01:00
2012-10-10 06:35:03 +02:00
io . ptw . req . valid : = state === s_request
2016-10-05 07:28:56 +02:00
io . ptw . req . bits <> io . ptw . status
2015-03-14 10:49:07 +01:00
io . ptw . req . bits . addr : = r_refill_tag
2015-03-28 00:20:59 +01:00
io . ptw . req . bits . store : = r_req . store
io . ptw . req . bits . fetch : = r_req . instruction
2012-10-10 06:35:03 +02:00
2016-03-25 22:17:25 +01:00
if ( usingVM ) {
when ( io . req . fire ( ) && tlb_miss ) {
state : = s_request
r_refill_tag : = lookup_tag
r_refill_waddr : = repl_waddr
r_req : = io . req . bits
2012-10-10 06:35:03 +02:00
}
2016-03-25 22:17:25 +01:00
when ( state === s_request ) {
when ( io . ptw . invalidate ) {
state : = s_ready
}
when ( io . ptw . req . ready ) {
state : = s_wait
when ( io . ptw . invalidate ) { state : = s_wait_invalidate }
}
}
when ( state === s_wait && io . ptw . invalidate ) {
state : = s_wait_invalidate
}
when ( io . ptw . resp . valid ) {
state : = s_ready
2012-10-10 06:35:03 +02:00
}
2016-07-02 23:26:05 +02:00
when ( io . ptw . invalidate ) {
valid : = 0
}
2012-10-10 06:35:03 +02:00
}
}
2016-01-14 20:37:58 +01:00
2016-12-13 02:38:55 +01:00
class DecoupledTLB ( implicit edge : TLEdgeOut , p : Parameters ) extends Module {
2016-01-14 20:37:58 +01:00
val io = new Bundle {
val req = Decoupled ( new TLBReq ) . flip
val resp = Decoupled ( new TLBResp )
val ptw = new TLBPTWIO
}
2016-08-24 03:36:03 +02:00
val req = Reg ( new TLBReq )
val resp = Reg ( new TLBResp )
2016-01-14 20:37:58 +01:00
val tlb = Module ( new TLB )
2016-08-24 03:36:03 +02:00
val s_idle : : s_tlb_req :: s_tlb_resp :: s_done :: Nil = Enum ( Bits ( ) , 4 )
val state = Reg ( init = s_idle )
2016-01-14 20:37:58 +01:00
2016-08-24 03:36:03 +02:00
when ( io . req . fire ( ) ) {
req : = io . req . bits
state : = s_tlb_req
}
when ( tlb . io . req . fire ( ) ) {
state : = s_tlb_resp
}
when ( state === s_tlb_resp ) {
when ( tlb . io . resp . miss ) {
state : = s_tlb_req
} . otherwise {
resp : = tlb . io . resp
state : = s_done
}
}
when ( io . resp . fire ( ) ) { state : = s_idle }
io . req . ready : = state === s_idle
tlb . io . req . valid : = state === s_tlb_req
tlb . io . req . bits : = req
2016-01-14 20:37:58 +01:00
2016-08-24 03:36:03 +02:00
io . resp . valid : = state === s_done
io . resp . bits : = resp
2016-01-14 20:37:58 +01:00
io . ptw <> tlb . io . ptw
}