Initial commit.
This commit is contained in:
28
src/main/scala/util/DeglitchShiftRegister.scala
Normal file
28
src/main/scala/util/DeglitchShiftRegister.scala
Normal file
@ -0,0 +1,28 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
//Allows us to specify a different clock for a shift register
|
||||
// and to force input to be high for > 1 cycle.
|
||||
class DeglitchShiftRegister(shift: Int) extends Module {
|
||||
val io = new Bundle {
|
||||
val d = Bool(INPUT)
|
||||
val q = Bool(OUTPUT)
|
||||
}
|
||||
val sync = ShiftRegister(io.d, shift)
|
||||
val last = ShiftRegister(sync, 1)
|
||||
io.q := sync & last
|
||||
}
|
||||
|
||||
object DeglitchShiftRegister {
|
||||
def apply (shift: Int, d: Bool, clock: Clock,
|
||||
name: Option[String] = None): Bool = {
|
||||
val deglitch = Module (new DeglitchShiftRegister(shift))
|
||||
name.foreach(deglitch.suggestName(_))
|
||||
deglitch.clock := clock
|
||||
deglitch.reset := Bool(false)
|
||||
deglitch.io.d := d
|
||||
deglitch.io.q
|
||||
}
|
||||
}
|
41
src/main/scala/util/RegMapFIFO.scala
Normal file
41
src/main/scala/util/RegMapFIFO.scala
Normal file
@ -0,0 +1,41 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.util
|
||||
|
||||
import Chisel._
|
||||
import regmapper._
|
||||
|
||||
// MSB indicates full status
|
||||
object NonBlockingEnqueue {
|
||||
def apply(enq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = {
|
||||
val enqWidth = enq.bits.getWidth
|
||||
require(enqWidth > 0)
|
||||
require(regWidth > enqWidth)
|
||||
Seq(
|
||||
RegField(enqWidth,
|
||||
RegReadFn(UInt(0)),
|
||||
RegWriteFn((valid, data) => {
|
||||
enq.valid := valid
|
||||
enq.bits := data
|
||||
Bool(true)
|
||||
})),
|
||||
RegField(regWidth - enqWidth - 1),
|
||||
RegField.r(1, !enq.ready))
|
||||
}
|
||||
}
|
||||
|
||||
// MSB indicates empty status
|
||||
object NonBlockingDequeue {
|
||||
def apply(deq: DecoupledIO[UInt], regWidth: Int = 32): Seq[RegField] = {
|
||||
val deqWidth = deq.bits.getWidth
|
||||
require(deqWidth > 0)
|
||||
require(regWidth > deqWidth)
|
||||
Seq(
|
||||
RegField.r(deqWidth,
|
||||
RegReadFn(ready => {
|
||||
deq.ready := ready
|
||||
(Bool(true), deq.bits)
|
||||
})),
|
||||
RegField(regWidth - deqWidth - 1),
|
||||
RegField.r(1, !deq.valid))
|
||||
}
|
||||
}
|
42
src/main/scala/util/ResetCatchAndSync.scala
Normal file
42
src/main/scala/util/ResetCatchAndSync.scala
Normal file
@ -0,0 +1,42 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.util
|
||||
|
||||
import Chisel._
|
||||
import util.AsyncResetRegVec
|
||||
|
||||
/** Reset: asynchronous assert,
|
||||
* synchronous de-assert
|
||||
*
|
||||
*/
|
||||
|
||||
class ResetCatchAndSync (sync: Int = 3) extends Module {
|
||||
|
||||
val io = new Bundle {
|
||||
val sync_reset = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
val reset_n_catch_reg = Module (new AsyncResetRegVec(sync, 0))
|
||||
|
||||
reset_n_catch_reg.io.en := Bool(true)
|
||||
reset_n_catch_reg.io.d := Cat(Bool(true), reset_n_catch_reg.io.q >> 1)
|
||||
|
||||
io.sync_reset := ~reset_n_catch_reg.io.q(0)
|
||||
|
||||
}
|
||||
|
||||
object ResetCatchAndSync {
|
||||
|
||||
def apply(clk: Clock, rst: Bool, sync: Int = 3, name: Option[String] = None): Bool = {
|
||||
|
||||
val catcher = Module (new ResetCatchAndSync(sync))
|
||||
if (name.isDefined) {catcher.suggestName(name.get)}
|
||||
catcher.clock := clk
|
||||
catcher.reset := rst
|
||||
|
||||
catcher.io.sync_reset
|
||||
}
|
||||
|
||||
def apply(clk: Clock, rst: Bool, sync: Int, name: String): Bool = apply(clk, rst, sync, Some(name))
|
||||
def apply(clk: Clock, rst: Bool, name: String): Bool = apply(clk, rst, name = Some(name))
|
||||
|
||||
}
|
12
src/main/scala/util/SRLatch.scala
Normal file
12
src/main/scala/util/SRLatch.scala
Normal file
@ -0,0 +1,12 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
class SRLatch extends BlackBox {
|
||||
val io = new Bundle {
|
||||
val set = Bool(INPUT)
|
||||
val reset = Bool(INPUT)
|
||||
val q = Bool(OUTPUT)
|
||||
}
|
||||
}
|
11
src/main/scala/util/ShiftReg.scala
Normal file
11
src/main/scala/util/ShiftReg.scala
Normal file
@ -0,0 +1,11 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
object ShiftRegisterInit {
|
||||
def apply[T <: Data](in: T, n: Int, init: T): T =
|
||||
(0 until n).foldLeft(in) {
|
||||
case (next, _) => Reg(next, next = next, init = init)
|
||||
}
|
||||
}
|
104
src/main/scala/util/Timer.scala
Normal file
104
src/main/scala/util/Timer.scala
Normal file
@ -0,0 +1,104 @@
|
||||
// See LICENSE for license details.
|
||||
package sifive.blocks.util
|
||||
|
||||
import Chisel._
|
||||
import Chisel.ImplicitConversions._
|
||||
import regmapper._
|
||||
import util.WideCounter
|
||||
|
||||
class SlaveRegIF(w: Int) extends Bundle {
|
||||
val write = Valid(UInt(width = w)).flip
|
||||
val read = UInt(OUTPUT, w)
|
||||
|
||||
override def cloneType: this.type = new SlaveRegIF(w).asInstanceOf[this.type]
|
||||
|
||||
def toRegField(dummy: Int = 0): RegField = {
|
||||
def writeFn(valid: Bool, data: UInt): Bool = {
|
||||
write.valid := valid
|
||||
write.bits := data
|
||||
Bool(true)
|
||||
}
|
||||
RegField(w, RegReadFn(read), RegWriteFn((v, d) => writeFn(v, d)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class GenericTimer extends Module {
|
||||
protected def countWidth: Int
|
||||
protected def cmpWidth: Int
|
||||
protected def ncmp: Int
|
||||
protected def countAlways: Bool
|
||||
protected def countEn: Bool
|
||||
protected def feed: Bool
|
||||
protected def ip: UInt
|
||||
protected def countAwake: Bool = Bool(false)
|
||||
protected def unlocked: Bool = Bool(true)
|
||||
protected def rsten: Bool = Bool(false)
|
||||
protected def deglitch: Bool = Bool(false)
|
||||
protected def sticky: Bool = Bool(false)
|
||||
protected def oneShot: Bool = Bool(false)
|
||||
protected def center: UInt = UInt(0)
|
||||
protected def gang: UInt = UInt(0)
|
||||
protected val scaleWidth = 4
|
||||
protected val regWidth = 32
|
||||
val maxcmp = 4
|
||||
require(ncmp <= maxcmp)
|
||||
|
||||
class GenericTimerIO extends Bundle {
|
||||
val regs = new Bundle {
|
||||
val cfg = new SlaveRegIF(regWidth)
|
||||
val countLo = new SlaveRegIF(regWidth)
|
||||
val countHi = new SlaveRegIF(regWidth)
|
||||
val s = new SlaveRegIF(cmpWidth)
|
||||
val cmp = Vec(ncmp, new SlaveRegIF(cmpWidth))
|
||||
val feed = new SlaveRegIF(regWidth)
|
||||
val key = new SlaveRegIF(regWidth)
|
||||
}
|
||||
val ip = Vec(ncmp, Bool()).asOutput
|
||||
}
|
||||
|
||||
def io: GenericTimerIO
|
||||
|
||||
protected val scale = RegEnable(io.regs.cfg.write.bits(scaleWidth-1, 0), io.regs.cfg.write.valid && unlocked)
|
||||
protected lazy val zerocmp = RegEnable(io.regs.cfg.write.bits(9), io.regs.cfg.write.valid && unlocked)
|
||||
protected val cmp = io.regs.cmp.map(c => RegEnable(c.write.bits, c.write.valid && unlocked))
|
||||
|
||||
protected val count = WideCounter(countWidth, countEn, reset = false)
|
||||
when (io.regs.countLo.write.valid && unlocked) { count := Cat(count >> regWidth, io.regs.countLo.write.bits) }
|
||||
if (countWidth > regWidth) when (io.regs.countHi.write.valid && unlocked) { count := Cat(io.regs.countHi.write.bits, count(regWidth-1, 0)) }
|
||||
|
||||
// generate periodic interrupt
|
||||
protected val s = (count >> scale)(cmpWidth-1, 0)
|
||||
// reset counter when fed or elapsed
|
||||
protected val elapsed =
|
||||
for (i <- 0 until ncmp)
|
||||
yield Mux(s(cmpWidth-1) && center(i), ~s, s) >= cmp(i)
|
||||
protected val countReset = feed || (zerocmp && elapsed(0))
|
||||
when (countReset) { count := 0 }
|
||||
|
||||
io.regs.cfg.read := Cat(ip, gang | UInt(0, maxcmp), UInt(0, maxcmp), center | UInt(0, maxcmp),
|
||||
UInt(0, 2), countAwake || oneShot, countAlways, UInt(0, 1), deglitch, zerocmp, rsten || sticky, UInt(0, 8-scaleWidth), scale)
|
||||
io.regs.countLo.read := count
|
||||
io.regs.countHi.read := count >> regWidth
|
||||
io.regs.s.read := s
|
||||
(io.regs.cmp zip cmp) map { case (r, c) => r.read := c }
|
||||
io.regs.feed.read := 0
|
||||
io.regs.key.read := unlocked
|
||||
io.ip := io.ip.fromBits(ip)
|
||||
}
|
||||
|
||||
|
||||
object GenericTimer {
|
||||
def timerRegMap(t: GenericTimer, offset: Int, regBytes: Int): Seq[(Int, Seq[RegField])] = {
|
||||
val regs = Seq(
|
||||
0 -> t.io.regs.cfg,
|
||||
2 -> t.io.regs.countLo,
|
||||
3 -> t.io.regs.countHi,
|
||||
4 -> t.io.regs.s,
|
||||
6 -> t.io.regs.feed,
|
||||
7 -> t.io.regs.key)
|
||||
val cmpRegs = t.io.regs.cmp.zipWithIndex map { case (r, i) => (8 + i) -> r }
|
||||
for ((i, r) <- (regs ++ cmpRegs))
|
||||
yield (offset + regBytes*i) -> Seq(r.toRegField())
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user