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} import vexriscv.Riscv.IMM object VfuPlugin{ val ROUND_MODE_WIDTH = 3 } case class VfuParameter() //Empty for now case class VfuCmd( p : VfuParameter ) extends Bundle{ val instruction = Bits(32 bits) val inputs = Vec(Bits(32 bits), 2) val rounding = Bits(VfuPlugin.ROUND_MODE_WIDTH bits) } case class VfuRsp(p : VfuParameter) extends Bundle{ val output = Bits(32 bits) } case class VfuBus(p : VfuParameter) extends Bundle with IMasterSlave{ val cmd = Stream(VfuCmd(p)) val rsp = Stream(VfuRsp(p)) def <<(m : VfuBus) : Unit = { val s = this s.cmd << m.cmd m.rsp << s.rsp } override def asMaster(): Unit = { master(cmd) slave(rsp) } } class VfuPlugin(val stageCount : Int, val allowZeroLatency : Boolean, val parameter : VfuParameter) extends Plugin[VexRiscv]{ def p = parameter var bus : VfuBus = null lazy val forkStage = pipeline.execute lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount)) object VFU_ENABLE extends Stageable(Bool()) object VFU_IN_FLIGHT extends Stageable(Bool()) override def setup(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ bus = master(VfuBus(p)) val decoderService = pipeline.service(classOf[DecoderService]) decoderService.addDefault(VFU_ENABLE, False) decoderService.add( key = M"-------------------------0001011", values = List( VFU_ENABLE -> True, REGFILE_WRITE_VALID -> True, //If you want to write something back into the integer register file BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0), BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1), RS1_USE -> True, RS2_USE -> True ) ) } override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ val csr = pipeline plug new Area{ val factory = pipeline.service(classOf[CsrInterface]) val rounding = Reg(Bits(VfuPlugin.ROUND_MODE_WIDTH bits)) factory.rw(csrAddress = 0xBC0, bitOffset = 0, that = rounding) } forkStage plug new Area{ import forkStage._ val hazard = stages.dropWhile(_ != forkStage).tail.map(s => s.arbitration.isValid && s.input(HAS_SIDE_EFFECT)).orR val scheduleWish = arbitration.isValid && input(VFU_ENABLE) val schedule = scheduleWish && !hazard arbitration.haltItself setWhen(scheduleWish && hazard) val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready) val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuck) insert(VFU_IN_FLIGHT) := schedule || hold || fired bus.cmd.valid := (schedule || hold) && !fired arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready) bus.cmd.instruction := input(INSTRUCTION) bus.cmd.inputs(0) := input(RS1) bus.cmd.inputs(1) := input(RS2) bus.cmd.rounding := csr.rounding } joinStage plug new Area{ import joinStage._ val rsp = if(forkStage != joinStage && allowZeroLatency) { bus.rsp.s2mPipe() } else { bus.rsp.combStage() } rsp.ready := False when(input(VFU_IN_FLIGHT) && input(REGFILE_WRITE_VALID)){ arbitration.haltItself setWhen(!bus.rsp.valid) rsp.ready := !arbitration.isStuckByOthers output(REGFILE_WRITE_DATA) := bus.rsp.output } } pipeline.stages.drop(1).foreach(s => s.output(VFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck)) addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(VFU_IN_FLIGHT).init(False))) } }