Fix CFU arbitration, add CFU decoder, CFU now redirect custom-0 with func3
This commit is contained in:
parent
310c325eaa
commit
a2b49ae000
|
@ -3,6 +3,8 @@ package vexriscv.plugin
|
|||
import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv}
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import spinal.lib.bus.bmb.WeakConnector
|
||||
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping}
|
||||
|
||||
case class CfuParameter(stageCount : Int,
|
||||
allowZeroLatency : Boolean,
|
||||
|
@ -23,37 +25,63 @@ case class CfuCmd(p : CfuParameter) extends Bundle{
|
|||
val reorder_id = UInt(p.CFU_REORDER_ID_W bits)
|
||||
val request_id = UInt(p.CFU_REQ_RESP_ID_W bits)
|
||||
val inputs = Vec(Bits(p.CFU_INPUT_DATA_W bits), p.CFU_INPUTS)
|
||||
|
||||
def weakAssignFrom(m : CfuCmd): Unit ={
|
||||
def s = this
|
||||
WeakConnector(m, s, m.function_id, s.function_id, defaultValue = null, allowUpSize = false, allowDownSize = true , allowDrop = true)
|
||||
WeakConnector(m, s, m.reorder_id, s.reorder_id, defaultValue = null, allowUpSize = false , allowDownSize = false, allowDrop = false)
|
||||
WeakConnector(m, s, m.request_id, s.request_id, defaultValue = null, allowUpSize = false, allowDownSize = false, allowDrop = false)
|
||||
s.inputs := m.inputs
|
||||
}
|
||||
}
|
||||
|
||||
case class CfuRsp(p : CfuParameter) extends Bundle{
|
||||
val response_ok = Bool()
|
||||
val response_id = UInt(p.CFU_REQ_RESP_ID_W bits)
|
||||
val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS)
|
||||
|
||||
def weakAssignFrom(m : CfuRsp): Unit ={
|
||||
def s = this
|
||||
s.response_ok := m.response_ok
|
||||
s.response_id := m.response_id
|
||||
s.outputs := m.outputs
|
||||
}
|
||||
}
|
||||
|
||||
case class CfuBus(p : CfuParameter) extends Bundle with IMasterSlave{
|
||||
val cmd = Stream(CfuCmd(p))
|
||||
val rsp = Stream(CfuRsp(p))
|
||||
|
||||
def <<(m : CfuBus) : Unit = {
|
||||
val s = this
|
||||
s.cmd.arbitrationFrom(m.cmd)
|
||||
m.rsp.arbitrationFrom(s.rsp)
|
||||
|
||||
s.cmd.weakAssignFrom(m.cmd)
|
||||
m.rsp.weakAssignFrom(s.rsp)
|
||||
}
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
slave(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{
|
||||
assert(p.CFU_INPUTS <= 2)
|
||||
assert(p.CFU_OUTPUTS == 1)
|
||||
assert(p.CFU_FUNCTION_ID_W == 3)
|
||||
|
||||
var bus : CfuBus = null
|
||||
var joinException : Flow[ExceptionCause] = null
|
||||
|
||||
lazy val forkStage = pipeline.execute
|
||||
lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + p.stageCount - 1))
|
||||
lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + p.stageCount))
|
||||
|
||||
|
||||
object CFU_ENABLE extends Stageable(Bool())
|
||||
object CFU_FUNCTION extends Stageable(UInt(p.CFU_FUNCTION_ID_W bits))
|
||||
object CFU_IN_FLIGHT extends Stageable(Bool())
|
||||
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
|
@ -64,21 +92,12 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{
|
|||
joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage)
|
||||
|
||||
val decoderService = pipeline.service(classOf[DecoderService])
|
||||
decoderService.addDefault(CFU_ENABLE, False)
|
||||
|
||||
//custom-0
|
||||
decoderService.add(List(
|
||||
M"000000-----------000-----0001011" -> List(
|
||||
M"000000-------------------0001011" -> List(
|
||||
CFU_ENABLE -> True,
|
||||
CFU_FUNCTION -> U"00",
|
||||
REGFILE_WRITE_VALID -> True,
|
||||
BYPASSABLE_EXECUTE_STAGE -> Bool(p.stageCount == 0),
|
||||
BYPASSABLE_MEMORY_STAGE -> Bool(p.stageCount <= 1),
|
||||
RS1_USE -> True,
|
||||
RS2_USE -> True
|
||||
),
|
||||
M"000000-----------001-----0001011" -> List(
|
||||
CFU_ENABLE -> True,
|
||||
CFU_FUNCTION -> U"01",
|
||||
REGFILE_WRITE_VALID -> True,
|
||||
BYPASSABLE_EXECUTE_STAGE -> Bool(p.stageCount == 0),
|
||||
BYPASSABLE_MEMORY_STAGE -> Bool(p.stageCount <= 1),
|
||||
|
@ -102,7 +121,7 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{
|
|||
bus.cmd.valid := (schedule || hold) && !fired
|
||||
arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready)
|
||||
|
||||
bus.cmd.function_id := input(CFU_FUNCTION)
|
||||
bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12))
|
||||
bus.cmd.reorder_id := 0
|
||||
bus.cmd.request_id := 0
|
||||
if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1)
|
||||
|
@ -132,7 +151,7 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{
|
|||
rsp.ready := False
|
||||
when(input(CFU_IN_FLIGHT)){
|
||||
arbitration.haltItself setWhen(!rsp.valid)
|
||||
rsp.ready := arbitration.isStuckByOthers
|
||||
rsp.ready := !arbitration.isStuckByOthers
|
||||
output(REGFILE_WRITE_DATA) := rsp.outputs(0)
|
||||
|
||||
when(arbitration.isValid){
|
||||
|
@ -142,3 +161,84 @@ class CfuPlugin(val p: CfuParameter) extends Plugin[VexRiscv]{
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object CfuTest{
|
||||
def getCfuParameter() = CfuParameter(
|
||||
stageCount = 0,
|
||||
allowZeroLatency = true,
|
||||
CFU_VERSION = 0,
|
||||
CFU_INTERFACE_ID_W = 0,
|
||||
CFU_FUNCTION_ID_W = 3,
|
||||
CFU_REORDER_ID_W = 0,
|
||||
CFU_REQ_RESP_ID_W = 0,
|
||||
CFU_INPUTS = 2,
|
||||
CFU_INPUT_DATA_W = 32,
|
||||
CFU_OUTPUTS = 1,
|
||||
CFU_OUTPUT_DATA_W = 32,
|
||||
CFU_FLOW_REQ_READY_ALWAYS = false,
|
||||
CFU_FLOW_RESP_READY_ALWAYS = false
|
||||
)
|
||||
}
|
||||
case class CfuTest() extends Component{
|
||||
val io = new Bundle {
|
||||
val bus = slave(CfuBus(CfuTest.getCfuParameter()))
|
||||
}
|
||||
io.bus.rsp.arbitrationFrom(io.bus.cmd)
|
||||
io.bus.rsp.response_ok := True
|
||||
io.bus.rsp.response_id := io.bus.cmd.request_id
|
||||
io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1))
|
||||
}
|
||||
|
||||
case class CfuDecoder(p : CfuParameter,
|
||||
mappings : Seq[AddressMapping],
|
||||
pendingMax : Int = 3) extends Component{
|
||||
val io = new Bundle {
|
||||
val input = slave(CfuBus(p))
|
||||
val outputs = Vec(master(CfuBus(p)), mappings.size)
|
||||
}
|
||||
val hasDefault = mappings.contains(DefaultMapping)
|
||||
val logic = if(hasDefault && mappings.size == 1){
|
||||
io.outputs(0) << io.input
|
||||
} else new Area {
|
||||
val hits = Vec(Bool, mappings.size)
|
||||
for (portId <- 0 until mappings.length) yield {
|
||||
val slaveBus = io.outputs(portId)
|
||||
val memorySpace = mappings(portId)
|
||||
val hit = hits(portId)
|
||||
hit := (memorySpace match {
|
||||
case DefaultMapping => !hits.filterNot(_ == hit).orR
|
||||
case _ => memorySpace.hit(io.input.cmd.function_id)
|
||||
})
|
||||
slaveBus.cmd.valid := io.input.cmd.valid && hit
|
||||
slaveBus.cmd.payload := io.input.cmd.payload.resized
|
||||
}
|
||||
val noHit = if (!hasDefault) !hits.orR else False
|
||||
io.input.cmd.ready := (hits, io.outputs).zipped.map(_ && _.cmd.ready).orR || noHit
|
||||
|
||||
val rspPendingCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init(0)
|
||||
rspPendingCounter := rspPendingCounter + U(io.input.cmd.fire) - U(io.input.rsp.fire)
|
||||
val rspHits = RegNextWhen(hits, io.input.cmd.fire)
|
||||
val rspPending = rspPendingCounter =/= 0
|
||||
val rspNoHitValid = if (!hasDefault) !rspHits.orR else False
|
||||
val rspNoHit = !hasDefault generate new Area{
|
||||
val doIt = RegInit(False) clearWhen(io.input.rsp.fire) setWhen(io.input.cmd.fire && noHit)
|
||||
val response_id = RegNextWhen(io.input.cmd.request_id, io.input.cmd.fire)
|
||||
}
|
||||
|
||||
io.input.rsp.valid := io.outputs.map(_.rsp.valid).orR || (rspPending && rspNoHitValid)
|
||||
io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits))
|
||||
if(!hasDefault) when(rspNoHit.doIt) {
|
||||
io.input.rsp.valid := True
|
||||
io.input.rsp.response_ok := False
|
||||
io.input.rsp.response_id := rspNoHit.response_id
|
||||
}
|
||||
for(output <- io.outputs) output.rsp.ready := io.input.rsp.ready
|
||||
|
||||
val cmdWait = (rspPending && (hits =/= rspHits || rspNoHitValid)) || rspPendingCounter === pendingMax
|
||||
when(cmdWait) {
|
||||
io.input.cmd.ready := False
|
||||
io.outputs.foreach(_.cmd.valid := False)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue