reorganize moving non-submodule packages into src/main/scala
This commit is contained in:
105
src/main/scala/uncore/util/AmoAlu.scala
Normal file
105
src/main/scala/uncore/util/AmoAlu.scala
Normal file
@ -0,0 +1,105 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package uncore.util
|
||||
|
||||
import Chisel._
|
||||
import uncore.tilelink._
|
||||
import cde.Parameters
|
||||
import uncore.constants._
|
||||
|
||||
class StoreGen(typ: UInt, addr: UInt, dat: UInt, maxSize: Int) {
|
||||
val size = typ(log2Up(log2Up(maxSize)+1)-1,0)
|
||||
def misaligned =
|
||||
(addr & ((UInt(1) << size) - UInt(1))(log2Up(maxSize)-1,0)).orR
|
||||
|
||||
def mask = {
|
||||
var res = UInt(1)
|
||||
for (i <- 0 until log2Up(maxSize)) {
|
||||
val upper = Mux(addr(i), res, UInt(0)) | Mux(size >= UInt(i+1), UInt((BigInt(1) << (1 << i))-1), UInt(0))
|
||||
val lower = Mux(addr(i), UInt(0), res)
|
||||
res = Cat(upper, lower)
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
protected def genData(i: Int): UInt =
|
||||
if (i >= log2Up(maxSize)) dat
|
||||
else Mux(size === UInt(i), Fill(1 << (log2Up(maxSize)-i), dat((8 << i)-1,0)), genData(i+1))
|
||||
|
||||
def data = genData(0)
|
||||
def wordData = genData(2)
|
||||
}
|
||||
|
||||
class StoreGenAligned(typ: UInt, addr: UInt, dat: UInt, maxSize: Int) extends StoreGen(typ, addr, dat, maxSize) {
|
||||
override def genData(i: Int) = dat
|
||||
}
|
||||
|
||||
class LoadGen(typ: UInt, signed: Bool, addr: UInt, dat: UInt, zero: Bool, maxSize: Int) {
|
||||
private val size = new StoreGen(typ, addr, dat, maxSize).size
|
||||
|
||||
private def genData(logMinSize: Int): UInt = {
|
||||
var res = dat
|
||||
for (i <- log2Up(maxSize)-1 to logMinSize by -1) {
|
||||
val pos = 8 << i
|
||||
val shifted = Mux(addr(i), res(2*pos-1,pos), res(pos-1,0))
|
||||
val doZero = Bool(i == 0) && zero
|
||||
val zeroed = Mux(doZero, UInt(0), shifted)
|
||||
res = Cat(Mux(size === UInt(i) || doZero, Fill(8*maxSize-pos, signed && zeroed(pos-1)), res(8*maxSize-1,pos)), zeroed)
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
def wordData = genData(2)
|
||||
def data = genData(0)
|
||||
}
|
||||
|
||||
class AMOALU(operandBits: Int, rhsIsAligned: Boolean = false)(implicit p: Parameters) extends Module {
|
||||
require(operandBits == 32 || operandBits == 64)
|
||||
val io = new Bundle {
|
||||
val addr = Bits(INPUT, log2Ceil(operandBits/8))
|
||||
val cmd = Bits(INPUT, M_SZ)
|
||||
val typ = Bits(INPUT, log2Ceil(log2Ceil(operandBits/8) + 1))
|
||||
val lhs = Bits(INPUT, operandBits)
|
||||
val rhs = Bits(INPUT, operandBits)
|
||||
val out = Bits(OUTPUT, operandBits)
|
||||
}
|
||||
|
||||
val storegen =
|
||||
if(rhsIsAligned) new StoreGenAligned(io.typ, io.addr, io.rhs, operandBits/8)
|
||||
else new StoreGen(io.typ, io.addr, io.rhs, operandBits/8)
|
||||
val rhs = storegen.wordData
|
||||
|
||||
val sgned = io.cmd === M_XA_MIN || io.cmd === M_XA_MAX
|
||||
val max = io.cmd === M_XA_MAX || io.cmd === M_XA_MAXU
|
||||
val min = io.cmd === M_XA_MIN || io.cmd === M_XA_MINU
|
||||
|
||||
val adder_out =
|
||||
if (operandBits == 32) io.lhs + rhs
|
||||
else {
|
||||
val mask = ~UInt(0,64) ^ (io.addr(2) << 31)
|
||||
(io.lhs & mask) + (rhs & mask)
|
||||
}
|
||||
|
||||
val less =
|
||||
if (operandBits == 32) Mux(io.lhs(31) === rhs(31), io.lhs < rhs, Mux(sgned, io.lhs(31), io.rhs(31)))
|
||||
else {
|
||||
val word = !io.typ(0)
|
||||
val cmp_lhs = Mux(word && !io.addr(2), io.lhs(31), io.lhs(63))
|
||||
val cmp_rhs = Mux(word && !io.addr(2), rhs(31), rhs(63))
|
||||
val lt_lo = io.lhs(31,0) < rhs(31,0)
|
||||
val lt_hi = io.lhs(63,32) < rhs(63,32)
|
||||
val eq_hi = io.lhs(63,32) === rhs(63,32)
|
||||
val lt = Mux(word, Mux(io.addr(2), lt_hi, lt_lo), lt_hi || eq_hi && lt_lo)
|
||||
Mux(cmp_lhs === cmp_rhs, lt, Mux(sgned, cmp_lhs, cmp_rhs))
|
||||
}
|
||||
|
||||
val out = Mux(io.cmd === M_XA_ADD, adder_out,
|
||||
Mux(io.cmd === M_XA_AND, io.lhs & rhs,
|
||||
Mux(io.cmd === M_XA_OR, io.lhs | rhs,
|
||||
Mux(io.cmd === M_XA_XOR, io.lhs ^ rhs,
|
||||
Mux(Mux(less, min, max), io.lhs,
|
||||
storegen.data)))))
|
||||
|
||||
val wmask = FillInterleaved(8, storegen.mask)
|
||||
io.out := wmask & out | ~wmask & io.lhs
|
||||
}
|
134
src/main/scala/uncore/util/Counters.scala
Normal file
134
src/main/scala/uncore/util/Counters.scala
Normal file
@ -0,0 +1,134 @@
|
||||
package uncore.util
|
||||
|
||||
import Chisel._
|
||||
import uncore.tilelink._
|
||||
import cde.Parameters
|
||||
|
||||
// Produces 0-width value when counting to 1
|
||||
class ZCounter(val n: Int) {
|
||||
val value = Reg(init=UInt(0, log2Ceil(n)))
|
||||
def inc(): Bool = {
|
||||
if (n == 1) Bool(true)
|
||||
else {
|
||||
val wrap = value === UInt(n-1)
|
||||
value := Mux(Bool(!isPow2(n)) && wrap, UInt(0), value + UInt(1))
|
||||
wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ZCounter {
|
||||
def apply(n: Int) = new ZCounter(n)
|
||||
def apply(cond: Bool, n: Int): (UInt, Bool) = {
|
||||
val c = new ZCounter(n)
|
||||
var wrap: Bool = null
|
||||
when (cond) { wrap = c.inc() }
|
||||
(c.value, cond && wrap)
|
||||
}
|
||||
}
|
||||
|
||||
object TwoWayCounter {
|
||||
def apply(up: Bool, down: Bool, max: Int): UInt = {
|
||||
val cnt = Reg(init = UInt(0, log2Up(max+1)))
|
||||
when (up && !down) { cnt := cnt + UInt(1) }
|
||||
when (down && !up) { cnt := cnt - UInt(1) }
|
||||
cnt
|
||||
}
|
||||
}
|
||||
|
||||
class BeatCounterStatus extends Bundle {
|
||||
val idx = UInt()
|
||||
val done = Bool()
|
||||
}
|
||||
|
||||
class TwoWayBeatCounterStatus extends Bundle {
|
||||
val pending = Bool()
|
||||
val up = new BeatCounterStatus()
|
||||
val down = new BeatCounterStatus()
|
||||
}
|
||||
|
||||
/** Utility trait containing wiring functions to keep track of how many data beats have
|
||||
* been sent or recieved over a particular [[uncore.TileLinkChannel]] or pair of channels.
|
||||
*
|
||||
* Won't count message types that don't have data.
|
||||
* Used in [[uncore.XactTracker]] and [[uncore.FinishUnit]].
|
||||
*/
|
||||
trait HasDataBeatCounters {
|
||||
type HasBeat = TileLinkChannel with HasTileLinkBeatId
|
||||
type HasId = TileLinkChannel with HasClientId
|
||||
|
||||
/** Returns the current count on this channel and when a message is done
|
||||
* @param inc increment the counter (usually .valid or .fire())
|
||||
* @param data the actual channel data
|
||||
* @param beat count to return for single-beat messages
|
||||
*/
|
||||
def connectDataBeatCounter[S <: TileLinkChannel](inc: Bool, data: S, beat: UInt) = {
|
||||
val multi = data.hasMultibeatData()
|
||||
val (multi_cnt, multi_done) = Counter(inc && multi, data.tlDataBeats)
|
||||
val cnt = Mux(multi, multi_cnt, beat)
|
||||
val done = Mux(multi, multi_done, inc)
|
||||
(cnt, done)
|
||||
}
|
||||
|
||||
/** Counter for beats on outgoing [[chisel.DecoupledIO]] */
|
||||
def connectOutgoingDataBeatCounter[T <: TileLinkChannel](
|
||||
out: DecoupledIO[T],
|
||||
beat: UInt = UInt(0)): (UInt, Bool) =
|
||||
connectDataBeatCounter(out.fire(), out.bits, beat)
|
||||
|
||||
/** Returns done but not cnt. Use the addr_beat subbundle instead of cnt for beats on
|
||||
* incoming channels in case of network reordering.
|
||||
*/
|
||||
def connectIncomingDataBeatCounter[T <: TileLinkChannel](in: DecoupledIO[T]): Bool =
|
||||
connectDataBeatCounter(in.fire(), in.bits, UInt(0))._2
|
||||
|
||||
/** Counter for beats on incoming DecoupledIO[LogicalNetworkIO[]]s returns done */
|
||||
def connectIncomingDataBeatCounterWithHeader[T <: TileLinkChannel](in: DecoupledIO[LogicalNetworkIO[T]]): Bool =
|
||||
connectDataBeatCounter(in.fire(), in.bits.payload, UInt(0))._2
|
||||
|
||||
/** If the network might interleave beats from different messages, we need a Vec of counters,
|
||||
* one for every outstanding message id that might be interleaved.
|
||||
*
|
||||
* @param getId mapping from Message to counter id
|
||||
*/
|
||||
def connectIncomingDataBeatCountersWithHeader[T <: TileLinkChannel with HasClientTransactionId](
|
||||
in: DecoupledIO[LogicalNetworkIO[T]],
|
||||
entries: Int,
|
||||
getId: LogicalNetworkIO[T] => UInt): Vec[Bool] = {
|
||||
Vec((0 until entries).map { i =>
|
||||
connectDataBeatCounter(in.fire() && getId(in.bits) === UInt(i), in.bits.payload, UInt(0))._2
|
||||
})
|
||||
}
|
||||
|
||||
/** Provides counters on two channels, as well a meta-counter that tracks how many
|
||||
* messages have been sent over the up channel but not yet responded to over the down channel
|
||||
*
|
||||
* @param status bundle of status of the counters
|
||||
* @param up outgoing channel
|
||||
* @param down incoming channel
|
||||
* @param max max number of outstanding ups with no down
|
||||
* @param beat overrides cnts on single-beat messages
|
||||
* @param track whether up's message should be tracked
|
||||
* @return a tuple containing whether their are outstanding messages, up's count,
|
||||
* up's done, down's count, down's done
|
||||
*/
|
||||
def connectTwoWayBeatCounters[T <: TileLinkChannel, S <: TileLinkChannel](
|
||||
status: TwoWayBeatCounterStatus,
|
||||
up: DecoupledIO[T],
|
||||
down: DecoupledIO[S],
|
||||
max: Int = 1,
|
||||
beat: UInt = UInt(0),
|
||||
trackUp: T => Bool = (t: T) => Bool(true),
|
||||
trackDown: S => Bool = (s: S) => Bool(true)) {
|
||||
val (up_idx, up_done) = connectDataBeatCounter(up.fire() && trackUp(up.bits), up.bits, beat)
|
||||
val (dn_idx, dn_done) = connectDataBeatCounter(down.fire() && trackDown(down.bits), down.bits, beat)
|
||||
val cnt = TwoWayCounter(up_done, dn_done, max)
|
||||
status.pending := cnt > UInt(0)
|
||||
status.up.idx := up_idx
|
||||
status.up.done := up_done
|
||||
status.down.idx := dn_idx
|
||||
status.down.done := dn_done
|
||||
}
|
||||
}
|
||||
|
||||
|
56
src/main/scala/uncore/util/Enqueuer.scala
Normal file
56
src/main/scala/uncore/util/Enqueuer.scala
Normal file
@ -0,0 +1,56 @@
|
||||
package uncore.util
|
||||
|
||||
import Chisel._
|
||||
import uncore.tilelink._
|
||||
import cde.Parameters
|
||||
|
||||
/** Struct for describing per-channel queue depths */
|
||||
case class TileLinkDepths(acq: Int, prb: Int, rel: Int, gnt: Int, fin: Int)
|
||||
|
||||
/** Optionally enqueues each [[uncore.TileLinkChannel]] individually */
|
||||
class TileLinkEnqueuer(depths: TileLinkDepths)(implicit p: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val client = new TileLinkIO().flip
|
||||
val manager = new TileLinkIO
|
||||
}
|
||||
io.manager.acquire <> (if(depths.acq > 0) Queue(io.client.acquire, depths.acq) else io.client.acquire)
|
||||
io.client.probe <> (if(depths.prb > 0) Queue(io.manager.probe, depths.prb) else io.manager.probe)
|
||||
io.manager.release <> (if(depths.rel > 0) Queue(io.client.release, depths.rel) else io.client.release)
|
||||
io.client.grant <> (if(depths.gnt > 0) Queue(io.manager.grant, depths.gnt) else io.manager.grant)
|
||||
io.manager.finish <> (if(depths.fin > 0) Queue(io.client.finish, depths.fin) else io.client.finish)
|
||||
}
|
||||
|
||||
object TileLinkEnqueuer {
|
||||
def apply(in: TileLinkIO, depths: TileLinkDepths)(implicit p: Parameters): TileLinkIO = {
|
||||
val t = Module(new TileLinkEnqueuer(depths))
|
||||
t.io.client <> in
|
||||
t.io.manager
|
||||
}
|
||||
def apply(in: TileLinkIO, depth: Int)(implicit p: Parameters): TileLinkIO = {
|
||||
apply(in, TileLinkDepths(depth, depth, depth, depth, depth))
|
||||
}
|
||||
}
|
||||
|
||||
class ClientTileLinkEnqueuer(depths: TileLinkDepths)(implicit p: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val inner = new ClientTileLinkIO().flip
|
||||
val outer = new ClientTileLinkIO
|
||||
}
|
||||
|
||||
io.outer.acquire <> (if(depths.acq > 0) Queue(io.inner.acquire, depths.acq) else io.inner.acquire)
|
||||
io.inner.probe <> (if(depths.prb > 0) Queue(io.outer.probe, depths.prb) else io.outer.probe)
|
||||
io.outer.release <> (if(depths.rel > 0) Queue(io.inner.release, depths.rel) else io.inner.release)
|
||||
io.inner.grant <> (if(depths.gnt > 0) Queue(io.outer.grant, depths.gnt) else io.outer.grant)
|
||||
io.outer.finish <> (if(depths.fin > 0) Queue(io.inner.finish, depths.fin) else io.inner.finish)
|
||||
}
|
||||
|
||||
object ClientTileLinkEnqueuer {
|
||||
def apply(in: ClientTileLinkIO, depths: TileLinkDepths)(implicit p: Parameters): ClientTileLinkIO = {
|
||||
val t = Module(new ClientTileLinkEnqueuer(depths))
|
||||
t.io.inner <> in
|
||||
t.io.outer
|
||||
}
|
||||
def apply(in: ClientTileLinkIO, depth: Int)(implicit p: Parameters): ClientTileLinkIO = {
|
||||
apply(in, TileLinkDepths(depth, depth, depth, depth, depth))
|
||||
}
|
||||
}
|
25
src/main/scala/uncore/util/Package.scala
Normal file
25
src/main/scala/uncore/util/Package.scala
Normal file
@ -0,0 +1,25 @@
|
||||
package uncore
|
||||
|
||||
import Chisel._
|
||||
|
||||
package object util {
|
||||
implicit class UIntIsOneOf(val x: UInt) extends AnyVal {
|
||||
def isOneOf(s: Seq[UInt]): Bool = s.map(x === _).reduce(_||_)
|
||||
|
||||
def isOneOf(u1: UInt, u2: UInt*): Bool = isOneOf(u1 +: u2.toSeq)
|
||||
}
|
||||
|
||||
implicit class SeqToAugmentedSeq[T <: Data](val x: Seq[T]) extends AnyVal {
|
||||
def apply(idx: UInt): T = {
|
||||
if (x.size == 1) {
|
||||
x.head
|
||||
} else {
|
||||
val half = 1 << (log2Ceil(x.size) - 1)
|
||||
val newIdx = idx & UInt(half - 1)
|
||||
Mux(idx >= UInt(half), x.drop(half)(newIdx), x.take(half)(newIdx))
|
||||
}
|
||||
}
|
||||
|
||||
def asUInt(): UInt = Cat(x.map(_.asUInt).reverse)
|
||||
}
|
||||
}
|
69
src/main/scala/uncore/util/Serializer.scala
Normal file
69
src/main/scala/uncore/util/Serializer.scala
Normal file
@ -0,0 +1,69 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package uncore.util
|
||||
|
||||
import Chisel._
|
||||
import uncore.tilelink._
|
||||
|
||||
class FlowThroughSerializer[T <: Bundle with HasTileLinkData](gen: T, n: Int) extends Module {
|
||||
val io = new Bundle {
|
||||
val in = Decoupled(gen).flip
|
||||
val out = Decoupled(gen)
|
||||
val cnt = UInt(OUTPUT, log2Up(n))
|
||||
val done = Bool(OUTPUT)
|
||||
}
|
||||
val narrowWidth = io.in.bits.data.getWidth / n
|
||||
require(io.in.bits.data.getWidth % narrowWidth == 0)
|
||||
|
||||
if(n == 1) {
|
||||
io.out <> io.in
|
||||
io.cnt := UInt(0)
|
||||
io.done := Bool(true)
|
||||
} else {
|
||||
val cnt = Reg(init=UInt(0, width = log2Up(n)))
|
||||
val wrap = cnt === UInt(n-1)
|
||||
val rbits = Reg{io.in.bits}
|
||||
val active = Reg(init=Bool(false))
|
||||
|
||||
val shifter = Wire(Vec(n, Bits(width = narrowWidth)))
|
||||
(0 until n).foreach {
|
||||
i => shifter(i) := rbits.data((i+1)*narrowWidth-1,i*narrowWidth)
|
||||
}
|
||||
|
||||
io.done := Bool(false)
|
||||
io.cnt := cnt
|
||||
io.in.ready := !active
|
||||
io.out.valid := active || io.in.valid
|
||||
io.out.bits := io.in.bits
|
||||
when(!active && io.in.valid) {
|
||||
when(io.in.bits.hasData()) {
|
||||
cnt := Mux(io.out.ready, UInt(1), UInt(0))
|
||||
rbits := io.in.bits
|
||||
active := Bool(true)
|
||||
}
|
||||
io.done := !io.in.bits.hasData()
|
||||
}
|
||||
when(active) {
|
||||
io.out.bits := rbits
|
||||
io.out.bits.data := shifter(cnt)
|
||||
when(io.out.ready) {
|
||||
cnt := cnt + UInt(1)
|
||||
when(wrap) {
|
||||
cnt := UInt(0)
|
||||
io.done := Bool(true)
|
||||
active := Bool(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object FlowThroughSerializer {
|
||||
def apply[T <: Bundle with HasTileLinkData](in: DecoupledIO[T], n: Int): DecoupledIO[T] = {
|
||||
val fs = Module(new FlowThroughSerializer(in.bits, n))
|
||||
fs.io.in.valid := in.valid
|
||||
fs.io.in.bits := in.bits
|
||||
in.ready := fs.io.in.ready
|
||||
fs.io.out
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user