153 lines
4.6 KiB
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)
|
|
}
|
|
}
|