mirror of
https://github.com/SpinalHDL/VexRiscv.git
synced 2025-04-23 21:47:06 -04:00
Merge remote-tracking branch 'origin/rpls-mul16'
This commit is contained in:
commit
f2a5134621
3 changed files with 147 additions and 12 deletions
119
src/main/scala/vexriscv/plugin/Mul16Plugin.scala
Normal file
119
src/main/scala/vexriscv/plugin/Mul16Plugin.scala
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue