Merge remote-tracking branch 'origin/rpls-mul16'

This commit is contained in:
Charles Papon 2019-10-23 22:29:35 +02:00
commit f2a5134621
3 changed files with 147 additions and 12 deletions

View file

@ -0,0 +1,119 @@
package vexriscv.plugin
import vexriscv._
import vexriscv.plugin._
import spinal.core._
/**
* A multiplication plugin using only 16-bit multiplications
*/
class Mul16Plugin extends Plugin[VexRiscv]{
object MUL_LL extends Stageable(UInt(32 bits))
object MUL_LH extends Stageable(UInt(32 bits))
object MUL_HL extends Stageable(UInt(32 bits))
object MUL_HH extends Stageable(UInt(32 bits))
object MUL extends Stageable(Bits(64 bits))
object IS_MUL extends Stageable(Bool)
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val actions = List[(Stageable[_ <: BaseType],Any)](
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False,
RS1_USE -> True,
RS2_USE -> True,
IS_MUL -> True
)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(IS_MUL, False)
decoderService.add(List(
MULX -> actions
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
// Prepare signed inputs for the multiplier in the next stage.
// This will map them best to an FPGA DSP.
execute plug new Area {
import execute._
val a,b = Bits(32 bit)
a := input(SRC1)
b := input(SRC2)
val aLow = a(15 downto 0).asUInt
val bLow = b(15 downto 0).asUInt
val aHigh = a(31 downto 16).asUInt
val bHigh = b(31 downto 16).asUInt
insert(MUL_LL) := aLow * bLow
insert(MUL_LH) := aLow * bHigh
insert(MUL_HL) := aHigh * bLow
insert(MUL_HH) := aHigh * bHigh
}
memory plug new Area {
import memory._
val ll = UInt(32 bits)
val lh = UInt(33 bits)
val hl = UInt(32 bits)
val hh = UInt(32 bits)
ll := input(MUL_LL)
lh := input(MUL_LH).resized
hl := input(MUL_HL)
hh := input(MUL_HH)
val hllh = lh + hl
insert(MUL) := ((hh ## ll(31 downto 16)).asUInt + hllh) ## ll(15 downto 0)
}
writeBack plug new Area {
import writeBack._
val aSigned,bSigned = Bool
switch(input(INSTRUCTION)(13 downto 12)) {
is(B"01") {
aSigned := True
bSigned := True
}
is(B"10") {
aSigned := True
bSigned := False
}
default {
aSigned := False
bSigned := False
}
}
val a = (aSigned && input(SRC1).msb) ? input(SRC2).asUInt | U(0)
val b = (bSigned && input(SRC2).msb) ? input(SRC1).asUInt | U(0)
when(arbitration.isValid && input(IS_MUL)){
switch(input(INSTRUCTION)(13 downto 12)){
is(B"00"){
output(REGFILE_WRITE_DATA) := input(MUL)(31 downto 0)
}
is(B"01",B"10",B"11"){
output(REGFILE_WRITE_DATA) := (((input(MUL)(63 downto 32)).asUInt + ~a) + (~b + 2)).asBits
}
}
}
}
}
}

View file

@ -78,13 +78,19 @@ class MulDivIterativePlugin(genMul : Boolean = true,
val rs2 = Reg(UInt(32 bits))
val accumulator = Reg(UInt(65 bits))
//FrontendOK is only used for CPU configs without memory/writeback stages, were it is required to wait one extra cycle
// to let's the frontend process rs1 rs2 registers
val frontendOk = if(flushStage != execute) True else RegInit(False) setWhen(arbitration.isValid && !pipeline.service(classOf[HazardService]).hazardOnExecuteRS && ((if(genDiv) input(IS_DIV) else False) || (if(genMul) input(IS_MUL) else False))) clearWhen(arbitration.isMoving)
val mul = ifGen(genMul) (if(customMul != null) customMul(rs1,rs2,memory,pipeline) else new Area{
assert(isPow2(mulUnrollFactor))
val counter = Counter(32 / mulUnrollFactor + 1)
val done = counter.willOverflowIfInc
when(arbitration.isValid && input(IS_MUL)){
when(!done){
when(!frontendOk || !done){
arbitration.haltItself := True
}
when(frontendOk && !done){
arbitration.haltItself := True
counter.increment()
rs2 := rs2 |>> mulUnrollFactor
@ -113,8 +119,10 @@ class MulDivIterativePlugin(genMul : Boolean = true,
val done = Reg(Bool) setWhen(counter === counter.end-1) clearWhen(!arbitration.isStuck)
val result = Reg(Bits(32 bits))
when(arbitration.isValid && input(IS_DIV)){
when(!done){
when(!frontendOk || !done){
arbitration.haltItself := True
}
when(frontendOk && !done){
counter.increment()
def stages(inNumerator: UInt, inRemainder: UInt, stage: Int): Unit = stage match {
@ -140,16 +148,11 @@ class MulDivIterativePlugin(genMul : Boolean = true,
}
output(REGFILE_WRITE_DATA) := result
// when(input(INSTRUCTION)(13 downto 12) === "00" && counter === 0 && rs2 =/= 0 && rs1 < 16 && rs2 < 16 && !input(RS1).msb && !input(RS2).msb) {
// output(REGFILE_WRITE_DATA) := B(rs1(3 downto 0) / rs2(3 downto 0)).resized
// counter.willIncrement := False
// arbitration.haltItself := False
// }
}
})
//Execute stage logic to drive memory stage's input regs
when(!arbitration.isStuck){
when(if(flushStage != execute) !arbitration.isStuck else !frontendOk){
accumulator := 0
def twoComplement(that : Bits, enable: Bool): UInt = (Mux(enable, ~that, that).asUInt + enable.asUInt)
val rs2NeedRevert = execute.input(RS2).msb && execute.input(IS_RS2_SIGNED)

View file

@ -102,7 +102,7 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") {
new VexRiscvPosition("MulDivFpgaSimple") {
l = new VexRiscvPosition("MulDivFpgaSimple") {
override def testParam = "MUL=yes DIV=yes"
override def applyOn(config: VexRiscvConfig): Unit = {
config.plugins += new MulSimplePlugin
@ -115,6 +115,19 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") {
}
} :: l
if(!noMemory && !noWriteBack) l = new VexRiscvPosition("MulDivFpga16BitsDsp") {
override def testParam = "MUL=yes DIV=yes"
override def applyOn(config: VexRiscvConfig): Unit = {
config.plugins += new Mul16Plugin
config.plugins += new MulDivIterativePlugin(
genMul = false,
genDiv = true,
mulUnrollFactor = 32,
divUnrollFactor = 1
)
}
} :: l
if(!noMemory) {
l = new VexRiscvPosition("MulDivAsic") {
override def testParam = "MUL=yes DIV=yes"
@ -619,9 +632,9 @@ class TestIndividualFeatures extends FunSuite {
val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong
//
// val testId = Some(mutable.HashSet(3,4,9,11,13,16,18,19,20,21))
// val testId = Some(mutable.HashSet(22))
// val testId = Some(mutable.HashSet(22, 33 , 38, 47, 48))
// val seed = 5426556825163943143l
// val testId = Some(mutable.HashSet(11))
// val testId = Some(mutable.HashSet(4, 11))
// val seed = 6592877339343561798l
val rand = new Random(seed)