Merge branch 'dev' into fiber
# Conflicts: # src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala # src/main/scala/vexriscv/plugin/MulPlugin.scala
This commit is contained in:
commit
3a34b8dae2
|
@ -31,6 +31,11 @@ case class VexRiscvConfig(){
|
||||||
case None => None
|
case None => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
def get[T](clazz: Class[T]): T = {
|
||||||
|
plugins.find(_.getClass == clazz) match {
|
||||||
|
case Some(x) => x.asInstanceOf[T]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Default Stageables
|
//Default Stageables
|
||||||
object IS_RVC extends Stageable(Bool)
|
object IS_RVC extends Stageable(Bool)
|
||||||
|
|
|
@ -17,7 +17,7 @@ import spinal.idslplugin.PostInitCallback
|
||||||
import spinal.lib.misc.plic.PlicMapping
|
import spinal.lib.misc.plic.PlicMapping
|
||||||
import spinal.lib.system.debugger.SystemDebuggerConfig
|
import spinal.lib.system.debugger.SystemDebuggerConfig
|
||||||
import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig}
|
import vexriscv.ip.{DataCacheAck, DataCacheConfig, DataCacheMemBus, InstructionCache, InstructionCacheConfig}
|
||||||
import vexriscv.plugin.{BranchPlugin, CsrAccess, CsrPlugin, CsrPluginConfig, DBusCachedPlugin, DBusSimplePlugin, DYNAMIC_TARGET, DebugPlugin, DecoderSimplePlugin, FpuPlugin, FullBarrelShifterPlugin, HazardSimplePlugin, IBusCachedPlugin, IBusSimplePlugin, IntAluPlugin, MmuPlugin, MmuPortConfig, MulDivIterativePlugin, MulPlugin, RegFilePlugin, STATIC, SrcPlugin, StaticMemoryTranslatorPlugin, YamlPlugin}
|
import vexriscv.plugin._
|
||||||
import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin}
|
import vexriscv.{Riscv, VexRiscv, VexRiscvBmbGenerator, VexRiscvConfig, plugin}
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
|
@ -168,6 +168,7 @@ object VexRiscvSmpClusterGen {
|
||||||
iCacheWays : Int = 2,
|
iCacheWays : Int = 2,
|
||||||
dCacheWays : Int = 2,
|
dCacheWays : Int = 2,
|
||||||
iBusRelax : Boolean = false,
|
iBusRelax : Boolean = false,
|
||||||
|
injectorStage : Boolean = false,
|
||||||
earlyBranch : Boolean = false,
|
earlyBranch : Boolean = false,
|
||||||
dBusCmdMasterPipe : Boolean = false,
|
dBusCmdMasterPipe : Boolean = false,
|
||||||
withMmu : Boolean = true,
|
withMmu : Boolean = true,
|
||||||
|
@ -175,7 +176,8 @@ object VexRiscvSmpClusterGen {
|
||||||
withFloat : Boolean = false,
|
withFloat : Boolean = false,
|
||||||
withDouble : Boolean = false,
|
withDouble : Boolean = false,
|
||||||
externalFpu : Boolean = true,
|
externalFpu : Boolean = true,
|
||||||
simHalt : Boolean = false
|
simHalt : Boolean = false,
|
||||||
|
regfileRead : RegFileReadKind = plugin.ASYNC
|
||||||
) = {
|
) = {
|
||||||
assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes")
|
assert(iCacheSize/iCacheWays <= 4096, "Instruction cache ways can't be bigger than 4096 bytes")
|
||||||
assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes")
|
assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes")
|
||||||
|
@ -195,7 +197,7 @@ object VexRiscvSmpClusterGen {
|
||||||
prediction = vexriscv.plugin.NONE,
|
prediction = vexriscv.plugin.NONE,
|
||||||
historyRamSizeLog2 = 9,
|
historyRamSizeLog2 = 9,
|
||||||
relaxPredictorAddress = true,
|
relaxPredictorAddress = true,
|
||||||
injectorStage = false,
|
injectorStage = injectorStage,
|
||||||
relaxedPcCalculation = iBusRelax,
|
relaxedPcCalculation = iBusRelax,
|
||||||
config = InstructionCacheConfig(
|
config = InstructionCacheConfig(
|
||||||
cacheSize = iCacheSize,
|
cacheSize = iCacheSize,
|
||||||
|
@ -250,7 +252,7 @@ object VexRiscvSmpClusterGen {
|
||||||
catchIllegalInstruction = true
|
catchIllegalInstruction = true
|
||||||
),
|
),
|
||||||
new RegFilePlugin(
|
new RegFilePlugin(
|
||||||
regFileReadyKind = plugin.ASYNC,
|
regFileReadyKind = regfileRead,
|
||||||
zeroBoot = false,
|
zeroBoot = false,
|
||||||
x0Init = true
|
x0Init = true
|
||||||
),
|
),
|
||||||
|
|
|
@ -511,7 +511,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave
|
||||||
cmdCtx.payload := aggregationCounter
|
cmdCtx.payload := aggregationCounter
|
||||||
halt setWhen(!cmdCtx.ready)
|
halt setWhen(!cmdCtx.ready)
|
||||||
|
|
||||||
val syncCtx = cmdCtx.queue(syncPendingMax)
|
val syncCtx = cmdCtx.queue(syncPendingMax).s2mPipe().m2sPipe() //Assume latency of sync is at least 3 cycles
|
||||||
syncCtx.ready := bus.sync.fire
|
syncCtx.ready := bus.sync.fire
|
||||||
|
|
||||||
sync.arbitrationFrom(bus.sync)
|
sync.arbitrationFrom(bus.sync)
|
||||||
|
|
|
@ -49,13 +49,11 @@ case class CfuCmd( p : CfuBusParameter ) extends Bundle{
|
||||||
}
|
}
|
||||||
|
|
||||||
case class CfuRsp(p : CfuBusParameter) extends Bundle{
|
case class CfuRsp(p : CfuBusParameter) extends Bundle{
|
||||||
val response_ok = Bool()
|
|
||||||
val response_id = UInt(p.CFU_REQ_RESP_ID_W bits)
|
val response_id = UInt(p.CFU_REQ_RESP_ID_W bits)
|
||||||
val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS)
|
val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS)
|
||||||
|
|
||||||
def weakAssignFrom(m : CfuRsp): Unit ={
|
def weakAssignFrom(m : CfuRsp): Unit ={
|
||||||
def s = this
|
def s = this
|
||||||
s.response_ok := m.response_ok
|
|
||||||
s.response_id := m.response_id
|
s.response_id := m.response_id
|
||||||
s.outputs := m.outputs
|
s.outputs := m.outputs
|
||||||
}
|
}
|
||||||
|
@ -105,7 +103,6 @@ class CfuPlugin(val stageCount : Int,
|
||||||
// assert(p.CFU_FUNCTION_ID_W == 3)
|
// assert(p.CFU_FUNCTION_ID_W == 3)
|
||||||
|
|
||||||
var bus : CfuBus = null
|
var bus : CfuBus = null
|
||||||
var joinException : Flow[ExceptionCause] = null
|
|
||||||
|
|
||||||
lazy val forkStage = pipeline.execute
|
lazy val forkStage = pipeline.execute
|
||||||
lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount))
|
lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount))
|
||||||
|
@ -121,7 +118,6 @@ class CfuPlugin(val stageCount : Int,
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
|
||||||
bus = master(CfuBus(p))
|
bus = master(CfuBus(p))
|
||||||
joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage)
|
|
||||||
|
|
||||||
val decoderService = pipeline.service(classOf[DecoderService])
|
val decoderService = pipeline.service(classOf[DecoderService])
|
||||||
decoderService.addDefault(CFU_ENABLE, False)
|
decoderService.addDefault(CFU_ENABLE, False)
|
||||||
|
@ -207,22 +203,15 @@ class CfuPlugin(val stageCount : Int,
|
||||||
bus.rsp.combStage()
|
bus.rsp.combStage()
|
||||||
}
|
}
|
||||||
|
|
||||||
joinException.valid := False
|
|
||||||
joinException.code := 15
|
|
||||||
joinException.badAddr := 0
|
|
||||||
|
|
||||||
rsp.ready := False
|
rsp.ready := False
|
||||||
when(input(CFU_IN_FLIGHT)){
|
when(input(CFU_IN_FLIGHT)){
|
||||||
arbitration.haltItself setWhen(!rsp.valid)
|
arbitration.haltItself setWhen(!rsp.valid)
|
||||||
rsp.ready := !arbitration.isStuckByOthers
|
rsp.ready := !arbitration.isStuckByOthers
|
||||||
output(REGFILE_WRITE_DATA) := rsp.outputs(0)
|
output(REGFILE_WRITE_DATA) := rsp.outputs(0)
|
||||||
|
|
||||||
when(arbitration.isValid){
|
|
||||||
joinException.valid := !rsp.response_ok
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pipeline.stages.drop(1).foreach(s => s.output(CFU_IN_FLIGHT) clearWhen(s.arbitration.isStuck))
|
||||||
addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False)))
|
addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +240,6 @@ case class CfuTest() extends Component{
|
||||||
val bus = slave(CfuBus(CfuTest.getCfuParameter()))
|
val bus = slave(CfuBus(CfuTest.getCfuParameter()))
|
||||||
}
|
}
|
||||||
io.bus.rsp.arbitrationFrom(io.bus.cmd)
|
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.response_id := io.bus.cmd.request_id
|
||||||
io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1))
|
io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1))
|
||||||
}
|
}
|
||||||
|
@ -320,7 +308,6 @@ case class CfuDecoder(p : CfuBusParameter,
|
||||||
io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits))
|
io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits))
|
||||||
if(!hasDefault) when(rspNoHit.doIt) {
|
if(!hasDefault) when(rspNoHit.doIt) {
|
||||||
io.input.rsp.valid := True
|
io.input.rsp.valid := True
|
||||||
io.input.rsp.response_ok := False
|
|
||||||
io.input.rsp.response_id := rspNoHit.response_id
|
io.input.rsp.response_id := rspNoHit.response_id
|
||||||
}
|
}
|
||||||
for(output <- io.outputs) output.rsp.ready := io.input.rsp.ready
|
for(output <- io.outputs) output.rsp.ready := io.input.rsp.ready
|
||||||
|
|
|
@ -31,29 +31,62 @@ class HazardSimplePlugin(bypassExecute : Boolean = false,
|
||||||
override def build(pipeline: VexRiscv): Unit = {
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
import pipeline._
|
import pipeline._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
val src0Hazard = False
|
|
||||||
val src1Hazard = False
|
|
||||||
|
|
||||||
val readStage = service(classOf[RegFileService]).readStage()
|
pipeline plug new Area {
|
||||||
|
val src0Hazard = False
|
||||||
|
val src1Hazard = False
|
||||||
|
|
||||||
def trackHazardWithStage(stage : Stage,bypassable : Boolean, runtimeBypassable : Stageable[Bool]): Unit ={
|
val readStage = service(classOf[RegFileService]).readStage()
|
||||||
val runtimeBypassableValue = if(runtimeBypassable != null) stage.input(runtimeBypassable) else True
|
|
||||||
val addr0Match = if(pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs1Range)
|
def trackHazardWithStage(stage: Stage, bypassable: Boolean, runtimeBypassable: Stageable[Bool]): Unit = {
|
||||||
val addr1Match = if(pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs2Range)
|
val runtimeBypassableValue = if (runtimeBypassable != null) stage.input(runtimeBypassable) else True
|
||||||
when(stage.arbitration.isValid && stage.input(REGFILE_WRITE_VALID)) {
|
val addr0Match = if (pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs1Range)
|
||||||
if (bypassable) {
|
val addr1Match = if (pessimisticAddressMatch) True else stage.input(INSTRUCTION)(rdRange) === readStage.input(INSTRUCTION)(rs2Range)
|
||||||
when(runtimeBypassableValue) {
|
when(stage.arbitration.isValid && stage.input(REGFILE_WRITE_VALID)) {
|
||||||
|
if (bypassable) {
|
||||||
|
when(runtimeBypassableValue) {
|
||||||
|
when(addr0Match) {
|
||||||
|
readStage.input(RS1) := stage.output(REGFILE_WRITE_DATA)
|
||||||
|
}
|
||||||
|
when(addr1Match) {
|
||||||
|
readStage.input(RS2) := stage.output(REGFILE_WRITE_DATA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when(stage.arbitration.isValid && (if (pessimisticWriteRegFile) True else stage.input(REGFILE_WRITE_VALID))) {
|
||||||
|
when((Bool(!bypassable) || !runtimeBypassableValue)) {
|
||||||
when(addr0Match) {
|
when(addr0Match) {
|
||||||
readStage.input(RS1) := stage.output(REGFILE_WRITE_DATA)
|
src0Hazard := True
|
||||||
}
|
}
|
||||||
when(addr1Match) {
|
when(addr1Match) {
|
||||||
readStage.input(RS2) := stage.output(REGFILE_WRITE_DATA)
|
src1Hazard := True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
when(stage.arbitration.isValid && (if(pessimisticWriteRegFile) True else stage.input(REGFILE_WRITE_VALID))) {
|
|
||||||
when((Bool(!bypassable) || !runtimeBypassableValue)) {
|
|
||||||
|
val writeBackWrites = Flow(cloneable(new Bundle {
|
||||||
|
val address = Bits(5 bits)
|
||||||
|
val data = Bits(32 bits)
|
||||||
|
}))
|
||||||
|
writeBackWrites.valid := stages.last.output(REGFILE_WRITE_VALID) && stages.last.arbitration.isFiring
|
||||||
|
writeBackWrites.address := stages.last.output(INSTRUCTION)(rdRange)
|
||||||
|
writeBackWrites.data := stages.last.output(REGFILE_WRITE_DATA)
|
||||||
|
val writeBackBuffer = writeBackWrites.stage()
|
||||||
|
|
||||||
|
val addr0Match = if (pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs1Range)
|
||||||
|
val addr1Match = if (pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs2Range)
|
||||||
|
when(writeBackBuffer.valid) {
|
||||||
|
if (bypassWriteBackBuffer) {
|
||||||
|
when(addr0Match) {
|
||||||
|
readStage.input(RS1) := writeBackBuffer.data
|
||||||
|
}
|
||||||
|
when(addr1Match) {
|
||||||
|
readStage.input(RS2) := writeBackBuffer.data
|
||||||
|
}
|
||||||
|
} else {
|
||||||
when(addr0Match) {
|
when(addr0Match) {
|
||||||
src0Hazard := True
|
src0Hazard := True
|
||||||
}
|
}
|
||||||
|
@ -62,54 +95,24 @@ class HazardSimplePlugin(bypassExecute : Boolean = false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (withWriteBackStage) trackHazardWithStage(writeBack, bypassWriteBack, null)
|
||||||
|
if (withMemoryStage) trackHazardWithStage(memory, bypassMemory, if (stages.last == memory) null else BYPASSABLE_MEMORY_STAGE)
|
||||||
|
if (readStage != execute) trackHazardWithStage(execute, bypassExecute, if (stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE)
|
||||||
|
|
||||||
|
|
||||||
val writeBackWrites = Flow(cloneable(new Bundle{
|
if (!pessimisticUseSrc) {
|
||||||
val address = Bits(5 bits)
|
when(!readStage.input(RS1_USE)) {
|
||||||
val data = Bits(32 bits)
|
src0Hazard := False
|
||||||
}))
|
|
||||||
writeBackWrites.valid := stages.last.output(REGFILE_WRITE_VALID) && stages.last.arbitration.isFiring
|
|
||||||
writeBackWrites.address := stages.last.output(INSTRUCTION)(rdRange)
|
|
||||||
writeBackWrites.data := stages.last.output(REGFILE_WRITE_DATA)
|
|
||||||
val writeBackBuffer = writeBackWrites.stage()
|
|
||||||
|
|
||||||
val addr0Match = if(pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs1Range)
|
|
||||||
val addr1Match = if(pessimisticAddressMatch) True else writeBackBuffer.address === readStage.input(INSTRUCTION)(rs2Range)
|
|
||||||
when(writeBackBuffer.valid) {
|
|
||||||
if (bypassWriteBackBuffer) {
|
|
||||||
when(addr0Match) {
|
|
||||||
readStage.input(RS1) := writeBackBuffer.data
|
|
||||||
}
|
}
|
||||||
when(addr1Match) {
|
when(!readStage.input(RS2_USE)) {
|
||||||
readStage.input(RS2) := writeBackBuffer.data
|
src1Hazard := False
|
||||||
}
|
|
||||||
} else {
|
|
||||||
when(addr0Match) {
|
|
||||||
src0Hazard := True
|
|
||||||
}
|
|
||||||
when(addr1Match) {
|
|
||||||
src1Hazard := True
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(withWriteBackStage) trackHazardWithStage(writeBack,bypassWriteBack,null)
|
when(readStage.arbitration.isValid && (src0Hazard || src1Hazard)) {
|
||||||
if(withMemoryStage) trackHazardWithStage(memory ,bypassMemory, if(stages.last == memory) null else BYPASSABLE_MEMORY_STAGE)
|
readStage.arbitration.haltByOther := True
|
||||||
if(readStage != execute) trackHazardWithStage(execute ,bypassExecute , if(stages.last == execute) null else BYPASSABLE_EXECUTE_STAGE)
|
|
||||||
|
|
||||||
|
|
||||||
if(!pessimisticUseSrc) {
|
|
||||||
when(!readStage.input(RS1_USE)) {
|
|
||||||
src0Hazard := False
|
|
||||||
}
|
}
|
||||||
when(!readStage.input(RS2_USE)) {
|
|
||||||
src1Hazard := False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when(readStage.arbitration.isValid && (src0Hazard || src1Hazard)){
|
|
||||||
readStage.arbitration.haltByOther := True
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,8 @@ import spinal.core._
|
||||||
import spinal.lib.KeepAttribute
|
import spinal.lib.KeepAttribute
|
||||||
|
|
||||||
//Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much.
|
//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] with VexRiscvRegressionArg {
|
class MulPlugin(var inputBuffer : Boolean = false,
|
||||||
|
var outputBuffer : Boolean = false) extends Plugin[VexRiscv] with VexRiscvRegressionArg {
|
||||||
object MUL_LL extends Stageable(UInt(32 bits))
|
object MUL_LL extends Stageable(UInt(32 bits))
|
||||||
object MUL_LH extends Stageable(SInt(34 bits))
|
object MUL_LH extends Stageable(SInt(34 bits))
|
||||||
object MUL_HL extends Stageable(SInt(34 bits))
|
object MUL_HL extends Stageable(SInt(34 bits))
|
||||||
|
@ -19,7 +20,6 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv] with Vex
|
||||||
List("MUL=yes")
|
List("MUL=yes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override def setup(pipeline: VexRiscv): Unit = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
import Riscv._
|
import Riscv._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
@ -58,16 +58,25 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv] with Vex
|
||||||
// a := input(SRC1)
|
// a := input(SRC1)
|
||||||
// b := input(SRC2)
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
counter := counter + 1
|
||||||
|
when(!arbitration.isStuck || arbitration.isStuckByOthers){
|
||||||
|
counter := 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val withInputBuffer = inputBuffer generate new Area{
|
val withInputBuffer = inputBuffer generate new Area{
|
||||||
val rs1 = RegNext(input(RS1))
|
val rs1 = RegNext(input(RS1))
|
||||||
val rs2 = RegNext(input(RS2))
|
val rs2 = RegNext(input(RS2))
|
||||||
a := rs1
|
a := rs1
|
||||||
b := rs2
|
b := rs2
|
||||||
|
|
||||||
val delay = RegNext(arbitration.isStuck)
|
|
||||||
when(arbitration.isValid && input(IS_MUL) && !delay){
|
|
||||||
arbitration.haltItself := True
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val noInputBuffer = (!inputBuffer) generate new Area{
|
val noInputBuffer = (!inputBuffer) generate new Area{
|
||||||
|
@ -96,10 +105,25 @@ class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv] with Vex
|
||||||
val bSLow = (False ## b(15 downto 0)).asSInt
|
val bSLow = (False ## b(15 downto 0)).asSInt
|
||||||
val aHigh = (((aSigned && a.msb) ## a(31 downto 16))).asSInt
|
val aHigh = (((aSigned && a.msb) ## a(31 downto 16))).asSInt
|
||||||
val bHigh = (((bSigned && b.msb) ## b(31 downto 16))).asSInt
|
val bHigh = (((bSigned && b.msb) ## b(31 downto 16))).asSInt
|
||||||
insert(MUL_LL) := aULow * bULow
|
|
||||||
insert(MUL_LH) := aSLow * bHigh
|
val withOuputBuffer = outputBuffer generate new Area{
|
||||||
insert(MUL_HL) := aHigh * bSLow
|
val mul_ll = RegNext(aULow * bULow)
|
||||||
insert(MUL_HH) := aHigh * bHigh
|
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{
|
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)
|
//Avoid synthesis tools to retime RS1 RS2 from execute stage to decode stage leading to bad timings (ex : Vivado, even if retiming is disabled)
|
||||||
|
|
|
@ -173,19 +173,26 @@ class MulDivDimension extends VexRiscvDimension("MulDiv") {
|
||||||
} :: l
|
} :: l
|
||||||
|
|
||||||
|
|
||||||
if(!noMemory && !noWriteBack) l =
|
if(!noMemory && !noWriteBack) {
|
||||||
new VexRiscvPosition("MulDivFpga") {
|
val inputBuffer = r.nextBoolean()
|
||||||
override def testParam = "MUL=yes DIV=yes"
|
val outputBuffer = r.nextBoolean()
|
||||||
override def applyOn(config: VexRiscvConfig): Unit = {
|
l = new VexRiscvPosition(s"MulDivFpga$inputBuffer$outputBuffer") {
|
||||||
config.plugins += new MulPlugin
|
override def testParam = "MUL=yes DIV=yes"
|
||||||
config.plugins += new MulDivIterativePlugin(
|
|
||||||
genMul = false,
|
override def applyOn(config: VexRiscvConfig): Unit = {
|
||||||
genDiv = true,
|
config.plugins += new MulPlugin(
|
||||||
mulUnrollFactor = 32,
|
inputBuffer = inputBuffer,
|
||||||
divUnrollFactor = 1
|
outputBuffer = outputBuffer
|
||||||
)
|
)
|
||||||
}
|
config.plugins += new MulDivIterativePlugin(
|
||||||
} :: l
|
genMul = false,
|
||||||
|
genDiv = true,
|
||||||
|
mulUnrollFactor = 32,
|
||||||
|
divUnrollFactor = 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} :: l
|
||||||
|
}
|
||||||
|
|
||||||
random(r, l)
|
random(r, l)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue