1
0

Move a bunch more things into util package

A lot of utility code was just being imported willy-nilly from one
package to another. This moves the common code into util to make things
more sensible. The code moved were

 * The AsyncQueue and AsyncDecoupledCrossing from junctions.
 * All of the code in rocket's util.scala
 * The BlackBox asynchronous reset registers from uncore.tilelink2
 * The implicit definitions from uncore.util
This commit is contained in:
Howard Mao
2016-09-27 21:27:07 -07:00
parent 0924f8adb0
commit 9910c69c67
53 changed files with 242 additions and 268 deletions

View File

@ -1,102 +0,0 @@
// See LICENSE for license details.
package junctions
import Chisel._
import uncore.util.{AsyncResetRegVec, AsyncResetReg}
object GrayCounter {
def apply(bits: Int, increment: Bool = Bool(true)): UInt = {
val incremented = Wire(UInt(width=bits))
val binary = AsyncResetReg(incremented, 0)
incremented := binary + increment.asUInt()
incremented ^ (incremented >> UInt(1))
}
}
object AsyncGrayCounter {
def apply(in: UInt, sync: Int): UInt = {
val syncv = List.fill(sync)(Module (new AsyncResetRegVec(w = in.getWidth, 0)))
syncv.last.io.d := in
syncv.last.io.en := Bool(true)
(syncv.init zip syncv.tail).foreach { case (sink, source) => {
sink.io.d := source.io.q
sink.io.en := Bool(true)
}
}
syncv(0).io.d
}
}
class AsyncQueueSource[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock, resetIn: Bool)
extends Module(_clock = clockIn, _reset = resetIn) {
val bits = log2Ceil(depth)
val io = new Bundle {
// These come from the source domain
val enq = Decoupled(gen).flip()
// These cross to the sink clock domain
val ridx = UInt(INPUT, width = bits+1)
val widx = UInt(OUTPUT, width = bits+1)
val mem = Vec(depth, gen).asOutput
}
val mem = Reg(Vec(depth, gen)) //This does NOT need to be asynchronously reset.
val widx = GrayCounter(bits+1, io.enq.fire())
val ridx = AsyncGrayCounter(io.ridx, sync)
val ready = widx =/= (ridx ^ UInt(depth | depth >> 1))
val index = if (depth == 1) UInt(0) else io.widx(bits-1, 0) ^ (io.widx(bits, bits) << (bits-1))
when (io.enq.fire() && !reset) { mem(index) := io.enq.bits }
val ready_reg = AsyncResetReg(ready, 0)
io.enq.ready := ready_reg
val widx_reg = AsyncResetReg(widx, 0)
io.widx := widx_reg
io.mem := mem
}
class AsyncQueueSink[T <: Data](gen: T, depth: Int, sync: Int, clockIn: Clock, resetIn: Bool)
extends Module(_clock = clockIn, _reset = resetIn) {
val bits = log2Ceil(depth)
val io = new Bundle {
// These come from the sink domain
val deq = Decoupled(gen)
// These cross to the source clock domain
val ridx = UInt(OUTPUT, width = bits+1)
val widx = UInt(INPUT, width = bits+1)
val mem = Vec(depth, gen).asInput
}
val ridx = GrayCounter(bits+1, io.deq.fire())
val widx = AsyncGrayCounter(io.widx, sync)
val valid = ridx =/= widx
// The mux is safe because timing analysis ensures ridx has reached the register
// On an ASIC, changes to the unread location cannot affect the selected value
// On an FPGA, only one input changes at a time => mem updates don't cause glitches
// The register only latches when the selected valued is not being written
val index = if (depth == 1) UInt(0) else ridx(bits-1, 0) ^ (ridx(bits, bits) << (bits-1))
// This register does not NEED to be reset, as its contents will not
// be considered unless the asynchronously reset deq valid register is set.
io.deq.bits := RegEnable(io.mem(index), valid)
io.deq.valid := AsyncResetReg(valid, 0)
io.ridx := AsyncResetReg(ridx, 0)
}
class AsyncQueue[T <: Data](gen: T, depth: Int = 8, sync: Int = 3) extends Crossing[T] {
require (sync >= 2)
require (depth > 0 && isPow2(depth))
val io = new CrossingIO(gen)
val source = Module(new AsyncQueueSource(gen, depth, sync, io.enq_clock, io.enq_reset))
val sink = Module(new AsyncQueueSink (gen, depth, sync, io.deq_clock, io.deq_reset))
source.io.enq <> io.enq
io.deq <> sink.io.deq
sink.io.mem := source.io.mem
sink.io.widx := source.io.widx
source.io.ridx := sink.io.ridx
}

View File

@ -1,134 +0,0 @@
package junctions
import Chisel._
import chisel3.util.{DecoupledIO, Decoupled, Irrevocable, IrrevocableIO, ReadyValidIO}
class CrossingIO[T <: Data](gen: T) extends Bundle {
// Enqueue clock domain
val enq_clock = Clock(INPUT)
val enq_reset = Bool(INPUT) // synchronously deasserted wrt. enq_clock
val enq = Decoupled(gen).flip()
// Dequeue clock domain
val deq_clock = Clock(INPUT)
val deq_reset = Bool(INPUT) // synchronously deasserted wrt. deq_clock
val deq = Decoupled(gen)
}
abstract class Crossing[T <: Data] extends Module {
val io: CrossingIO[T]
}
class AsyncScope extends Module { val io = new Bundle }
object AsyncScope { def apply() = Module(new AsyncScope) }
object AsyncDecoupledCrossing
{
// takes from_source from the 'from' clock domain and puts it into the 'to' clock domain
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], to_clock: Clock, to_reset: Bool, depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
val crossing = Module(new AsyncQueue(from_source.bits, depth, sync)).io
crossing.enq_clock := from_clock
crossing.enq_reset := from_reset
crossing.enq <> from_source
crossing.deq_clock := to_clock
crossing.deq_reset := to_reset
crossing.deq
}
}
object AsyncDecoupledTo
{
// takes source from your clock domain and puts it into the 'to' clock domain
def apply[T <: Data](to_clock: Clock, to_reset: Bool, source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
val scope = AsyncScope()
AsyncDecoupledCrossing(scope.clock, scope.reset, source, to_clock, to_reset, depth, sync)
}
}
object AsyncDecoupledFrom
{
// takes from_source from the 'from' clock domain and puts it into your clock domain
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): DecoupledIO[T] = {
val scope = AsyncScope()
AsyncDecoupledCrossing(from_clock, from_reset, from_source, scope.clock, scope.reset, depth, sync)
}
}
object PostQueueIrrevocablize
{
def apply[T <: Data](deq: DecoupledIO[T]): IrrevocableIO[T] = {
val irr = Wire(new IrrevocableIO(deq.bits))
irr.bits := deq.bits
irr.valid := deq.valid
deq.ready := irr.ready
irr
}
}
object AsyncIrrevocableCrossing {
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], to_clock: Clock, to_reset: Bool, depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
PostQueueIrrevocablize(AsyncDecoupledCrossing(from_clock, from_reset, from_source, to_clock, to_reset, depth, sync))
}
}
object AsyncIrrevocableTo
{
// takes source from your clock domain and puts it into the 'to' clock domain
def apply[T <: Data](to_clock: Clock, to_reset: Bool, source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
PostQueueIrrevocablize(AsyncDecoupledTo(to_clock, to_reset, source, depth, sync))
}
}
object AsyncIrrevocableFrom
{
// takes from_source from the 'from' clock domain and puts it into your clock domain
def apply[T <: Data](from_clock: Clock, from_reset: Bool, from_source: ReadyValidIO[T], depth: Int = 8, sync: Int = 3): IrrevocableIO[T] = {
PostQueueIrrevocablize(AsyncDecoupledFrom(from_clock, from_reset, from_source, depth, sync))
}
}
/**
* This helper object synchronizes a level-sensitive signal from one
* clock domain to another.
*/
object LevelSyncCrossing {
class SynchronizerBackend(sync: Int, _clock: Clock) extends Module(Some(_clock)) {
val io = new Bundle {
val in = Bool(INPUT)
val out = Bool(OUTPUT)
}
io.out := ShiftRegister(io.in, sync)
}
class SynchronizerFrontend(_clock: Clock) extends Module(Some(_clock)) {
val io = new Bundle {
val in = Bool(INPUT)
val out = Bool(OUTPUT)
}
io.out := RegNext(io.in)
}
def apply(from_clock: Clock, to_clock: Clock, in: Bool, sync: Int = 2): Bool = {
val front = Module(new SynchronizerFrontend(from_clock))
val back = Module(new SynchronizerBackend(sync, to_clock))
front.io.in := in
back.io.in := front.io.out
back.io.out
}
}
object LevelSyncTo {
def apply(to_clock: Clock, in: Bool, sync: Int = 2): Bool = {
val scope = AsyncScope()
LevelSyncCrossing(scope.clock, to_clock, in, sync)
}
}
object LevelSyncFrom {
def apply(from_clock: Clock, in: Bool, sync: Int = 2): Bool = {
val scope = AsyncScope()
LevelSyncCrossing(from_clock, scope.clock, in, sync)
}
}

View File

@ -4,7 +4,7 @@ package junctions
import Chisel._
import scala.math.max
import scala.collection.mutable.ArraySeq
import util.{ParameterizedBundle, HellaPeekingArbiter}
import util._
import cde.{Parameters, Field}
case object NastiKey extends Field[NastiParameters]