107 lines
2.7 KiB
Scala
107 lines
2.7 KiB
Scala
// See LICENSE for license details.
|
|
package sifive.blocks.devices.chiplink
|
|
|
|
import Chisel._
|
|
import freechips.rocketchip.tilelink._
|
|
import freechips.rocketchip.util._
|
|
|
|
class ParitalExtractor[T <: TLDataChannel](gen: T) extends Module
|
|
{
|
|
val io = new Bundle {
|
|
val last = Bool(INPUT)
|
|
val i = Decoupled(gen).flip
|
|
val o = Decoupled(gen)
|
|
}
|
|
|
|
io.o <> io.i
|
|
|
|
// Grab references to the fields we care about
|
|
val (i_opcode, i_data) = io.i.bits match {
|
|
case a: TLBundleA => (a.opcode, a.data)
|
|
case b: TLBundleB => (b.opcode, b.data)
|
|
}
|
|
val (o_data, o_mask) = io.o.bits match {
|
|
case a: TLBundleA => (a.data, a.mask)
|
|
case b: TLBundleB => (b.data, b.mask)
|
|
}
|
|
|
|
val state = RegInit(UInt(0, width=4)) // number of nibbles; [0,8]
|
|
val shift = Reg(UInt(width=32))
|
|
val enable = i_opcode === TLMessages.PutPartialData
|
|
val empty = state === UInt(0)
|
|
|
|
when (enable) {
|
|
val wide = shift | (i_data << (state << 2))
|
|
o_data := Vec.tabulate(4) { i => wide(9*(i+1)-1, 9*i+1) } .asUInt
|
|
o_mask := Vec.tabulate(4) { i => wide(9*i) } .asUInt
|
|
|
|
// Swallow beat if we have no nibbles
|
|
when (empty) {
|
|
io.i.ready := Bool(true)
|
|
io.o.valid := Bool(false)
|
|
}
|
|
|
|
// Update the FSM
|
|
when (io.i.fire()) {
|
|
shift := Mux(empty, i_data, wide >> 36)
|
|
state := state - UInt(1)
|
|
when (empty) { state := UInt(8) }
|
|
when (io.last) { state := UInt(0) }
|
|
}
|
|
}
|
|
}
|
|
|
|
class PartialInjector[T <: TLDataChannel](gen: T) extends Module
|
|
{
|
|
val io = new Bundle {
|
|
val i_last = Bool(INPUT)
|
|
val o_last = Bool(OUTPUT)
|
|
val i = Decoupled(gen).flip
|
|
val o = Decoupled(gen)
|
|
}
|
|
|
|
io.o <> io.i
|
|
|
|
// Grab references to the fields we care about
|
|
val (i_opcode, i_data, i_mask) = io.i.bits match {
|
|
case a: TLBundleA => (a.opcode, a.data, a.mask)
|
|
case b: TLBundleB => (b.opcode, b.data, b.mask)
|
|
}
|
|
val o_data = io.o.bits match {
|
|
case a: TLBundleA => a.data
|
|
case b: TLBundleB => b.data
|
|
}
|
|
|
|
val state = RegInit(UInt(0, width=4)) // number of nibbles; [0,8]
|
|
val shift = RegInit(UInt(0, width=32))
|
|
val full = state(3)
|
|
val partial = i_opcode === TLMessages.PutPartialData
|
|
|
|
val last = RegInit(Bool(false))
|
|
io.o_last := Mux(partial, last, io.i_last)
|
|
|
|
when (partial) {
|
|
val bytes = Seq.tabulate(4) { i => i_data(8*(i+1)-1, 8*i) }
|
|
val bits = i_mask.toBools
|
|
val mixed = Cat(Seq(bits, bytes).transpose.flatten.reverse)
|
|
val wide = shift | (mixed << (state << 2))
|
|
o_data := wide
|
|
|
|
// Inject a beat
|
|
when ((io.i_last || full) && !last) {
|
|
io.i.ready := Bool(false)
|
|
}
|
|
|
|
// Update the FSM
|
|
when (io.o.fire()) {
|
|
shift := wide >> 32
|
|
state := state + UInt(1)
|
|
when (full || last) {
|
|
state := UInt(0)
|
|
shift := UInt(0)
|
|
}
|
|
last := io.i_last && !last
|
|
}
|
|
}
|
|
}
|