Initial commit.
This commit is contained in:
105
src/main/scala/devices/mockaon/MockAON.scala
Normal file
105
src/main/scala/devices/mockaon/MockAON.scala
Normal file
@ -0,0 +1,105 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import regmapper._
|
||||
import uncore.tilelink2._
|
||||
import rocketchip.PeripheryBusConfig
|
||||
|
||||
import sifive.blocks.util.GenericTimer
|
||||
|
||||
case class MockAONConfig(
|
||||
address: BigInt = BigInt(0x10000000),
|
||||
nBackupRegs: Int = 16) {
|
||||
def size: Int = 0x1000
|
||||
def regBytes: Int = 4
|
||||
def wdogOffset: Int = 0
|
||||
def rtcOffset: Int = 0x40
|
||||
def backupRegOffset: Int = 0x80
|
||||
def pmuOffset: Int = 0x100
|
||||
}
|
||||
|
||||
trait HasMockAONParameters {
|
||||
val params: (MockAONConfig, Parameters)
|
||||
val c = params._1
|
||||
implicit val p = params._2
|
||||
}
|
||||
|
||||
class MockAONPMUIO extends Bundle {
|
||||
val vddpaden = Bool(OUTPUT)
|
||||
val dwakeup = Bool(INPUT)
|
||||
}
|
||||
|
||||
class MockAONMOffRstIO extends Bundle {
|
||||
val hfclkrst = Bool(OUTPUT)
|
||||
val corerst = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
trait MockAONBundle extends Bundle with HasMockAONParameters {
|
||||
|
||||
// Output of the Power Management Sequencer
|
||||
val moff = new MockAONMOffRstIO ()
|
||||
|
||||
// This goes out to wrapper
|
||||
// to be combined to create aon_rst.
|
||||
val wdog_rst = Bool(OUTPUT)
|
||||
|
||||
// This goes out to wrapper
|
||||
// and comes back as our clk
|
||||
val lfclk = Clock(OUTPUT)
|
||||
|
||||
val pmu = new MockAONPMUIO
|
||||
|
||||
val lfextclk = Clock(INPUT)
|
||||
|
||||
val resetCauses = new ResetCauses().asInput
|
||||
}
|
||||
|
||||
trait MockAONModule extends Module with HasRegMap with HasMockAONParameters {
|
||||
val io: MockAONBundle
|
||||
|
||||
// the expectation here is that Chisel's implicit reset is aonrst,
|
||||
// which is asynchronous, so don't use synchronous-reset registers.
|
||||
|
||||
val rtc = Module(new RTC)
|
||||
|
||||
val pmu = Module(new PMU(new DevKitPMUConfig))
|
||||
io.moff <> pmu.io.control
|
||||
io.pmu.vddpaden := pmu.io.control.vddpaden
|
||||
pmu.io.wakeup.dwakeup := io.pmu.dwakeup
|
||||
pmu.io.wakeup.awakeup := Bool(false)
|
||||
pmu.io.wakeup.rtc := rtc.io.ip(0)
|
||||
pmu.io.resetCauses := io.resetCauses
|
||||
val pmuRegMap = {
|
||||
val regs = pmu.io.regs.wakeupProgram ++ pmu.io.regs.sleepProgram ++
|
||||
Seq(pmu.io.regs.ie, pmu.io.regs.cause, pmu.io.regs.sleep, pmu.io.regs.key)
|
||||
for ((r, i) <- regs.zipWithIndex)
|
||||
yield (c.pmuOffset + c.regBytes*i) -> Seq(r.toRegField())
|
||||
}
|
||||
interrupts(1) := rtc.io.ip(0)
|
||||
|
||||
val wdog = Module(new WatchdogTimer)
|
||||
io.wdog_rst := wdog.io.rst
|
||||
wdog.io.corerst := pmu.io.control.corerst
|
||||
interrupts(0) := wdog.io.ip(0)
|
||||
|
||||
// If there are multiple lfclks to choose from, we can mux them here.
|
||||
io.lfclk := io.lfextclk
|
||||
|
||||
val backupRegs = Seq.fill(c.nBackupRegs)(Reg(UInt(width = c.regBytes * 8)))
|
||||
val backupRegMap =
|
||||
for ((reg, i) <- backupRegs.zipWithIndex)
|
||||
yield (c.backupRegOffset + c.regBytes*i) -> Seq(RegField(reg.getWidth, RegReadFn(reg), RegWriteFn(reg)))
|
||||
|
||||
regmap((backupRegMap ++
|
||||
GenericTimer.timerRegMap(wdog, c.wdogOffset, c.regBytes) ++
|
||||
GenericTimer.timerRegMap(rtc, c.rtcOffset, c.regBytes) ++
|
||||
pmuRegMap):_*)
|
||||
|
||||
}
|
||||
|
||||
class MockAON(c: MockAONConfig)(implicit val p: Parameters)
|
||||
extends TLRegisterRouter(c.address, interrupts = 2, size = c.size, beatBytes = p(PeripheryBusConfig).beatBytes, concurrency = 1)(
|
||||
new TLRegBundle((c, p), _) with MockAONBundle)(
|
||||
new TLRegModule((c, p), _, _) with MockAONModule)
|
42
src/main/scala/devices/mockaon/MockAONPeriphery.scala
Normal file
42
src/main/scala/devices/mockaon/MockAONPeriphery.scala
Normal file
@ -0,0 +1,42 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import diplomacy.LazyModule
|
||||
import rocketchip.{TopNetwork,TopNetworkModule}
|
||||
import uncore.tilelink2.{IntXing, TLAsyncCrossingSource, TLFragmenter}
|
||||
import coreplex._
|
||||
|
||||
trait PeripheryMockAON extends TopNetwork {
|
||||
val mockAONConfig: MockAONConfig
|
||||
val coreplex: CoreplexRISCVPlatform
|
||||
|
||||
// We override the clock & Reset here so that all synchronizers, etc
|
||||
// are in the proper clock domain.
|
||||
val aon = LazyModule(new MockAONWrapper(mockAONConfig))
|
||||
val aon_int = LazyModule(new IntXing)
|
||||
aon.node := TLAsyncCrossingSource()(TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node))
|
||||
aon_int.intnode := aon.intnode
|
||||
intBus.intnode := aon_int.intnode
|
||||
}
|
||||
|
||||
trait PeripheryMockAONBundle {
|
||||
val aon = new MockAONWrapperBundle()
|
||||
}
|
||||
|
||||
trait PeripheryMockAONModule {
|
||||
this: TopNetworkModule {
|
||||
val outer: PeripheryMockAON
|
||||
val io: PeripheryMockAONBundle
|
||||
} =>
|
||||
|
||||
io.aon <> outer.aon.module.io
|
||||
|
||||
// Explicit clock & reset are unused in MockAONWrapper.
|
||||
// Tie to check this assumption.
|
||||
outer.aon.module.clock := Bool(false).asClock
|
||||
outer.aon.module.reset := Bool(true)
|
||||
|
||||
outer.coreplex.module.io.rtcToggle := outer.aon.module.io.rtc.asUInt.toBool
|
||||
|
||||
}
|
181
src/main/scala/devices/mockaon/MockAONWrapper.scala
Normal file
181
src/main/scala/devices/mockaon/MockAONWrapper.scala
Normal file
@ -0,0 +1,181 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import diplomacy._
|
||||
import uncore.tilelink2._
|
||||
import sifive.blocks.devices.gpio.{GPIOPin, GPIOOutputPinCtrl, GPIOInputPinCtrl}
|
||||
import sifive.blocks.util.{DeglitchShiftRegister, ResetCatchAndSync}
|
||||
import util._
|
||||
/* The wrapper handles the Clock and Reset Generation for The AON block itself,
|
||||
and instantiates real pad controls (aka pull-ups)*/
|
||||
|
||||
class MockAONWrapperPMUIO extends Bundle {
|
||||
val dwakeup_n = new GPIOPin()
|
||||
val vddpaden = new GPIOPin()
|
||||
}
|
||||
|
||||
class MockAONWrapperPadsIO extends Bundle {
|
||||
val erst_n = new GPIOPin()
|
||||
val lfextclk = new GPIOPin()
|
||||
val pmu = new MockAONWrapperPMUIO()
|
||||
}
|
||||
|
||||
class MockAONWrapperBundle extends Bundle {
|
||||
val pads = new MockAONWrapperPadsIO()
|
||||
val rsts = new MockAONMOffRstIO()
|
||||
}
|
||||
|
||||
class MockAONWrapper(c: MockAONConfig)(implicit val p: Parameters) extends LazyModule {
|
||||
|
||||
val node = TLAsyncInputNode()
|
||||
val intnode = IntOutputNode()
|
||||
val aon = LazyModule (new MockAON(c)(p))
|
||||
|
||||
// We only need to isolate the signals
|
||||
// coming from MOFF to AON,
|
||||
// since AON is never off while MOFF is on.
|
||||
// The MOFF is on the "in" side of the Isolation.
|
||||
// AON is on the "out" side of the Isolation.
|
||||
|
||||
def isoOut(iso: Bool, x: UInt): UInt = IsoZero(iso, x)
|
||||
def isoIn(iso: Bool, x: UInt): UInt = x
|
||||
val isolation = LazyModule(new TLIsolation(fOut = isoOut, fIn = isoIn))
|
||||
val crossing = LazyModule(new TLAsyncCrossingSink(depth = 1))
|
||||
|
||||
isolation.node := node
|
||||
crossing.node := isolation.node
|
||||
val crossing_monitor = (aon.node := crossing.node)
|
||||
|
||||
// crossing lives outside in Periphery
|
||||
intnode := aon.intnode
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new MockAONWrapperBundle {
|
||||
val in = node.bundleIn
|
||||
val ip = intnode.bundleOut
|
||||
val rtc = Clock(OUTPUT)
|
||||
}
|
||||
|
||||
val aon_io = aon.module.io
|
||||
val pads = io.pads
|
||||
|
||||
// -----------------------------------------------
|
||||
// Generation of aonrst
|
||||
// -----------------------------------------------
|
||||
|
||||
// ERST
|
||||
val erst = ~ GPIOInputPinCtrl(pads.erst_n, pue = Bool(true))
|
||||
aon_io.resetCauses.erst := erst
|
||||
aon_io.resetCauses.wdogrst := aon_io.wdog_rst
|
||||
|
||||
// PORRST
|
||||
val porrst = Bool(false) // TODO
|
||||
aon_io.resetCauses.porrst := porrst
|
||||
|
||||
//--------------------------------------------------
|
||||
// Drive "Mostly Off" Reset Signals (these
|
||||
// are synchronized inside MOFF as needed)
|
||||
//--------------------------------------------------
|
||||
|
||||
io.rsts.hfclkrst := aon_io.moff.hfclkrst
|
||||
io.rsts.corerst := aon_io.moff.corerst
|
||||
|
||||
//--------------------------------------------------
|
||||
// Generate the LFCLK input to AON
|
||||
// This is the same clock that is driven to this
|
||||
// block as 'clock'.
|
||||
//--------------------------------------------------
|
||||
|
||||
// LFCLK Override
|
||||
// Note that the actual mux lives inside AON itself.
|
||||
// Therefore, the lfclk which comes out of AON is the
|
||||
// true clock that AON and AONWrapper are running off of.
|
||||
val lfextclk = GPIOInputPinCtrl(pads.lfextclk, pue=Bool(true))
|
||||
aon_io.lfextclk := lfextclk.asClock
|
||||
|
||||
// Drive AON's clock and Reset
|
||||
val lfclk = aon_io.lfclk
|
||||
|
||||
val aonrst_catch = Module (new ResetCatchAndSync(3))
|
||||
aonrst_catch.reset := erst | aon_io.wdog_rst
|
||||
aonrst_catch.clock := lfclk
|
||||
aon.module.reset := aonrst_catch.io.sync_reset
|
||||
|
||||
aon.module.clock := lfclk
|
||||
|
||||
//--------------------------------------------------
|
||||
// TL2 Register Access Interface
|
||||
//--------------------------------------------------
|
||||
|
||||
// Safely cross TL2 into AON Domain
|
||||
// Ensure that both are reset and clocked
|
||||
// at the same time.
|
||||
// Note that aon.moff.corerst is synchronous
|
||||
// to aon.module.clock, so this is safe.
|
||||
val crossing_slave_reset = ResetCatchAndSync(lfclk,
|
||||
aon.module.io.moff.corerst | aon.module.reset)
|
||||
|
||||
crossing.module.clock := lfclk
|
||||
crossing.module.reset := crossing_slave_reset
|
||||
|
||||
crossing_monitor.foreach { lm =>
|
||||
lm.module.clock := lfclk
|
||||
lm.module.reset := crossing_slave_reset
|
||||
}
|
||||
|
||||
// Note that aon.moff.corerst is synchronous
|
||||
// to aon.module.clock, so this is safe.
|
||||
isolation.module.io.iso_out := aon.module.io.moff.corerst
|
||||
isolation.module.io.iso_in := Bool(true)
|
||||
|
||||
//--------------------------------------------------
|
||||
// PMU <--> pads Interface
|
||||
//--------------------------------------------------
|
||||
|
||||
val dwakeup_n_async = GPIOInputPinCtrl(pads.pmu.dwakeup_n, pue=Bool(true))
|
||||
|
||||
val dwakeup_deglitch = Module (new DeglitchShiftRegister(3))
|
||||
dwakeup_deglitch.clock := lfclk
|
||||
dwakeup_deglitch.io.d := ~dwakeup_n_async
|
||||
aon.module.io.pmu.dwakeup := dwakeup_deglitch.io.q
|
||||
|
||||
GPIOOutputPinCtrl(pads.pmu.vddpaden, aon.module.io.pmu.vddpaden)
|
||||
|
||||
//--------------------------------------------------
|
||||
// Connect signals to MOFF
|
||||
//--------------------------------------------------
|
||||
|
||||
io.rtc := aon_io.lfclk
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
// Isolation Cells
|
||||
// -----------------------------------------------
|
||||
|
||||
class IsoZero extends Module {
|
||||
val io = new Bundle {
|
||||
val in = Bool(INPUT)
|
||||
val iso = Bool(INPUT)
|
||||
val out = Bool(OUTPUT)
|
||||
}
|
||||
io.out := io.in & ~io.iso
|
||||
}
|
||||
|
||||
object IsoZero {
|
||||
def apply (iso: Bool, in: UInt): UInt = {
|
||||
|
||||
val w = in.getWidth
|
||||
val isos: List[IsoZero] = List.tabulate(in.getWidth)(
|
||||
x => Module(new IsoZero).suggestName(s"iso_$x")
|
||||
)
|
||||
for ((z, i) <- isos.zipWithIndex) {
|
||||
z.io.in := in(i)
|
||||
z.io.iso := iso
|
||||
}
|
||||
isos.map(_.io.out).asUInt
|
||||
}
|
||||
}
|
152
src/main/scala/devices/mockaon/PMU.scala
Normal file
152
src/main/scala/devices/mockaon/PMU.scala
Normal file
@ -0,0 +1,152 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
58
src/main/scala/devices/mockaon/WatchdogTimer.scala
Normal file
58
src/main/scala/devices/mockaon/WatchdogTimer.scala
Normal file
@ -0,0 +1,58 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.devices.mockaon
|
||||
|
||||
import Chisel._
|
||||
import Chisel.ImplicitConversions._
|
||||
import util.AsyncResetReg
|
||||
|
||||
import sifive.blocks.util.{SlaveRegIF, GenericTimer}
|
||||
|
||||
object WatchdogTimer {
|
||||
def writeAnyExceptKey(regs: Bundle, keyReg: SlaveRegIF): Bool = {
|
||||
regs.elements.values.filter(_ ne keyReg).map({
|
||||
case v: Vec[SlaveRegIF] @unchecked => v.map(_.write.valid).reduce(_||_)
|
||||
case s: SlaveRegIF => s.write.valid
|
||||
}).reduce(_||_)
|
||||
}
|
||||
|
||||
val key = 0x51F15E
|
||||
}
|
||||
|
||||
class WatchdogTimer extends GenericTimer {
|
||||
protected def countWidth = 31
|
||||
protected def cmpWidth = 16
|
||||
protected def ncmp = 1
|
||||
protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.bits(12), io.regs.cfg.write.valid && unlocked)(0)
|
||||
override protected lazy val countAwake = AsyncResetReg(io.regs.cfg.write.bits(13), io.regs.cfg.write.valid && unlocked)(0)
|
||||
protected lazy val countEn = {
|
||||
val corerstSynchronized = Reg(next = Reg(next = io.corerst))
|
||||
countAlways || (countAwake && !corerstSynchronized)
|
||||
}
|
||||
override protected lazy val rsten = AsyncResetReg(io.regs.cfg.write.bits(8), io.regs.cfg.write.valid && unlocked)(0)
|
||||
protected lazy val ip = RegEnable(io.regs.cfg.write.bits(28) || elapsed(0), (io.regs.cfg.write.valid && unlocked) || elapsed(0))
|
||||
override protected lazy val unlocked = {
|
||||
val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key)
|
||||
AsyncResetReg(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, io.regs.key.write.valid || writeAny)(0)
|
||||
}
|
||||
protected lazy val feed = {
|
||||
val food = 0xD09F00D
|
||||
unlocked && io.regs.feed.write.valid && io.regs.feed.write.bits === food
|
||||
}
|
||||
lazy val io = new GenericTimerIO {
|
||||
val corerst = Bool(INPUT)
|
||||
val rst = Bool(OUTPUT)
|
||||
}
|
||||
io.rst := AsyncResetReg(Bool(true), rsten && elapsed(0))
|
||||
}
|
||||
|
||||
class RTC extends GenericTimer {
|
||||
protected def countWidth = 48
|
||||
protected def cmpWidth = 32
|
||||
protected def ncmp = 1
|
||||
protected def countEn = countAlways
|
||||
override protected lazy val ip = Reg(next = elapsed(0))
|
||||
override protected lazy val zerocmp = Bool(false)
|
||||
protected lazy val countAlways = AsyncResetReg(io.regs.cfg.write.bits(12), io.regs.cfg.write.valid && unlocked)(0)
|
||||
protected lazy val feed = Bool(false)
|
||||
lazy val io = new GenericTimerIO
|
||||
}
|
Reference in New Issue
Block a user