12d0c00822
RegField.bytes was unconditionally overwriting mtime, preventing it from ever ticking. Avoid RegField.bytes by splitting mtime into a Seq of words.
98 lines
3.1 KiB
Scala
98 lines
3.1 KiB
Scala
// See LICENSE for license details.
|
|
|
|
package uncore.devices
|
|
|
|
import Chisel._
|
|
import rocket.Util._
|
|
import junctions._
|
|
import junctions.NastiConstants._
|
|
import uncore.tilelink2._
|
|
import uncore.util._
|
|
import scala.math.{min,max}
|
|
import cde.{Parameters, Field}
|
|
|
|
/** Number of tiles */
|
|
case object NTiles extends Field[Int]
|
|
|
|
class CoreplexLocalInterrupts extends Bundle {
|
|
val mtip = Bool()
|
|
val msip = Bool()
|
|
}
|
|
|
|
case class CoreplexLocalInterrupterConfig(beatBytes: Int, address: BigInt = 0x44000000) {
|
|
def msipOffset(hart: Int) = hart * msipBytes
|
|
def msipAddress(hart: Int) = address + msipOffset(hart)
|
|
def timecmpOffset(hart: Int) = 0x4000 + hart * timecmpBytes
|
|
def timecmpAddress(hart: Int) = address + timecmpOffset(hart)
|
|
def timeOffset = 0xbff8
|
|
def timeAddress = address + timeOffset
|
|
def msipBytes = 4
|
|
def timecmpBytes = 8
|
|
def size = 0x10000
|
|
}
|
|
|
|
trait MixCoreplexLocalInterrupterParameters {
|
|
val params: (CoreplexLocalInterrupterConfig, Parameters)
|
|
val c = params._1
|
|
implicit val p = params._2
|
|
}
|
|
|
|
trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterrupterParameters {
|
|
val tiles = Vec(p(NTiles), new CoreplexLocalInterrupts).asOutput
|
|
val rtcTick = Bool(INPUT)
|
|
}
|
|
|
|
trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCoreplexLocalInterrupterParameters {
|
|
val io: CoreplexLocalInterrupterBundle
|
|
|
|
val timeWidth = 64
|
|
val regWidth = 32
|
|
// demand atomic accesses for RV64
|
|
require(c.beatBytes == (p(rocket.XLen) min timeWidth)/8)
|
|
|
|
val time = Seq.fill(timeWidth/regWidth)(Reg(init=UInt(0, width = regWidth)))
|
|
when (io.rtcTick) {
|
|
val newTime = time.asUInt + 1
|
|
for ((reg, i) <- time zip (0 until timeWidth by regWidth))
|
|
reg := newTime >> i
|
|
}
|
|
|
|
val timecmp = Seq.fill(p(NTiles)) { Seq.fill(timeWidth/regWidth)(Reg(UInt(width = regWidth))) }
|
|
val ipi = Seq.fill(p(NTiles)) { RegInit(UInt(0, width = 1)) }
|
|
|
|
for ((tile, i) <- io.tiles zipWithIndex) {
|
|
tile.msip := ipi(i)(0)
|
|
tile.mtip := time.asUInt >= timecmp(i).asUInt
|
|
}
|
|
|
|
/* 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
|
|
*/
|
|
val ipi_base = 0
|
|
val timecmp_base = c.timecmpOffset(0) / c.beatBytes
|
|
val time_base = c.timeOffset / c.beatBytes
|
|
|
|
regmap((
|
|
RegField.split(makeRegFields(ipi), ipi_base, c.beatBytes) ++
|
|
RegField.split(makeRegFields(timecmp.flatten), timecmp_base, c.beatBytes) ++
|
|
RegField.split(makeRegFields(time), time_base, c.beatBytes)):_*)
|
|
|
|
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
|
|
}
|
|
|
|
/** Power, Reset, Clock, Interrupt */
|
|
// Magic TL2 Incantation to create a TL2 Slave
|
|
class CoreplexLocalInterrupter(c: CoreplexLocalInterrupterConfig)(implicit val p: Parameters)
|
|
extends TLRegisterRouter(c.address, 0, c.size, None, c.beatBytes, false)(
|
|
new TLRegBundle((c, p), _) with CoreplexLocalInterrupterBundle)(
|
|
new TLRegModule((c, p), _, _) with CoreplexLocalInterrupterModule)
|
|
{
|
|
override def name = "clint" // defaul is "CoreplexLocalInterrupter"
|
|
}
|