2020db7089b4183a0499d07e9986b791068169d1
[sifive-blocks.git] / src / main / scala / devices / mockaon / PMU.scala
1 // See LICENSE for license details.
2 package sifive.blocks.devices.mockaon
3
4 import Chisel._
5 import Chisel.ImplicitConversions._
6 import freechips.rocketchip.util._
7 import sifive.blocks.util.SRLatch
8
9 import sifive.blocks.util.{SlaveRegIF}
10
11 class WakeupCauses extends Bundle {
12 val awakeup = Bool()
13 val dwakeup = Bool()
14 val rtc = Bool()
15 val reset = Bool()
16 }
17
18 class ResetCauses extends Bundle {
19 val wdogrst = Bool()
20 val erst = Bool()
21 val porrst = Bool()
22 }
23
24 class PMUSignals extends Bundle {
25 val hfclkrst = Bool()
26 val corerst = Bool()
27 val reserved1 = Bool()
28 val vddpaden = Bool()
29 val reserved0 = Bool()
30 }
31
32 class PMUInstruction extends Bundle {
33 val sigs = new PMUSignals
34 val dt = UInt(width = 4)
35 }
36
37 class PMUConfig(wakeupProgramIn: Seq[Int],
38 sleepProgramIn: Seq[Int]) {
39 val programLength = 8
40 val nWakeupCauses = new WakeupCauses().elements.size
41 val wakeupProgram = wakeupProgramIn.padTo(programLength, wakeupProgramIn.last)
42 val sleepProgram = sleepProgramIn.padTo(programLength, sleepProgramIn.last)
43 require(wakeupProgram.length == programLength)
44 require(sleepProgram.length == programLength)
45 }
46
47 class DevKitPMUConfig extends PMUConfig( // TODO
48 Seq(0x1f0, 0x0f8, 0x030),
49 Seq(0x0f0, 0x1f0, 0x1d0, 0x1c0))
50
51 class PMURegs(c: PMUConfig) extends Bundle {
52 val ie = new SlaveRegIF(c.nWakeupCauses)
53 val cause = new SlaveRegIF(32)
54 val sleep = new SlaveRegIF(32)
55 val key = new SlaveRegIF(32)
56 val wakeupProgram = Vec(c.programLength, new SlaveRegIF(32))
57 val sleepProgram = Vec(c.programLength, new SlaveRegIF(32))
58 }
59
60 class PMUCore(c: PMUConfig)(resetIn: Bool) extends Module(_reset = resetIn) {
61 val io = new Bundle {
62 val wakeup = new WakeupCauses().asInput
63 val control = Valid(new PMUSignals)
64 val resetCause = UInt(INPUT, log2Ceil(new ResetCauses().getWidth))
65 val regs = new PMURegs(c)
66 }
67
68 val run = Reg(init = Bool(true))
69 val awake = Reg(init = Bool(true))
70 val unlocked = {
71 val writeAny = WatchdogTimer.writeAnyExceptKey(io.regs, io.regs.key)
72 RegEnable(io.regs.key.write.bits === WatchdogTimer.key && !writeAny, Bool(false), io.regs.key.write.valid || writeAny)
73 }
74 val wantSleep = RegEnable(Bool(true), Bool(false), io.regs.sleep.write.valid && unlocked)
75 val pc = Reg(init = UInt(0, log2Ceil(c.programLength)))
76 val wakeupCause = Reg(init = UInt(0, log2Ceil(c.nWakeupCauses)))
77 val ie = RegEnable(io.regs.ie.write.bits, io.regs.ie.write.valid && unlocked) | 1 /* POR always enabled */
78
79 val insnWidth = new PMUInstruction().getWidth
80 val wakeupProgram = c.wakeupProgram.map(v => Reg(init = UInt(v, insnWidth)))
81 val sleepProgram = c.sleepProgram.map(v => Reg(init = UInt(v, insnWidth)))
82 val insnBits = Mux(awake, wakeupProgram(pc), sleepProgram(pc))
83 val insn = new PMUInstruction().fromBits(insnBits)
84
85 val count = Reg(init = UInt(0, 1 << insn.dt.getWidth))
86 val tick = (count ^ (count + 1))(insn.dt)
87 val npc = pc +& 1
88 val last = npc >= c.programLength
89 io.control.valid := run && !last && tick
90 io.control.bits := insn.sigs
91
92 when (run) {
93 count := count + 1
94 when (tick) {
95 count := 0
96
97 require(isPow2(c.programLength))
98 run := !last
99 pc := npc
100 }
101 }.otherwise {
102 val maskedWakeupCauses = ie & io.wakeup.asUInt
103 when (!awake && maskedWakeupCauses.orR) {
104 run := true
105 awake := true
106 wakeupCause := PriorityEncoder(maskedWakeupCauses)
107 }
108 when (awake && wantSleep) {
109 run := true
110 awake := false
111 wantSleep := false
112 }
113 }
114
115 io.regs.cause.read := wakeupCause | (io.resetCause << 8)
116 io.regs.ie.read := ie
117 io.regs.key.read := unlocked
118 io.regs.sleep.read := 0
119
120 for ((port, reg) <- (io.regs.wakeupProgram ++ io.regs.sleepProgram) zip (wakeupProgram ++ sleepProgram)) {
121 port.read := reg
122 when (port.write.valid && unlocked) { reg := port.write.bits }
123 }
124 }
125
126 class PMU(val c: PMUConfig) extends Module {
127 val io = new Bundle {
128 val wakeup = new WakeupCauses().asInput
129 val control = new PMUSignals().asOutput
130 val regs = new PMURegs(c)
131 val resetCauses = new ResetCauses().asInput
132 }
133
134 val core = Module(new PMUCore(c)(resetIn = Reg(next = Reg(next = reset))))
135 io <> core.io
136 core.io.wakeup.reset := false // this is implied by resetting the PMU
137
138 // during aonrst, hold all control signals high
139 val latch = ~AsyncResetReg(~core.io.control.bits.asUInt, core.io.control.valid)
140 io.control := io.control.fromBits(latch)
141
142 core.io.resetCause := {
143 val cause = io.resetCauses.asUInt
144 val latches = for (i <- 0 until cause.getWidth) yield {
145 val latch = Module(new SRLatch)
146 latch.io.set := cause(i)
147 latch.io.reset := (0 until cause.getWidth).filter(_ != i).map(cause(_)).reduce(_||_)
148 latch.io.q
149 }
150 OHToUInt(latches)
151 }
152 }