1
0
Fork 0
sifive-blocks/src/main/scala/devices/mockaon/PMU.scala

153 lines
4.6 KiB
Scala

// See LICENSE for license details.
package sifive.blocks.devices.mockaon
import Chisel._
import Chisel.ImplicitConversions._
import util._
import sifive.blocks.util.SRLatch
import sifive.blocks.util.{SlaveRegIF}
class WakeupCauses extends Bundle {
val awakeup = Bool()
val dwakeup = Bool()
val rtc = Bool()
val reset = Bool()
}
class ResetCauses extends Bundle {
val wdogrst = Bool()
val erst = Bool()
val porrst = Bool()
}
class PMUSignals extends Bundle {
val hfclkrst = Bool()
val corerst = Bool()
val reserved1 = Bool()
val vddpaden = Bool()
val reserved0 = Bool()
}
class PMUInstruction extends Bundle {
val sigs = new PMUSignals
val dt = UInt(width = 4)
}
class PMUConfig(wakeupProgramIn: Seq[Int],
sleepProgramIn: Seq[Int]) {
val programLength = 8
val nWakeupCauses = new WakeupCauses().elements.size
val wakeupProgram = wakeupProgramIn.padTo(programLength, wakeupProgramIn.last)
val sleepProgram = sleepProgramIn.padTo(programLength, sleepProgramIn.last)
require(wakeupProgram.length == programLength)
require(sleepProgram.length == programLength)
}
class DevKitPMUConfig extends PMUConfig( // TODO
Seq(0x1f0, 0x0f8, 0x030),
Seq(0x0f0, 0x1f0, 0x1d0, 0x1c0))
class PMURegs(c: PMUConfig) extends Bundle {
val ie = new SlaveRegIF(c.nWakeupCauses)
val cause = new SlaveRegIF(32)
val sleep = new SlaveRegIF(32)
val key = new SlaveRegIF(32)
val wakeupProgram = Vec(c.programLength, new SlaveRegIF(32))
val sleepProgram = Vec(c.programLength, new SlaveRegIF(32))
}
class PMUCore(c: PMUConfig)(resetIn: Bool) extends Module(_reset = resetIn) {
val io = new Bundle {
val wakeup = new WakeupCauses().asInput
val control = Valid(new PMUSignals)
val resetCause = UInt(INPUT, log2Ceil(new ResetCauses().getWidth))
val regs = new PMURegs(c)
}
val run = Reg(init = Bool(true))
val awake = Reg(init = Bool(true))
val unlocked = {
val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key)
RegEnable(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, Bool(false), io.regs.key.write.valid || writeAny)
}
val wantSleep = RegEnable(Bool(true), Bool(false), io.regs.sleep.write.valid && unlocked)
val pc = Reg(init = UInt(0, log2Ceil(c.programLength)))
val wakeupCause = Reg(init = UInt(0, log2Ceil(c.nWakeupCauses)))
val ie = RegEnable(io.regs.ie.write.bits, io.regs.ie.write.valid && unlocked) | 1 /* POR always enabled */
val insnWidth = new PMUInstruction().getWidth
val wakeupProgram = c.wakeupProgram.map(v => Reg(init = UInt(v, insnWidth)))
val sleepProgram = c.sleepProgram.map(v => Reg(init = UInt(v, insnWidth)))
val insnBits = Mux(awake, wakeupProgram(pc), sleepProgram(pc))
val insn = new PMUInstruction().fromBits(insnBits)
val count = Reg(init = UInt(0, 1 << insn.dt.getWidth))
val tick = (count ^ (count + 1))(insn.dt)
val npc = pc +& 1
val last = npc >= c.programLength
io.control.valid := run && !last && tick
io.control.bits := insn.sigs
when (run) {
count := count + 1
when (tick) {
count := 0
require(isPow2(c.programLength))
run := !last
pc := npc
}
}.otherwise {
val maskedWakeupCauses = ie & io.wakeup.asUInt
when (!awake && maskedWakeupCauses.orR) {
run := true
awake := true
wakeupCause := PriorityEncoder(maskedWakeupCauses)
}
when (awake && wantSleep) {
run := true
awake := false
wantSleep := false
}
}
io.regs.cause.read := wakeupCause | (io.resetCause << 8)
io.regs.ie.read := ie
io.regs.key.read := unlocked
io.regs.sleep.read := 0
for ((port, reg) <- (io.regs.wakeupProgram ++ io.regs.sleepProgram) zip (wakeupProgram ++ sleepProgram)) {
port.read := reg
when (port.write.valid && unlocked) { reg := port.write.bits }
}
}
class PMU(val c: PMUConfig) extends Module {
val io = new Bundle {
val wakeup = new WakeupCauses().asInput
val control = new PMUSignals().asOutput
val regs = new PMURegs(c)
val resetCauses = new ResetCauses().asInput
}
val core = Module(new PMUCore(c)(resetIn = Reg(next = Reg(next = reset))))
io <> core.io
core.io.wakeup.reset := false // this is implied by resetting the PMU
// during aonrst, hold all control signals high
val latch = ~AsyncResetReg(~core.io.control.bits.asUInt, core.io.control.valid)
io.control := io.control.fromBits(latch)
core.io.resetCause := {
val cause = io.resetCauses.asUInt
val latches = for (i <- 0 until cause.getWidth) yield {
val latch = Module(new SRLatch)
latch.io.set := cause(i)
latch.io.reset := (0 until cause.getWidth).filter(_ != i).map(cause(_)).reduce(_||_)
latch.io.q
}
OHToUInt(latches)
}
}