Refactor package hierarchy and remove legacy bus protocol implementations (#845)
* Refactors package hierarchy. Additionally: - Removes legacy ground tests and configs - Removes legacy bus protocol implementations - Removes NTiles - Adds devices package - Adds more functions to util package
This commit is contained in:
@ -1,8 +1,9 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
|
||||
/** A generalized locking RR arbiter that addresses the limitations of the
|
||||
* version in the Chisel standard library */
|
||||
@ -93,3 +94,52 @@ class HellaCountingArbiter[T <: Data](
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** This arbiter preserves the order of responses */
|
||||
class InOrderArbiter[T <: Data, U <: Data](reqTyp: T, respTyp: U, n: Int)
|
||||
(implicit p: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val in_req = Vec(n, Decoupled(reqTyp)).flip
|
||||
val in_resp = Vec(n, Decoupled(respTyp))
|
||||
val out_req = Decoupled(reqTyp)
|
||||
val out_resp = Decoupled(respTyp).flip
|
||||
}
|
||||
|
||||
if (n > 1) {
|
||||
val route_q = Module(new Queue(UInt(width = log2Up(n)), 2))
|
||||
val req_arb = Module(new RRArbiter(reqTyp, n))
|
||||
req_arb.io.in <> io.in_req
|
||||
|
||||
val req_helper = DecoupledHelper(
|
||||
req_arb.io.out.valid,
|
||||
route_q.io.enq.ready,
|
||||
io.out_req.ready)
|
||||
|
||||
io.out_req.bits := req_arb.io.out.bits
|
||||
io.out_req.valid := req_helper.fire(io.out_req.ready)
|
||||
|
||||
route_q.io.enq.bits := req_arb.io.chosen
|
||||
route_q.io.enq.valid := req_helper.fire(route_q.io.enq.ready)
|
||||
|
||||
req_arb.io.out.ready := req_helper.fire(req_arb.io.out.valid)
|
||||
|
||||
val resp_sel = route_q.io.deq.bits
|
||||
val resp_ready = io.in_resp(resp_sel).ready
|
||||
val resp_helper = DecoupledHelper(
|
||||
resp_ready,
|
||||
route_q.io.deq.valid,
|
||||
io.out_resp.valid)
|
||||
|
||||
val resp_valid = resp_helper.fire(resp_ready)
|
||||
for (i <- 0 until n) {
|
||||
io.in_resp(i).bits := io.out_resp.bits
|
||||
io.in_resp(i).valid := resp_valid && resp_sel === UInt(i)
|
||||
}
|
||||
|
||||
route_q.io.deq.ready := resp_helper.fire(route_q.io.deq.valid)
|
||||
io.out_resp.ready := resp_helper.fire(io.out_resp.valid)
|
||||
} else {
|
||||
io.out_req <> io.in_req.head
|
||||
io.in_resp.head <> io.out_resp
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import chisel3.util.{ReadyValidIO}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
object GrayCounter {
|
||||
|
@ -1,11 +1,9 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
import config._
|
||||
|
||||
/** This black-boxes an Async Reset
|
||||
* (or Set)
|
||||
* Register.
|
||||
|
48
src/main/scala/util/Broadcaster.scala
Normal file
48
src/main/scala/util/Broadcaster.scala
Normal file
@ -0,0 +1,48 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
/** Takes in data on one decoupled interface and broadcasts it
|
||||
* to N decoupled output interfaces.
|
||||
*/
|
||||
class Broadcaster[T <: Data](typ: T, n: Int) extends Module {
|
||||
val io = new Bundle {
|
||||
val in = Decoupled(typ).flip
|
||||
val out = Vec(n, Decoupled(typ))
|
||||
}
|
||||
|
||||
require (n > 0)
|
||||
|
||||
if (n == 1) {
|
||||
io.out.head <> io.in
|
||||
} else {
|
||||
val idx = Reg(init = UInt(0, log2Up(n)))
|
||||
val save = Reg(typ)
|
||||
|
||||
io.out.head.valid := idx === UInt(0) && io.in.valid
|
||||
io.out.head.bits := io.in.bits
|
||||
for (i <- 1 until n) {
|
||||
io.out(i).valid := idx === UInt(i)
|
||||
io.out(i).bits := save
|
||||
}
|
||||
io.in.ready := io.out.head.ready && idx === UInt(0)
|
||||
|
||||
when (io.in.fire()) { save := io.in.bits }
|
||||
|
||||
when (io.out(idx).fire()) {
|
||||
when (idx === UInt(n - 1)) { idx := UInt(0) }
|
||||
.otherwise { idx := idx + UInt(1) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Broadcaster {
|
||||
def apply[T <: Data](in: DecoupledIO[T], n: Int): Vec[DecoupledIO[T]] = {
|
||||
val split = Module(new Broadcaster(in.bits, n))
|
||||
split.io.in <> in
|
||||
split.io.out
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import scala.math.max
|
||||
|
||||
// Produces 0-width value when counting to 1
|
||||
|
@ -1,6 +1,6 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import chisel3.util.{DecoupledIO, Decoupled, Irrevocable, IrrevocableIO, ReadyValidIO}
|
||||
|
160
src/main/scala/util/ECC.scala
Normal file
160
src/main/scala/util/ECC.scala
Normal file
@ -0,0 +1,160 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
abstract class Decoding
|
||||
{
|
||||
def uncorrected: UInt
|
||||
def corrected: UInt
|
||||
def correctable: Bool
|
||||
def uncorrectable: Bool // If true, correctable should be ignored
|
||||
def error = correctable || uncorrectable
|
||||
}
|
||||
|
||||
abstract class Code
|
||||
{
|
||||
def width(w0: Int): Int
|
||||
def encode(x: UInt): UInt
|
||||
def decode(x: UInt): Decoding
|
||||
|
||||
/** Copy the bits in x to the right bit positions in an encoded word,
|
||||
* so that x === decode(swizzle(x)).uncorrected; but don't generate
|
||||
* the other code bits, so decode(swizzle(x)).error might be true.
|
||||
* For codes for which this operation is not trivial, throw an
|
||||
* UnsupportedOperationException. */
|
||||
def swizzle(x: UInt): UInt
|
||||
}
|
||||
|
||||
class IdentityCode extends Code
|
||||
{
|
||||
def width(w0: Int) = w0
|
||||
def encode(x: UInt) = x
|
||||
def swizzle(x: UInt) = x
|
||||
def decode(y: UInt) = new Decoding {
|
||||
def uncorrected = y
|
||||
def corrected = y
|
||||
def correctable = Bool(false)
|
||||
def uncorrectable = Bool(false)
|
||||
}
|
||||
}
|
||||
|
||||
class ParityCode extends Code
|
||||
{
|
||||
def width(w0: Int) = w0+1
|
||||
def encode(x: UInt) = Cat(x.xorR, x)
|
||||
def swizzle(x: UInt) = Cat(false.B, x)
|
||||
def decode(y: UInt) = new Decoding {
|
||||
val uncorrected = y(y.getWidth-2,0)
|
||||
val corrected = uncorrected
|
||||
val correctable = Bool(false)
|
||||
val uncorrectable = y.xorR
|
||||
}
|
||||
}
|
||||
|
||||
class SECCode extends Code
|
||||
{
|
||||
def width(k: Int) = {
|
||||
val m = log2Floor(k) + 1
|
||||
k + m + (if((1 << m) < m+k+1) 1 else 0)
|
||||
}
|
||||
def encode(x: UInt) = {
|
||||
val k = x.getWidth
|
||||
require(k > 0)
|
||||
val n = width(k)
|
||||
|
||||
val y = for (i <- 1 to n) yield {
|
||||
if (isPow2(i)) {
|
||||
val r = for (j <- 1 to n; if j != i && (j & i) != 0)
|
||||
yield x(mapping(j))
|
||||
r reduce (_^_)
|
||||
} else
|
||||
x(mapping(i))
|
||||
}
|
||||
y.asUInt
|
||||
}
|
||||
def swizzle(x: UInt) = {
|
||||
val y = for (i <- 1 to width(x.getWidth))
|
||||
yield (if (isPow2(i)) false.B else x(mapping(i)))
|
||||
y.asUInt
|
||||
}
|
||||
def decode(y: UInt) = new Decoding {
|
||||
val n = y.getWidth
|
||||
require(n > 0 && !isPow2(n))
|
||||
|
||||
val p2 = for (i <- 0 until log2Up(n)) yield 1 << i
|
||||
val syndrome = (p2 map { i =>
|
||||
val r = for (j <- 1 to n; if (j & i) != 0)
|
||||
yield y(j-1)
|
||||
r reduce (_^_)
|
||||
}).asUInt
|
||||
|
||||
private def swizzle(z: UInt) = (1 to n).filter(i => !isPow2(i)).map(i => z(i-1)).asUInt
|
||||
val uncorrected = swizzle(y)
|
||||
val corrected = swizzle(((y << 1) ^ UIntToOH(syndrome)) >> 1)
|
||||
val correctable = syndrome.orR
|
||||
val uncorrectable = syndrome > UInt(n)
|
||||
}
|
||||
private def mapping(i: Int) = i-1-log2Up(i)
|
||||
}
|
||||
|
||||
class SECDEDCode extends Code
|
||||
{
|
||||
private val sec = new SECCode
|
||||
private val par = new ParityCode
|
||||
|
||||
def width(k: Int) = sec.width(k)+1
|
||||
def encode(x: UInt) = par.encode(sec.encode(x))
|
||||
def swizzle(x: UInt) = par.swizzle(sec.swizzle(x))
|
||||
def decode(x: UInt) = new Decoding {
|
||||
val secdec = sec.decode(x(x.getWidth-2,0))
|
||||
val pardec = par.decode(x)
|
||||
|
||||
val uncorrected = secdec.uncorrected
|
||||
val corrected = secdec.corrected
|
||||
val correctable = pardec.uncorrectable
|
||||
val uncorrectable = !pardec.uncorrectable && secdec.correctable
|
||||
}
|
||||
}
|
||||
|
||||
object ErrGen
|
||||
{
|
||||
// generate a 1-bit error with approximate probability 2^-f
|
||||
def apply(width: Int, f: Int): UInt = {
|
||||
require(width > 0 && f >= 0 && log2Up(width) + f <= 16)
|
||||
UIntToOH(LFSR16()(log2Up(width)+f-1,0))(width-1,0)
|
||||
}
|
||||
def apply(x: UInt, f: Int): UInt = x ^ apply(x.getWidth, f)
|
||||
}
|
||||
|
||||
class SECDEDTest extends Module
|
||||
{
|
||||
val code = new SECDEDCode
|
||||
val k = 4
|
||||
val n = code.width(k)
|
||||
|
||||
val io = new Bundle {
|
||||
val original = Bits(OUTPUT, k)
|
||||
val encoded = Bits(OUTPUT, n)
|
||||
val injected = Bits(OUTPUT, n)
|
||||
val uncorrected = Bits(OUTPUT, k)
|
||||
val corrected = Bits(OUTPUT, k)
|
||||
val correctable = Bool(OUTPUT)
|
||||
val uncorrectable = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
val c = Counter(Bool(true), 1 << k)
|
||||
val numErrors = Counter(c._2, 3)._1
|
||||
val e = code.encode(c._1)
|
||||
val i = e ^ Mux(numErrors < UInt(1), UInt(0), ErrGen(n, 1)) ^ Mux(numErrors < UInt(2), UInt(0), ErrGen(n, 1))
|
||||
val d = code.decode(i)
|
||||
|
||||
io.original := c._1
|
||||
io.encoded := e
|
||||
io.injected := i
|
||||
io.uncorrected := d.uncorrected
|
||||
io.corrected := d.corrected
|
||||
io.correctable := d.correctable
|
||||
io.uncorrectable := d.uncorrectable
|
||||
}
|
43
src/main/scala/util/Frequency.scala
Normal file
43
src/main/scala/util/Frequency.scala
Normal file
@ -0,0 +1,43 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
/** Given a list of (frequency, value) pairs, return a random value
|
||||
* according to the frequency distribution. The sum of the
|
||||
* frequencies in the distribution must be a power of two.
|
||||
*/
|
||||
object Frequency {
|
||||
def apply(dist : List[(Int, Bits)]) : Bits = {
|
||||
// Distribution must be non-empty
|
||||
require(dist.length > 0)
|
||||
|
||||
// Require that the frequencies sum to a power of two
|
||||
val (freqs, vals) = dist.unzip
|
||||
val total = freqs.sum
|
||||
require(isPow2(total))
|
||||
|
||||
// First item in the distribution
|
||||
val (firstFreq, firstVal) = dist.head
|
||||
|
||||
// Result wire
|
||||
val result = Wire(Bits(width = firstVal.getWidth))
|
||||
result := UInt(0)
|
||||
|
||||
// Random value
|
||||
val randVal = LCG(log2Up(total))
|
||||
|
||||
// Pick return value
|
||||
var count = firstFreq
|
||||
var select = when (randVal < UInt(firstFreq)) { result := firstVal }
|
||||
for (p <- dist.drop(1)) {
|
||||
count = count + p._1
|
||||
select = select.elsewhen(randVal < UInt(count)) { result := p._2 }
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import chisel3.internal.firrtl.Circuit
|
||||
import chisel3.experimental.{RawModule}
|
||||
import config._
|
||||
import diplomacy.LazyModule
|
||||
// TODO: better job of Makefrag generation for non-RocketChip testing platforms
|
||||
import freechips.rocketchip.chip.{TestGeneration, DefaultTestSuites}
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.diplomacy.LazyModule
|
||||
import java.io.{File, FileWriter}
|
||||
|
||||
/** Representation of the information this Generator needs to collect from external sources. */
|
||||
@ -40,7 +43,6 @@ trait HasGeneratorUtilities {
|
||||
|
||||
def getParameters(config: Config): Parameters = Parameters.root(config.toInstance)
|
||||
|
||||
import chisel3.internal.firrtl.Circuit
|
||||
def elaborate(names: ParsedInputNames, params: Parameters): Circuit = {
|
||||
val gen = () =>
|
||||
Class.forName(names.fullTopModuleClass)
|
||||
@ -92,13 +94,10 @@ trait GeneratorApp extends App with HasGeneratorUtilities {
|
||||
/** Output software test Makefrags, which provide targets for integration testing. */
|
||||
def generateTestSuiteMakefrags {
|
||||
addTestSuites
|
||||
writeOutputFile(td, s"$longName.d", rocketchip.TestGeneration.generateMakefrag) // Coreplex-specific test suites
|
||||
writeOutputFile(td, s"$longName.d", TestGeneration.generateMakefrag) // Coreplex-specific test suites
|
||||
}
|
||||
|
||||
def addTestSuites {
|
||||
// TODO: better job of Makefrag generation
|
||||
// for non-RocketChip testing platforms
|
||||
import rocketchip.{DefaultTestSuites, TestGeneration}
|
||||
TestGeneration.addSuite(DefaultTestSuites.groundtest64("p"))
|
||||
TestGeneration.addSuite(DefaultTestSuites.emptyBmarks)
|
||||
TestGeneration.addSuite(DefaultTestSuites.singleRegression)
|
||||
|
@ -1,6 +1,6 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
|
||||
class HellaFlowQueue[T <: Data](val entries: Int)(data: => T) extends Module {
|
||||
val io = new QueueIO(data, entries)
|
||||
|
@ -1,4 +1,6 @@
|
||||
package util
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import chisel3.core.Record
|
||||
|
55
src/main/scala/util/LCG.scala
Normal file
55
src/main/scala/util/LCG.scala
Normal file
@ -0,0 +1,55 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
/** A 16-bit psuedo-random generator based on a linear conguential
|
||||
* generator (LCG). The state is stored in an unitialised register.
|
||||
* When using the C++ backend, it is straigtforward to arrange a
|
||||
* random initial value for each uninitialised register, effectively
|
||||
* seeding each LCG16 instance with a different seed.
|
||||
*/
|
||||
class LCG16 extends Module {
|
||||
val io = new Bundle {
|
||||
val out = UInt(OUTPUT, 16)
|
||||
val inc = Bool(INPUT)
|
||||
}
|
||||
val state = Reg(UInt(width = 32))
|
||||
when (io.inc) {
|
||||
state := state * UInt(1103515245, 32) + UInt(12345, 32)
|
||||
}
|
||||
io.out := state(30, 15)
|
||||
}
|
||||
|
||||
/** An n-bit psuedo-random generator made from many instances of a
|
||||
* 16-bit LCG. Parameter 'width' must be larger than 0.
|
||||
*/
|
||||
class LCG(val w: Int) extends Module {
|
||||
val io = new Bundle {
|
||||
val out = UInt(OUTPUT, w)
|
||||
val inc = Bool(INPUT)
|
||||
}
|
||||
require(w > 0)
|
||||
val numLCG16s : Int = (w+15)/16
|
||||
val outs = Seq.fill(numLCG16s) { LCG16(io.inc) }
|
||||
io.out := Cat(outs)
|
||||
}
|
||||
|
||||
object LCG16 {
|
||||
def apply(inc: Bool = Bool(true)): UInt = {
|
||||
val lcg = Module(new LCG16)
|
||||
lcg.io.inc := inc
|
||||
lcg.io.out
|
||||
}
|
||||
}
|
||||
|
||||
object LCG {
|
||||
def apply(w: Int, inc: Bool = Bool(true)): UInt = {
|
||||
val lcg = Module(new LCG(w))
|
||||
lcg.io.inc := inc
|
||||
lcg.io.out
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import scala.math._
|
||||
|
||||
class ParameterizedBundle(implicit p: Parameters) extends Bundle {
|
||||
@ -59,6 +59,19 @@ object MuxTLookup {
|
||||
}
|
||||
}
|
||||
|
||||
object ValidMux {
|
||||
def apply[T <: Data](v1: ValidIO[T], v2: ValidIO[T]*): ValidIO[T] = {
|
||||
apply(v1 +: v2.toSeq)
|
||||
}
|
||||
def apply[T <: Data](valids: Seq[ValidIO[T]]): ValidIO[T] = {
|
||||
val out = Wire(Valid(valids.head.bits))
|
||||
out.valid := valids.map(_.valid).reduce(_ || _)
|
||||
out.bits := MuxCase(valids.head.bits,
|
||||
valids.map(v => (v.valid -> v.bits)))
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
object Str
|
||||
{
|
||||
def apply(s: String): UInt = {
|
||||
@ -172,3 +185,53 @@ object Majority {
|
||||
|
||||
def apply(in: UInt): Bool = apply(in.toBools.toSet)
|
||||
}
|
||||
|
||||
object PopCountAtLeast {
|
||||
private def two(x: UInt): (Bool, Bool) = x.getWidth match {
|
||||
case 1 => (x.toBool, Bool(false))
|
||||
case n =>
|
||||
val half = x.getWidth / 2
|
||||
val (leftOne, leftTwo) = two(x(half - 1, 0))
|
||||
val (rightOne, rightTwo) = two(x(x.getWidth - 1, half))
|
||||
(leftOne || rightOne, leftTwo || rightTwo || (leftOne && rightOne))
|
||||
}
|
||||
def apply(x: UInt, n: Int): Bool = n match {
|
||||
case 0 => Bool(true)
|
||||
case 1 => x.orR
|
||||
case 2 => two(x)._2
|
||||
case 3 => PopCount(x) >= UInt(n)
|
||||
}
|
||||
}
|
||||
|
||||
// This gets used everywhere, so make the smallest circuit possible ...
|
||||
// Given an address and size, create a mask of beatBytes size
|
||||
// eg: (0x3, 0, 4) => 0001, (0x3, 1, 4) => 0011, (0x3, 2, 4) => 1111
|
||||
// groupBy applies an interleaved OR reduction; groupBy=2 take 0010 => 01
|
||||
object MaskGen {
|
||||
def apply(addr_lo: UInt, lgSize: UInt, beatBytes: Int, groupBy: Int = 1): UInt = {
|
||||
require (groupBy >= 1 && beatBytes >= groupBy)
|
||||
require (isPow2(beatBytes) && isPow2(groupBy))
|
||||
val lgBytes = log2Ceil(beatBytes)
|
||||
val sizeOH = UIntToOH(lgSize, log2Up(beatBytes)) | UInt(groupBy*2 - 1)
|
||||
|
||||
def helper(i: Int): Seq[(Bool, Bool)] = {
|
||||
if (i == 0) {
|
||||
Seq((lgSize >= UInt(lgBytes), Bool(true)))
|
||||
} else {
|
||||
val sub = helper(i-1)
|
||||
val size = sizeOH(lgBytes - i)
|
||||
val bit = addr_lo(lgBytes - i)
|
||||
val nbit = !bit
|
||||
Seq.tabulate (1 << i) { j =>
|
||||
val (sub_acc, sub_eq) = sub(j/2)
|
||||
val eq = sub_eq && (if (j % 2 == 1) bit else nbit)
|
||||
val acc = sub_acc || (size && eq)
|
||||
(acc, eq)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groupBy == beatBytes) UInt(1) else
|
||||
Cat(helper(lgBytes-log2Ceil(groupBy)).map(_._1).reverse)
|
||||
}
|
||||
}
|
||||
|
160
src/main/scala/util/MultiWidthFifo.scala
Normal file
160
src/main/scala/util/MultiWidthFifo.scala
Normal file
@ -0,0 +1,160 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.unittest.UnitTest
|
||||
|
||||
class MultiWidthFifo(inW: Int, outW: Int, n: Int) extends Module {
|
||||
val io = new Bundle {
|
||||
val in = Decoupled(Bits(width = inW)).flip
|
||||
val out = Decoupled(Bits(width = outW))
|
||||
val count = UInt(OUTPUT, log2Up(n + 1))
|
||||
}
|
||||
|
||||
if (inW == outW) {
|
||||
val q = Module(new Queue(Bits(width = inW), n))
|
||||
q.io.enq <> io.in
|
||||
io.out <> q.io.deq
|
||||
io.count := q.io.count
|
||||
} else if (inW > outW) {
|
||||
val nBeats = inW / outW
|
||||
|
||||
require(inW % outW == 0, s"MultiWidthFifo: in: $inW not divisible by out: $outW")
|
||||
require(n % nBeats == 0, s"Cannot store $n output words when output beats is $nBeats")
|
||||
|
||||
val wdata = Reg(Vec(n / nBeats, Bits(width = inW)))
|
||||
val rdata = Vec(wdata.flatMap { indat =>
|
||||
(0 until nBeats).map(i => indat(outW * (i + 1) - 1, outW * i)) })
|
||||
|
||||
val head = Reg(init = UInt(0, log2Up(n / nBeats)))
|
||||
val tail = Reg(init = UInt(0, log2Up(n)))
|
||||
val size = Reg(init = UInt(0, log2Up(n + 1)))
|
||||
|
||||
when (io.in.fire()) {
|
||||
wdata(head) := io.in.bits
|
||||
head := head + UInt(1)
|
||||
}
|
||||
|
||||
when (io.out.fire()) { tail := tail + UInt(1) }
|
||||
|
||||
size := MuxCase(size, Seq(
|
||||
(io.in.fire() && io.out.fire()) -> (size + UInt(nBeats - 1)),
|
||||
io.in.fire() -> (size + UInt(nBeats)),
|
||||
io.out.fire() -> (size - UInt(1))))
|
||||
|
||||
io.out.valid := size > UInt(0)
|
||||
io.out.bits := rdata(tail)
|
||||
io.in.ready := size < UInt(n)
|
||||
io.count := size
|
||||
} else {
|
||||
val nBeats = outW / inW
|
||||
|
||||
require(outW % inW == 0, s"MultiWidthFifo: out: $outW not divisible by in: $inW")
|
||||
|
||||
val wdata = Reg(Vec(n * nBeats, Bits(width = inW)))
|
||||
val rdata = Vec.tabulate(n) { i =>
|
||||
Cat(wdata.slice(i * nBeats, (i + 1) * nBeats).reverse)}
|
||||
|
||||
val head = Reg(init = UInt(0, log2Up(n * nBeats)))
|
||||
val tail = Reg(init = UInt(0, log2Up(n)))
|
||||
val size = Reg(init = UInt(0, log2Up(n * nBeats + 1)))
|
||||
|
||||
when (io.in.fire()) {
|
||||
wdata(head) := io.in.bits
|
||||
head := head + UInt(1)
|
||||
}
|
||||
|
||||
when (io.out.fire()) { tail := tail + UInt(1) }
|
||||
|
||||
size := MuxCase(size, Seq(
|
||||
(io.in.fire() && io.out.fire()) -> (size - UInt(nBeats - 1)),
|
||||
io.in.fire() -> (size + UInt(1)),
|
||||
io.out.fire() -> (size - UInt(nBeats))))
|
||||
|
||||
io.count := size >> UInt(log2Up(nBeats))
|
||||
io.out.valid := io.count > UInt(0)
|
||||
io.out.bits := rdata(tail)
|
||||
io.in.ready := size < UInt(n * nBeats)
|
||||
}
|
||||
}
|
||||
|
||||
class MultiWidthFifoTest extends UnitTest {
|
||||
val big2little = Module(new MultiWidthFifo(16, 8, 8))
|
||||
val little2big = Module(new MultiWidthFifo(8, 16, 4))
|
||||
|
||||
val bl_send = Reg(init = Bool(false))
|
||||
val lb_send = Reg(init = Bool(false))
|
||||
val bl_recv = Reg(init = Bool(false))
|
||||
val lb_recv = Reg(init = Bool(false))
|
||||
val bl_finished = Reg(init = Bool(false))
|
||||
val lb_finished = Reg(init = Bool(false))
|
||||
|
||||
val bl_data = Vec.tabulate(4){i => UInt((2 * i + 1) * 256 + 2 * i, 16)}
|
||||
val lb_data = Vec.tabulate(8){i => UInt(i, 8)}
|
||||
|
||||
val (bl_send_cnt, bl_send_done) = Counter(big2little.io.in.fire(), 4)
|
||||
val (lb_send_cnt, lb_send_done) = Counter(little2big.io.in.fire(), 8)
|
||||
|
||||
val (bl_recv_cnt, bl_recv_done) = Counter(big2little.io.out.fire(), 8)
|
||||
val (lb_recv_cnt, lb_recv_done) = Counter(little2big.io.out.fire(), 4)
|
||||
|
||||
big2little.io.in.valid := bl_send
|
||||
big2little.io.in.bits := bl_data(bl_send_cnt)
|
||||
big2little.io.out.ready := bl_recv
|
||||
|
||||
little2big.io.in.valid := lb_send
|
||||
little2big.io.in.bits := lb_data(lb_send_cnt)
|
||||
little2big.io.out.ready := lb_recv
|
||||
|
||||
val bl_recv_data_idx = bl_recv_cnt >> UInt(1)
|
||||
val bl_recv_data = Mux(bl_recv_cnt(0),
|
||||
bl_data(bl_recv_data_idx)(15, 8),
|
||||
bl_data(bl_recv_data_idx)(7, 0))
|
||||
|
||||
val lb_recv_data = Cat(
|
||||
lb_data(Cat(lb_recv_cnt, UInt(1, 1))),
|
||||
lb_data(Cat(lb_recv_cnt, UInt(0, 1))))
|
||||
|
||||
when (io.start) {
|
||||
bl_send := Bool(true)
|
||||
lb_send := Bool(true)
|
||||
}
|
||||
|
||||
when (bl_send_done) {
|
||||
bl_send := Bool(false)
|
||||
bl_recv := Bool(true)
|
||||
}
|
||||
|
||||
when (lb_send_done) {
|
||||
lb_send := Bool(false)
|
||||
lb_recv := Bool(true)
|
||||
}
|
||||
|
||||
when (bl_recv_done) {
|
||||
bl_recv := Bool(false)
|
||||
bl_finished := Bool(true)
|
||||
}
|
||||
|
||||
when (lb_recv_done) {
|
||||
lb_recv := Bool(false)
|
||||
lb_finished := Bool(true)
|
||||
}
|
||||
|
||||
io.finished := bl_finished && lb_finished
|
||||
|
||||
val bl_start_recv = Reg(next = bl_send_done)
|
||||
val lb_start_recv = Reg(next = lb_send_done)
|
||||
|
||||
assert(!little2big.io.out.valid || little2big.io.out.bits === lb_recv_data,
|
||||
"Little to Big data mismatch")
|
||||
assert(!big2little.io.out.valid || big2little.io.out.bits === bl_recv_data,
|
||||
"Bit to Little data mismatch")
|
||||
|
||||
assert(!lb_start_recv || little2big.io.count === UInt(4),
|
||||
"Little to Big count incorrect")
|
||||
assert(!bl_start_recv || big2little.io.count === UInt(8),
|
||||
"Big to Little count incorrect")
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
class plusarg_reader(val format: String, val default: Int, val docstring: String) extends BlackBox(Map(
|
||||
|
@ -1,6 +1,7 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
case class PositionalMultiQueueParameters[T <: Data](gen: T, positions: Int, ways: Int)
|
||||
|
@ -1,12 +1,13 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
// If you know two clocks are related with an N:M relationship, you
|
||||
// can cross the clock domains with lower latency than an AsyncQueue.
|
||||
// This crossing adds 1 cycle in the target clock domain.
|
||||
|
||||
package util
|
||||
import Chisel._
|
||||
|
||||
// A rational crossing must put registers on the slow side.
|
||||
// This trait covers the options of how/where to put the registers.
|
||||
// BEWARE: the source+sink must agree on the direction!
|
||||
|
@ -1,6 +1,7 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
object ReduceOthers {
|
||||
|
@ -1,10 +1,9 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
import config._
|
||||
|
||||
class ReorderQueueWrite[T <: Data](dType: T, tagWidth: Int) extends Bundle {
|
||||
val data = dType.cloneType
|
||||
|
39
src/main/scala/util/Repeater.scala
Normal file
39
src/main/scala/util/Repeater.scala
Normal file
@ -0,0 +1,39 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
// A Repeater passes it's input to it's output, unless repeat is asserted.
|
||||
// When repeat is asserted, the Repeater copies the input and repeats it next cycle.
|
||||
class Repeater[T <: Data](gen: T) extends Module
|
||||
{
|
||||
val io = new Bundle {
|
||||
val repeat = Bool(INPUT)
|
||||
val full = Bool(OUTPUT)
|
||||
val enq = Decoupled(gen).flip
|
||||
val deq = Decoupled(gen)
|
||||
}
|
||||
|
||||
val full = RegInit(Bool(false))
|
||||
val saved = Reg(gen)
|
||||
|
||||
// When !full, a repeater is pass-through
|
||||
io.deq.valid := io.enq.valid || full
|
||||
io.enq.ready := io.deq.ready && !full
|
||||
io.deq.bits := Mux(full, saved, io.enq.bits)
|
||||
io.full := full
|
||||
|
||||
when (io.enq.fire() && io.repeat) { full := Bool(true); saved := io.enq.bits }
|
||||
when (io.deq.fire() && !io.repeat) { full := Bool(false) }
|
||||
}
|
||||
|
||||
object Repeater
|
||||
{
|
||||
def apply[T <: Data](enq: DecoupledIO[T], repeat: Bool): DecoupledIO[T] = {
|
||||
val repeater = Module(new Repeater(enq.bits))
|
||||
repeater.io.repeat := repeat
|
||||
repeater.io.enq := enq
|
||||
repeater.io.deq
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// See LICENSE.Berkeley for license details.
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
package util
|
||||
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package util
|
||||
package freechips.rocketchip.util
|
||||
|
||||
import Chisel._
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip
|
||||
|
||||
import Chisel._
|
||||
import scala.math.min
|
||||
|
||||
package object util {
|
||||
implicit class UIntIsOneOf(val x: UInt) extends AnyVal {
|
||||
@ -70,20 +73,27 @@ package object util {
|
||||
def option[T](z: => T): Option[T] = if (x) Some(z) else None
|
||||
}
|
||||
|
||||
object PopCountAtLeast {
|
||||
private def two(x: UInt): (Bool, Bool) = x.getWidth match {
|
||||
case 1 => (x.toBool, Bool(false))
|
||||
case n =>
|
||||
val half = x.getWidth / 2
|
||||
val (leftOne, leftTwo) = two(x(half - 1, 0))
|
||||
val (rightOne, rightTwo) = two(x(x.getWidth - 1, half))
|
||||
(leftOne || rightOne, leftTwo || rightTwo || (leftOne && rightOne))
|
||||
}
|
||||
def apply(x: UInt, n: Int): Bool = n match {
|
||||
case 0 => Bool(true)
|
||||
case 1 => x.orR
|
||||
case 2 => two(x)._2
|
||||
case 3 => PopCount(x) >= UInt(n)
|
||||
}
|
||||
def OH1ToOH(x: UInt): UInt = (x << 1 | UInt(1)) & ~Cat(UInt(0, width=1), x)
|
||||
def OH1ToUInt(x: UInt): UInt = OHToUInt(OH1ToOH(x))
|
||||
def UIntToOH1(x: UInt, width: Int): UInt = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)
|
||||
|
||||
def trailingZeros(x: Int): Option[Int] = if (x > 0) Some(log2Ceil(x & -x)) else None
|
||||
|
||||
// Fill 1s from low bits to high bits
|
||||
def leftOR(x: UInt): UInt = leftOR(x, x.getWidth, x.getWidth)
|
||||
def leftOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = {
|
||||
val stop = min(width, cap)
|
||||
def helper(s: Int, x: UInt): UInt =
|
||||
if (s >= stop) x else helper(s+s, x | (x << s)(width-1,0))
|
||||
helper(1, x)(width-1, 0)
|
||||
}
|
||||
|
||||
// Fill 1s form high bits to low bits
|
||||
def rightOR(x: UInt): UInt = rightOR(x, x.getWidth, x.getWidth)
|
||||
def rightOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = {
|
||||
val stop = min(width, cap)
|
||||
def helper(s: Int, x: UInt): UInt =
|
||||
if (s >= stop) x else helper(s+s, x | (x >> s))
|
||||
helper(1, x)(width-1, 0)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user