PWM: Add the ability to invert the output directly in PWM (without GPIO pinmux)
[sifive-blocks.git] / src / main / scala / util / Timer.scala
1 // See LICENSE for license details.
2 package sifive.blocks.util
3
4 import Chisel._
5 import Chisel.ImplicitConversions._
6 import freechips.rocketchip.regmapper._
7 import freechips.rocketchip.util.WideCounter
8
9 class SlaveRegIF(w: Int) extends Bundle {
10 val write = Valid(UInt(width = w)).flip
11 val read = UInt(OUTPUT, w)
12
13 override def cloneType: this.type = new SlaveRegIF(w).asInstanceOf[this.type]
14
15 def toRegField(dummy: Int = 0): RegField = {
16 def writeFn(valid: Bool, data: UInt): Bool = {
17 write.valid := valid
18 write.bits := data
19 Bool(true)
20 }
21 RegField(w, RegReadFn(read), RegWriteFn((v, d) => writeFn(v, d)))
22 }
23 }
24
25
26 abstract class GenericTimer extends Module {
27 protected def countWidth: Int
28 protected def cmpWidth: Int
29 protected def ncmp: Int
30 protected def countAlways: Bool
31 protected def countEn: Bool
32 protected def feed: Bool
33 protected def ip: UInt
34 protected def countAwake: Bool = Bool(false)
35 protected def unlocked: Bool = Bool(true)
36 protected def rsten: Bool = Bool(false)
37 protected def deglitch: Bool = Bool(false)
38 protected def sticky: Bool = Bool(false)
39 protected def oneShot: Bool = Bool(false)
40 protected def center: UInt = UInt(0)
41 protected def extra: UInt = UInt(0)
42 protected def gang: UInt = UInt(0)
43 protected val scaleWidth = 4
44 protected val regWidth = 32
45 val maxcmp = 4
46 require(ncmp <= maxcmp)
47
48 class GenericTimerIO extends Bundle {
49 val regs = new Bundle {
50 val cfg = new SlaveRegIF(regWidth)
51 val countLo = new SlaveRegIF(regWidth)
52 val countHi = new SlaveRegIF(regWidth)
53 val s = new SlaveRegIF(cmpWidth)
54 val cmp = Vec(ncmp, new SlaveRegIF(cmpWidth))
55 val feed = new SlaveRegIF(regWidth)
56 val key = new SlaveRegIF(regWidth)
57 }
58 val ip = Vec(ncmp, Bool()).asOutput
59 }
60
61 def io: GenericTimerIO
62
63 protected val scale = RegEnable(io.regs.cfg.write.bits(scaleWidth-1, 0), io.regs.cfg.write.valid && unlocked)
64 protected lazy val zerocmp = RegEnable(io.regs.cfg.write.bits(9), io.regs.cfg.write.valid && unlocked)
65 protected val cmp = io.regs.cmp.map(c => RegEnable(c.write.bits, c.write.valid && unlocked))
66
67 protected val count = WideCounter(countWidth, countEn, reset = false)
68 when (io.regs.countLo.write.valid && unlocked) { count := Cat(count >> regWidth, io.regs.countLo.write.bits) }
69 if (countWidth > regWidth) when (io.regs.countHi.write.valid && unlocked) { count := Cat(io.regs.countHi.write.bits, count(regWidth-1, 0)) }
70
71 // generate periodic interrupt
72 protected val s = (count >> scale)(cmpWidth-1, 0)
73 // reset counter when fed or elapsed
74 protected val elapsed =
75 for (i <- 0 until ncmp)
76 yield Mux(s(cmpWidth-1) && center(i), ~s, s) >= cmp(i)
77 protected val countReset = feed || (zerocmp && elapsed(0))
78 when (countReset) { count := 0 }
79
80 io.regs.cfg.read := Cat(ip, gang | UInt(0, maxcmp), extra | UInt(0, maxcmp), center | UInt(0, maxcmp),
81 UInt(0, 2), countAwake || oneShot, countAlways, UInt(0, 1), deglitch, zerocmp, rsten || sticky,
82 UInt(0, 8-scaleWidth), scale)
83 io.regs.countLo.read := count
84 io.regs.countHi.read := count >> regWidth
85 io.regs.s.read := s
86 (io.regs.cmp zip cmp) map { case (r, c) => r.read := c }
87 io.regs.feed.read := 0
88 io.regs.key.read := unlocked
89 io.ip := io.ip.fromBits(ip)
90 }
91
92
93 object GenericTimer {
94 def timerRegMap(t: GenericTimer, offset: Int, regBytes: Int): Seq[(Int, Seq[RegField])] = {
95 val regs = Seq(
96 0 -> t.io.regs.cfg,
97 2 -> t.io.regs.countLo,
98 3 -> t.io.regs.countHi,
99 4 -> t.io.regs.s,
100 6 -> t.io.regs.feed,
101 7 -> t.io.regs.key)
102 val cmpRegs = t.io.regs.cmp.zipWithIndex map { case (r, i) => (8 + i) -> r }
103 for ((i, r) <- (regs ++ cmpRegs))
104 yield (offset + regBytes*i) -> Seq(r.toRegField())
105 }
106 }