2017-08-08 03:30:38 +02:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
|
|
|
package freechips.rocketchip.devices.tilelink
|
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import freechips.rocketchip.config.Parameters
|
|
|
|
import freechips.rocketchip.diplomacy._
|
|
|
|
import freechips.rocketchip.regmapper._
|
|
|
|
import freechips.rocketchip.tilelink._
|
|
|
|
import freechips.rocketchip.util._
|
|
|
|
|
2017-08-09 02:10:01 +02:00
|
|
|
case class DevicePMPParams(addressBits: Int, pageBits: Int)
|
2017-08-08 03:30:38 +02:00
|
|
|
class DevicePMP(params: DevicePMPParams) extends GenericParameterizedBundle(params)
|
|
|
|
{
|
2017-08-09 02:10:01 +02:00
|
|
|
require (params.addressBits > params.pageBits)
|
2017-08-08 03:30:38 +02:00
|
|
|
|
|
|
|
val l = UInt(width = 1) // locked
|
|
|
|
val a = UInt(width = 1) // LSB of A (0=disabled, 1=TOR)
|
|
|
|
val r = UInt(width = 1)
|
|
|
|
val w = UInt(width = 1)
|
|
|
|
|
2017-08-09 02:10:01 +02:00
|
|
|
val addr_hi = UInt(width = params.addressBits-params.pageBits)
|
|
|
|
def address = Cat(addr_hi, UInt(0, width=params.pageBits))
|
2017-08-09 01:43:59 +02:00
|
|
|
def blockPriorAddress = l(0) && a(0)
|
2017-08-08 03:30:38 +02:00
|
|
|
|
2017-08-09 01:43:59 +02:00
|
|
|
def fields(blockAddress: Bool): Seq[RegField] = {
|
|
|
|
def field(bits: Int, reg: UInt, lock: Bool = l(0)) =
|
2017-08-08 03:30:38 +02:00
|
|
|
RegField(bits, RegReadFn(reg), RegWriteFn((wen, data) => {
|
2017-08-09 01:43:59 +02:00
|
|
|
when (wen && !lock) { reg := data }
|
2017-08-08 03:30:38 +02:00
|
|
|
Bool(true)
|
|
|
|
}))
|
|
|
|
Seq(
|
|
|
|
RegField(10),
|
2017-08-09 02:10:01 +02:00
|
|
|
field(params.addressBits-params.pageBits, addr_hi, l(0) || blockAddress),
|
2017-08-08 03:30:38 +02:00
|
|
|
RegField(56 - (params.addressBits-2)),
|
|
|
|
field(1, r),
|
|
|
|
field(1, w),
|
|
|
|
RegField(1), // x
|
|
|
|
field(1, a),
|
|
|
|
RegField(3), // a high + 2 reserved
|
|
|
|
field(1, l))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object DevicePMP
|
|
|
|
{
|
2017-08-09 02:10:01 +02:00
|
|
|
def apply(addressBits: Int, pageBits: Int) = {
|
|
|
|
val out = Wire(new DevicePMP(DevicePMPParams(addressBits, pageBits)))
|
2017-08-08 03:30:38 +02:00
|
|
|
out.l := UInt(0)
|
2017-08-08 23:19:59 +02:00
|
|
|
out.a := UInt(0)
|
2017-08-08 03:30:38 +02:00
|
|
|
out.r := UInt(0)
|
|
|
|
out.w := UInt(0)
|
|
|
|
out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-11 22:16:50 +02:00
|
|
|
/** BusBlocker uses a set of DevicePMP registers to control whether
|
|
|
|
* accesses of certain types are allowed to proceed or bypassed to
|
|
|
|
* a /dev/null device.
|
|
|
|
*/
|
|
|
|
|
|
|
|
case class BusBlockerParams(
|
|
|
|
controlAddress: BigInt,
|
|
|
|
controlBeatBytes: Int,
|
|
|
|
deviceBeatBytes: Int,
|
|
|
|
pmpRegisters: Int)
|
|
|
|
{
|
|
|
|
val page = 4096
|
|
|
|
val pageBits = log2Ceil(page)
|
|
|
|
val size = (((pmpRegisters * 8) + page - 1) / page) * page
|
|
|
|
|
|
|
|
require (pmpRegisters > 0)
|
|
|
|
require (controlAddress > 0)
|
|
|
|
require (controlAddress % size == 0)
|
|
|
|
require (controlBeatBytes > 0 && isPow2(controlBeatBytes))
|
|
|
|
require (deviceBeatBytes > 0 && isPow2(deviceBeatBytes))
|
|
|
|
}
|
|
|
|
|
2017-08-08 03:30:38 +02:00
|
|
|
class BusBlocker(params: BusBlockerParams)(implicit p: Parameters) extends TLBusBypassBase(params.deviceBeatBytes)
|
|
|
|
{
|
|
|
|
val device = new SimpleDevice("bus-blocker", Seq("sifive,bus-blocker0"))
|
|
|
|
|
|
|
|
val controlNode = TLRegisterNode(
|
|
|
|
address = Seq(AddressSet(params.controlAddress, params.size-1)),
|
|
|
|
device = device,
|
|
|
|
beatBytes = params.controlBeatBytes)
|
|
|
|
|
|
|
|
lazy val module = new LazyModuleImp(this) {
|
|
|
|
// We need to be able to represent +1 larger than the largest populated address
|
2017-09-15 23:44:07 +02:00
|
|
|
val addressBits = log2Ceil(nodeOut.edges.out(0).manager.maxAddress+1+1)
|
2017-08-09 02:10:01 +02:00
|
|
|
val pmps = RegInit(Vec.fill(params.pmpRegisters) { DevicePMP(addressBits, params.pageBits) })
|
2017-08-09 01:43:59 +02:00
|
|
|
val blocks = pmps.tail.map(_.blockPriorAddress) :+ Bool(false)
|
|
|
|
controlNode.regmap(0 -> (pmps zip blocks).map { case (p, b) => p.fields(b) }.toList.flatten)
|
2017-08-08 03:30:38 +02:00
|
|
|
|
2017-09-14 03:06:03 +02:00
|
|
|
val (in, edge) = nodeIn.in(0)
|
2017-08-08 03:30:38 +02:00
|
|
|
|
|
|
|
// Determine if a request is allowed
|
|
|
|
val needW = in.a.bits.opcode =/= TLMessages.Get
|
|
|
|
val needR = in.a.bits.opcode =/= TLMessages.PutFullData && in.a.bits.opcode =/= TLMessages.PutPartialData
|
2017-08-09 01:44:51 +02:00
|
|
|
val lt = Bool(false) +: pmps.map(in.a.bits.address < _.address)
|
|
|
|
val sel = (pmps.map(_.a) zip (lt.init zip lt.tail)) map { case (a, (l, r)) => a(0) && !l && r }
|
2017-08-08 03:30:38 +02:00
|
|
|
val ok = pmps.map(p => (p.r(0) || !needR) && (p.w(0) || !needW))
|
2017-08-08 23:19:59 +02:00
|
|
|
val allow = PriorityMux(sel :+ Bool(true), ok :+ Bool(false)) // no match => deny
|
2017-08-08 03:30:38 +02:00
|
|
|
|
|
|
|
bar.module.io.bypass := !allow
|
|
|
|
}
|
|
|
|
}
|
2017-10-11 22:16:50 +02:00
|
|
|
|
|
|
|
/** BasicBusBlocker uses a single bit register to control whether
|
|
|
|
* accesses of all types are allowed to proceed or bypassed to
|
|
|
|
* a /dev/null device. It has a second bit register to report
|
|
|
|
* whether any requests are pending on either path.
|
|
|
|
*/
|
|
|
|
|
|
|
|
case class BasicBusBlockerParams(
|
|
|
|
controlAddress: BigInt,
|
|
|
|
controlBeatBytes: Int,
|
|
|
|
deviceBeatBytes: Int,
|
|
|
|
deadlock: Boolean = false)
|
|
|
|
|
|
|
|
class BasicBusBlocker(params: BasicBusBlockerParams)(implicit p: Parameters)
|
|
|
|
extends TLBusBypassBase(params.deviceBeatBytes, params.deadlock)
|
|
|
|
{
|
|
|
|
val device = new SimpleDevice("basic-bus-blocker", Seq("sifive,basic-bus-blocker0"))
|
|
|
|
|
|
|
|
val controlNode = TLRegisterNode(
|
|
|
|
address = Seq(AddressSet(params.controlAddress, 0xFFF)),
|
|
|
|
device = device,
|
|
|
|
beatBytes = params.controlBeatBytes)
|
|
|
|
|
|
|
|
lazy val module = new LazyModuleImp(this) {
|
|
|
|
val allow = RegInit(true.B)
|
|
|
|
val pending = RegNext(bar.module.io.pending)
|
|
|
|
|
|
|
|
controlNode.regmap(
|
|
|
|
0 -> Seq(RegField (32, allow)),
|
|
|
|
4 -> Seq(RegField.r(32, pending)))
|
|
|
|
|
|
|
|
bar.module.io.bypass := !allow
|
|
|
|
}
|
|
|
|
}
|