1
0
Files
sifive-blocks/src/main/scala/devices/chiplink/Partial.scala
2018-03-22 16:06:10 -07:00

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
}
}
}