devices: add support for the chiplink protocol
This commit is contained in:
106
src/main/scala/devices/chiplink/Partial.scala
Normal file
106
src/main/scala/devices/chiplink/Partial.scala
Normal file
@@ -0,0 +1,106 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user