2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
2016-05-03 00:19:43 +02:00
|
|
|
|
2017-07-07 19:48:16 +02:00
|
|
|
package freechips.rocketchip.devices.tilelink
|
2016-05-03 00:19:43 +02:00
|
|
|
|
|
|
|
import Chisel._
|
2017-07-23 17:31:04 +02:00
|
|
|
import freechips.rocketchip.config.{Field, Parameters}
|
|
|
|
import freechips.rocketchip.coreplex.HasPeripheryBus
|
2017-07-07 19:48:16 +02:00
|
|
|
import freechips.rocketchip.diplomacy._
|
|
|
|
import freechips.rocketchip.regmapper._
|
|
|
|
import freechips.rocketchip.tile.XLen
|
|
|
|
import freechips.rocketchip.tilelink._
|
|
|
|
import freechips.rocketchip.util._
|
2016-09-16 07:06:39 +02:00
|
|
|
import scala.math.{min,max}
|
2016-05-03 00:19:43 +02:00
|
|
|
|
2016-10-29 06:20:49 +02:00
|
|
|
object ClintConsts
|
|
|
|
{
|
2016-09-16 23:26:34 +02:00
|
|
|
def msipOffset(hart: Int) = hart * msipBytes
|
|
|
|
def timecmpOffset(hart: Int) = 0x4000 + hart * timecmpBytes
|
|
|
|
def timeOffset = 0xbff8
|
2016-06-28 08:05:48 +02:00
|
|
|
def msipBytes = 4
|
|
|
|
def timecmpBytes = 8
|
2016-09-16 23:26:34 +02:00
|
|
|
def size = 0x10000
|
2017-03-02 06:57:00 +01:00
|
|
|
def timeWidth = 64
|
|
|
|
def regWidth = 32
|
|
|
|
def ints = 2
|
2016-06-28 08:05:48 +02:00
|
|
|
}
|
|
|
|
|
2017-09-06 23:20:46 +02:00
|
|
|
case class ClintParams(baseAddress: BigInt = 0x02000000, intStages: Int = 0)
|
2017-06-21 01:11:57 +02:00
|
|
|
{
|
|
|
|
def address = AddressSet(baseAddress, ClintConsts.size-1)
|
|
|
|
}
|
|
|
|
|
2017-09-09 03:33:44 +02:00
|
|
|
case object ClintKey extends Field(ClintParams())
|
2017-07-23 17:31:04 +02:00
|
|
|
|
2017-06-21 02:21:53 +02:00
|
|
|
class CoreplexLocalInterrupter(params: ClintParams)(implicit p: Parameters) extends LazyModule
|
2017-03-02 06:57:00 +01:00
|
|
|
{
|
|
|
|
import ClintConsts._
|
2016-06-28 08:05:48 +02:00
|
|
|
|
2017-03-02 06:57:00 +01:00
|
|
|
// clint0 => at most 4095 devices
|
|
|
|
val device = new SimpleDevice("clint", Seq("riscv,clint0")) {
|
|
|
|
override val alwaysExtended = true
|
2016-09-21 00:00:52 +02:00
|
|
|
}
|
|
|
|
|
2017-03-02 06:57:00 +01:00
|
|
|
val node = TLRegisterNode(
|
2017-06-21 01:11:57 +02:00
|
|
|
address = Seq(params.address),
|
2017-03-02 06:57:00 +01:00
|
|
|
device = device,
|
|
|
|
beatBytes = p(XLen)/8)
|
2016-06-28 08:05:48 +02:00
|
|
|
|
2017-03-02 06:57:00 +01:00
|
|
|
val intnode = IntNexusNode(
|
|
|
|
numSourcePorts = 0 to 1024,
|
|
|
|
numSinkPorts = 0 to 0,
|
|
|
|
sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(ints, Seq(Resource(device, "int"))))) },
|
|
|
|
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) })
|
2016-09-15 03:09:27 +02:00
|
|
|
|
2017-03-02 06:57:00 +01:00
|
|
|
lazy val module = new LazyModuleImp(this) {
|
2017-09-14 03:06:03 +02:00
|
|
|
val io = IO(new Bundle {
|
2017-03-02 06:57:00 +01:00
|
|
|
val rtcTick = Bool(INPUT)
|
2017-09-14 03:06:03 +02:00
|
|
|
})
|
2017-03-02 06:57:00 +01:00
|
|
|
|
|
|
|
val time = Seq.fill(timeWidth/regWidth)(Reg(init=UInt(0, width = regWidth)))
|
|
|
|
when (io.rtcTick) {
|
|
|
|
val newTime = time.asUInt + UInt(1)
|
|
|
|
for ((reg, i) <- time zip (0 until timeWidth by regWidth))
|
|
|
|
reg := newTime >> i
|
|
|
|
}
|
|
|
|
|
2017-09-14 03:06:03 +02:00
|
|
|
val nTiles = intnode.out.size
|
2017-06-21 01:11:57 +02:00
|
|
|
val timecmp = Seq.fill(nTiles) { Seq.fill(timeWidth/regWidth)(Reg(UInt(width = regWidth))) }
|
|
|
|
val ipi = Seq.fill(nTiles) { RegInit(UInt(0, width = 1)) }
|
2017-03-02 06:57:00 +01:00
|
|
|
|
2017-09-15 23:44:07 +02:00
|
|
|
val (intnode_in, _) = intnode.in.unzip
|
|
|
|
intnode_in.zipWithIndex.foreach { case (int, i) =>
|
2017-09-06 23:20:46 +02:00
|
|
|
int(0) := ShiftRegister(ipi(i)(0), params.intStages) // msip
|
|
|
|
int(1) := ShiftRegister(time.asUInt >= timecmp(i).asUInt, params.intStages) // mtip
|
2017-03-02 06:57:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 0000 msip hart 0
|
|
|
|
* 0004 msip hart 1
|
|
|
|
* 4000 mtimecmp hart 0 lo
|
|
|
|
* 4004 mtimecmp hart 0 hi
|
|
|
|
* 4008 mtimecmp hart 1 lo
|
|
|
|
* 400c mtimecmp hart 1 hi
|
|
|
|
* bff8 mtime lo
|
|
|
|
* bffc mtime hi
|
|
|
|
*/
|
|
|
|
|
|
|
|
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
|
|
|
|
|
|
|
|
node.regmap(
|
|
|
|
0 -> makeRegFields(ipi),
|
|
|
|
timecmpOffset(0) -> makeRegFields(timecmp.flatten),
|
|
|
|
timeOffset -> makeRegFields(time))
|
2016-11-22 23:58:03 +01:00
|
|
|
}
|
|
|
|
}
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
/** Trait that will connect a Clint to a coreplex */
|
|
|
|
trait HasPeripheryClint extends HasPeripheryBus {
|
2017-09-09 03:33:44 +02:00
|
|
|
val clint = LazyModule(new CoreplexLocalInterrupter(p(ClintKey)))
|
2017-07-23 17:31:04 +02:00
|
|
|
clint.node := pbus.toVariableWidthSlaves
|
|
|
|
}
|