diff --git a/src/main/scala/vexriscv/plugin/MulPlugin.scala b/src/main/scala/vexriscv/plugin/MulPlugin.scala index 31714e8..c1619d2 100644 --- a/src/main/scala/vexriscv/plugin/MulPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MulPlugin.scala @@ -5,7 +5,8 @@ import spinal.core._ import spinal.lib.KeepAttribute //Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much. -class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ +class MulPlugin(var inputBuffer : Boolean = false, + var outputBuffer : Boolean = false) extends Plugin[VexRiscv]{ object MUL_LL extends Stageable(UInt(32 bits)) object MUL_LH extends Stageable(SInt(34 bits)) object MUL_HL extends Stageable(SInt(34 bits)) @@ -53,16 +54,26 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ // a := input(SRC1) // b := input(SRC2) + val delay = (if(inputBuffer) 1 else 0) + (if(outputBuffer) 1 else 0) + + val delayLogic = (delay != 0) generate new Area{ + val counter = Reg(UInt(log2Up(delay+1) bits)) + when(arbitration.isValid && input(IS_MUL) && counter =/= delay){ + arbitration.haltItself := True + } + when(!arbitration.isStuckByOthers){ + counter := counter + 1 + } + when(!arbitration.isStuck){ + counter := 0 + } + } + val withInputBuffer = inputBuffer generate new Area{ val rs1 = RegNext(input(RS1)) val rs2 = RegNext(input(RS2)) a := rs1 b := rs2 - - val delay = RegNext(arbitration.isStuck) - when(arbitration.isValid && input(IS_MUL) && !delay){ - arbitration.haltItself := True - } } val noInputBuffer = (!inputBuffer) generate new Area{ @@ -91,10 +102,25 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{ val bSLow = (False ## b(15 downto 0)).asSInt val aHigh = (((aSigned && a.msb) ## a(31 downto 16))).asSInt val bHigh = (((bSigned && b.msb) ## b(31 downto 16))).asSInt - insert(MUL_LL) := aULow * bULow - insert(MUL_LH) := aSLow * bHigh - insert(MUL_HL) := aHigh * bSLow - insert(MUL_HH) := aHigh * bHigh + + val withOuputBuffer = outputBuffer generate new Area{ + val mul_ll = RegNext(aULow * bULow) + val mul_lh = RegNext(aSLow * bHigh) + val mul_hl = RegNext(aHigh * bSLow) + val mul_hh = RegNext(aHigh * bHigh) + + insert(MUL_LL) := mul_ll + insert(MUL_LH) := mul_lh + insert(MUL_HL) := mul_hl + insert(MUL_HH) := mul_hh + } + + val noOutputBuffer = (!outputBuffer) generate new Area{ + insert(MUL_LL) := aULow * bULow + insert(MUL_LH) := aSLow * bHigh + insert(MUL_HL) := aHigh * bSLow + insert(MUL_HH) := aHigh * bHigh + } Component.current.afterElaboration{ //Avoid synthesis tools to retime RS1 RS2 from execute stage to decode stage leading to bad timings (ex : Vivado, even if retiming is disabled) diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 0cf5ce6..429ad3e 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -173,19 +173,26 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") { } :: l - if(!noMemory && !noWriteBack) l = - new VexRiscvPosition("MulDivFpga") { - override def testParam = "MUL=yes DIV=yes" - override def applyOn(config: VexRiscvConfig): Unit = { - config.plugins += new MulPlugin - config.plugins += new MulDivIterativePlugin( - genMul = false, - genDiv = true, - mulUnrollFactor = 32, - divUnrollFactor = 1 - ) - } - } :: l + if(!noMemory && !noWriteBack) { + val inputBuffer = r.nextBoolean() + val outputBuffer = r.nextBoolean() + l = new VexRiscvPosition(s"MulDivFpga$inputBuffer$outputBuffer") { + override def testParam = "MUL=yes DIV=yes" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulPlugin( + inputBuffer = inputBuffer, + outputBuffer = outputBuffer + ) + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + } random(r, l) }