mirror of
https://github.com/SpinalHDL/VexRiscv.git
synced 2025-04-24 05:57:07 -04:00
iBusSimplePlugin done, DebugPlugin need minor rework
This commit is contained in:
parent
64022557bf
commit
ac74fb9ce8
13 changed files with 939 additions and 735 deletions
|
@ -31,33 +31,33 @@ object TestsWorkspace {
|
|||
SpinalConfig(mergeAsyncProcess = false).generateVerilog {
|
||||
val configFull = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new PcManagerSimplePlugin(
|
||||
resetVector = 0x80000000l,
|
||||
relaxedPcCalculation = false
|
||||
),
|
||||
// new IBusSimplePlugin(
|
||||
// interfaceKeepData = false,
|
||||
// catchAccessFault = true
|
||||
// new PcManagerSimplePlugin(
|
||||
// resetVector = 0x80000000l,
|
||||
// relaxedPcCalculation = false
|
||||
// ),
|
||||
new IBusCachedPlugin(
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 1024*16,
|
||||
bytePerLine = 32,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchIllegalAccess = true,
|
||||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoCycleRam = false
|
||||
),
|
||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
portTlbSize = 4
|
||||
)
|
||||
new IBusSimplePlugin(
|
||||
interfaceKeepData = false,
|
||||
catchAccessFault = true
|
||||
),
|
||||
// new DBusSimplePlugin(
|
||||
// new IBusCachedPlugin(
|
||||
// config = InstructionCacheConfig(
|
||||
// cacheSize = 1024*16,
|
||||
// bytePerLine = 32,
|
||||
// wayCount = 1,
|
||||
// addressWidth = 32,
|
||||
// cpuDataWidth = 32,
|
||||
// memDataWidth = 32,
|
||||
// catchIllegalAccess = true,
|
||||
// catchAccessFault = true,
|
||||
// catchMemoryTranslationMiss = true,
|
||||
// asyncTagMemory = false,
|
||||
// twoCycleRam = false
|
||||
// ),
|
||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
// portTlbSize = 4
|
||||
// )
|
||||
// ),
|
||||
//// new DBusSimplePlugin(
|
||||
// catchAddressMisaligned = true,
|
||||
// catchAccessFault = true,
|
||||
// earlyInjection = false
|
||||
|
@ -122,11 +122,11 @@ object TestsWorkspace {
|
|||
),
|
||||
// new DivPlugin,
|
||||
new CsrPlugin(CsrPluginConfig.all(0x80000020l).copy(deterministicInteruptionEntry = false)),
|
||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new BranchPlugin(
|
||||
earlyBranch = true,
|
||||
catchAddressMisaligned = true,
|
||||
prediction = DYNAMIC_TARGET,
|
||||
prediction = NONE,
|
||||
historyRamSizeLog2 = 8
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
|
|
|
@ -58,8 +58,8 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
|
|||
type T = VexRiscv
|
||||
import config._
|
||||
|
||||
stages ++= List.fill(6)(new Stage())
|
||||
val prefetch :: fetch :: decode :: execute :: memory :: writeBack :: Nil = stages.toList
|
||||
stages ++= List.fill(4)(new Stage())
|
||||
val /*prefetch :: fetch :: */decode :: execute :: memory :: writeBack :: Nil = stages.toList
|
||||
plugins ++= config.plugins
|
||||
|
||||
//regression usage
|
||||
|
|
|
@ -11,10 +11,10 @@ object GenSmallestNoCsr extends App{
|
|||
def cpu() = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new PcManagerSimplePlugin(
|
||||
resetVector = 0x00000000l,
|
||||
relaxedPcCalculation = false
|
||||
),
|
||||
// new PcManagerSimplePlugin(
|
||||
// resetVector = 0x00000000l,
|
||||
// relaxedPcCalculation = false
|
||||
// ),
|
||||
new IBusSimplePlugin(
|
||||
interfaceKeepData = false,
|
||||
catchAccessFault = false
|
||||
|
|
|
@ -64,7 +64,7 @@ class MuraxMasterArbiter(simpleBusConfig : SimpleBusConfig) extends Component{
|
|||
io.masterBus.cmd.valid := False
|
||||
}
|
||||
|
||||
io.iBus.rsp.ready := io.masterBus.rsp.valid && !rspTarget
|
||||
io.iBus.rsp.valid := io.masterBus.rsp.valid && !rspTarget
|
||||
io.iBus.rsp.inst := io.masterBus.rsp.data
|
||||
io.iBus.rsp.error := False
|
||||
|
||||
|
|
|
@ -70,8 +70,8 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
|
||||
prediction match {
|
||||
case NONE =>
|
||||
case STATIC | DYNAMIC => predictionJumpInterface = pcManagerService.createJumpInterface(pipeline.decode)
|
||||
case DYNAMIC_TARGET => predictionJumpInterface = pcManagerService.createJumpInterface(pipeline.fetch)
|
||||
// case STATIC | DYNAMIC => predictionJumpInterface = pcManagerService.createJumpInterface(pipeline.decode)
|
||||
// case DYNAMIC_TARGET => predictionJumpInterface = pcManagerService.createJumpInterface(pipeline.fetch)
|
||||
}
|
||||
|
||||
if (catchAddressMisaligned) {
|
||||
|
@ -79,17 +79,17 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
branchExceptionPort = exceptionService.newExceptionPort(if (earlyBranch) pipeline.execute else pipeline.memory)
|
||||
prediction match {
|
||||
case NONE =>
|
||||
case STATIC | DYNAMIC => predictionExceptionPort = exceptionService.newExceptionPort(pipeline.decode)
|
||||
case DYNAMIC_TARGET =>
|
||||
// case STATIC | DYNAMIC => predictionExceptionPort = exceptionService.newExceptionPort(pipeline.decode)
|
||||
// case DYNAMIC_TARGET =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = prediction match {
|
||||
case `NONE` => buildWithoutPrediction(pipeline)
|
||||
case `STATIC` => buildWithPrediction(pipeline)
|
||||
case `DYNAMIC` => buildWithPrediction(pipeline)
|
||||
case `DYNAMIC_TARGET` => buildDynamicTargetPrediction(pipeline)
|
||||
// case `STATIC` => buildWithPrediction(pipeline)
|
||||
// case `DYNAMIC` => buildWithPrediction(pipeline)
|
||||
// case `DYNAMIC_TARGET` => buildDynamicTargetPrediction(pipeline)
|
||||
}
|
||||
|
||||
def buildWithoutPrediction(pipeline: VexRiscv): Unit = {
|
||||
|
@ -147,262 +147,262 @@ class BranchPlugin(earlyBranch : Boolean,
|
|||
}
|
||||
|
||||
|
||||
def buildWithPrediction(pipeline: VexRiscv): Unit = {
|
||||
case class BranchPredictorLine() extends Bundle{
|
||||
val history = SInt(historyWidth bits)
|
||||
}
|
||||
|
||||
object PREDICTION_HAD_BRANCHED extends Stageable(Bool)
|
||||
object HISTORY_LINE extends Stageable(BranchPredictorLine())
|
||||
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
val historyCache = if(prediction == DYNAMIC) Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) setName("branchCache") else null
|
||||
val historyCacheWrite = if(prediction == DYNAMIC) historyCache.writePort else null
|
||||
|
||||
//Read historyCache
|
||||
if(prediction == DYNAMIC) fetch plug new Area{
|
||||
val readAddress = prefetch.output(PC)(2, historyRamSizeLog2 bits)
|
||||
fetch.insert(HISTORY_LINE) := historyCache.readSync(readAddress,!prefetch.arbitration.isStuckByOthers)
|
||||
|
||||
//WriteFirst bypass TODO long combinatorial path
|
||||
// val writePortReg = RegNext(historyCacheWrite)
|
||||
// when(writePortReg.valid && writePortReg.address === readAddress){
|
||||
// fetch.insert(HISTORY_LINE) := writePortReg.data
|
||||
// def buildWithPrediction(pipeline: VexRiscv): Unit = {
|
||||
// case class BranchPredictorLine() extends Bundle{
|
||||
// val history = SInt(historyWidth bits)
|
||||
// }
|
||||
//
|
||||
// object PREDICTION_HAD_BRANCHED extends Stageable(Bool)
|
||||
// object HISTORY_LINE extends Stageable(BranchPredictorLine())
|
||||
//
|
||||
// import pipeline._
|
||||
// import pipeline.config._
|
||||
//
|
||||
// val historyCache = if(prediction == DYNAMIC) Mem(BranchPredictorLine(), 1 << historyRamSizeLog2) setName("branchCache") else null
|
||||
// val historyCacheWrite = if(prediction == DYNAMIC) historyCache.writePort else null
|
||||
//
|
||||
// //Read historyCache
|
||||
// if(prediction == DYNAMIC) fetch plug new Area{
|
||||
// val readAddress = prefetch.output(PC)(2, historyRamSizeLog2 bits)
|
||||
// fetch.insert(HISTORY_LINE) := historyCache.readSync(readAddress,!prefetch.arbitration.isStuckByOthers)
|
||||
//
|
||||
// //WriteFirst bypass TODO long combinatorial path
|
||||
//// val writePortReg = RegNext(historyCacheWrite)
|
||||
//// when(writePortReg.valid && writePortReg.address === readAddress){
|
||||
//// fetch.insert(HISTORY_LINE) := writePortReg.data
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// //Branch JAL, predict Bxx and branch it
|
||||
// decode plug new Area{
|
||||
// import decode._
|
||||
// val imm = IMM(input(INSTRUCTION))
|
||||
//
|
||||
// val conditionalBranchPrediction = (prediction match {
|
||||
// case `STATIC` => imm.b_sext.msb
|
||||
// case `DYNAMIC` => input(HISTORY_LINE).history.msb
|
||||
// })
|
||||
// insert(PREDICTION_HAD_BRANCHED) := input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction)
|
||||
//
|
||||
// predictionJumpInterface.valid := input(PREDICTION_HAD_BRANCHED) && arbitration.isFiring //TODO OH Doublon de priorité
|
||||
// predictionJumpInterface.payload := input(PC) + ((input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
|
||||
// when(predictionJumpInterface.valid) {
|
||||
// fetch.arbitration.flushAll := True
|
||||
// }
|
||||
}
|
||||
|
||||
//Branch JAL, predict Bxx and branch it
|
||||
decode plug new Area{
|
||||
import decode._
|
||||
val imm = IMM(input(INSTRUCTION))
|
||||
|
||||
val conditionalBranchPrediction = (prediction match {
|
||||
case `STATIC` => imm.b_sext.msb
|
||||
case `DYNAMIC` => input(HISTORY_LINE).history.msb
|
||||
})
|
||||
insert(PREDICTION_HAD_BRANCHED) := input(BRANCH_CTRL) === BranchCtrlEnum.JAL || (input(BRANCH_CTRL) === BranchCtrlEnum.B && conditionalBranchPrediction)
|
||||
|
||||
predictionJumpInterface.valid := input(PREDICTION_HAD_BRANCHED) && arbitration.isFiring //TODO OH Doublon de priorité
|
||||
predictionJumpInterface.payload := input(PC) + ((input(BRANCH_CTRL) === BranchCtrlEnum.JAL) ? imm.j_sext | imm.b_sext).asUInt
|
||||
when(predictionJumpInterface.valid) {
|
||||
fetch.arbitration.flushAll := True
|
||||
}
|
||||
|
||||
if(catchAddressMisaligned) {
|
||||
predictionExceptionPort.valid := input(INSTRUCTION_READY) && input(PREDICTION_HAD_BRANCHED) && arbitration.isValid && predictionJumpInterface.payload(1 downto 0) =/= 0
|
||||
predictionExceptionPort.code := 0
|
||||
predictionExceptionPort.badAddr := predictionJumpInterface.payload
|
||||
}
|
||||
}
|
||||
|
||||
//Do real branch calculation
|
||||
execute plug new Area {
|
||||
import execute._
|
||||
|
||||
val less = input(SRC_LESS)
|
||||
val eq = input(SRC1) === input(SRC2)
|
||||
|
||||
insert(BRANCH_COND_RESULT) := input(BRANCH_CTRL).mux(
|
||||
BranchCtrlEnum.INC -> False,
|
||||
BranchCtrlEnum.JAL -> True,
|
||||
BranchCtrlEnum.JALR -> True,
|
||||
BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux(
|
||||
B"000" -> eq ,
|
||||
B"001" -> !eq ,
|
||||
M"1-1" -> !less,
|
||||
default -> less
|
||||
)
|
||||
)
|
||||
|
||||
insert(BRANCH_DO) := input(PREDICTION_HAD_BRANCHED) =/= insert(BRANCH_COND_RESULT)
|
||||
|
||||
//Calculation of the branch target / correction
|
||||
val imm = IMM(input(INSTRUCTION))
|
||||
val branch_src1,branch_src2 = UInt(32 bits)
|
||||
switch(input(BRANCH_CTRL)){
|
||||
is(BranchCtrlEnum.JALR){
|
||||
branch_src1 := input(RS1).asUInt
|
||||
branch_src2 := imm.i_sext.asUInt
|
||||
}
|
||||
default{
|
||||
branch_src1 := input(PC)
|
||||
branch_src2 := (input(PREDICTION_HAD_BRANCHED) ? B(4) | imm.b_sext).asUInt
|
||||
}
|
||||
}
|
||||
val branchAdder = branch_src1 + branch_src2
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ ((input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? False | branchAdder(0))
|
||||
}
|
||||
|
||||
|
||||
// branch JALR or JAL/Bxx prediction miss corrections
|
||||
val branchStage = if(earlyBranch) execute else memory
|
||||
branchStage plug new Area {
|
||||
import branchStage._
|
||||
jumpInterface.valid := input(BRANCH_DO) && arbitration.isFiring
|
||||
jumpInterface.payload := input(BRANCH_CALC)
|
||||
|
||||
when(jumpInterface.valid) {
|
||||
stages(indexOf(branchStage) - 1).arbitration.flushAll := True
|
||||
}
|
||||
|
||||
if(catchAddressMisaligned) {
|
||||
branchExceptionPort.valid := input(INSTRUCTION_READY) && arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1 downto 0) =/= 0
|
||||
branchExceptionPort.code := 0
|
||||
branchExceptionPort.badAddr := jumpInterface.payload
|
||||
}
|
||||
}
|
||||
|
||||
//Update historyCache
|
||||
if(prediction == DYNAMIC) branchStage plug new Area {
|
||||
import branchStage._
|
||||
val newHistory = input(HISTORY_LINE).history.resize(historyWidth + 1) + Mux(input(BRANCH_COND_RESULT),S(-1),S(1))
|
||||
val noOverflow = newHistory(newHistory.high downto newHistory.high - 1) =/= S"10" && newHistory(newHistory.high downto newHistory.high - 1) =/= S"01"
|
||||
|
||||
historyCacheWrite.valid := arbitration.isFiring && input(BRANCH_CTRL) === BranchCtrlEnum.B && noOverflow
|
||||
historyCacheWrite.address := input(PC)(2, historyRamSizeLog2 bits)
|
||||
historyCacheWrite.data.history := newHistory.resized
|
||||
}
|
||||
}
|
||||
//
|
||||
// if(catchAddressMisaligned) {
|
||||
// predictionExceptionPort.valid := input(INSTRUCTION_READY) && input(PREDICTION_HAD_BRANCHED) && arbitration.isValid && predictionJumpInterface.payload(1 downto 0) =/= 0
|
||||
// predictionExceptionPort.code := 0
|
||||
// predictionExceptionPort.badAddr := predictionJumpInterface.payload
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //Do real branch calculation
|
||||
// execute plug new Area {
|
||||
// import execute._
|
||||
//
|
||||
// val less = input(SRC_LESS)
|
||||
// val eq = input(SRC1) === input(SRC2)
|
||||
//
|
||||
// insert(BRANCH_COND_RESULT) := input(BRANCH_CTRL).mux(
|
||||
// BranchCtrlEnum.INC -> False,
|
||||
// BranchCtrlEnum.JAL -> True,
|
||||
// BranchCtrlEnum.JALR -> True,
|
||||
// BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux(
|
||||
// B"000" -> eq ,
|
||||
// B"001" -> !eq ,
|
||||
// M"1-1" -> !less,
|
||||
// default -> less
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// insert(BRANCH_DO) := input(PREDICTION_HAD_BRANCHED) =/= insert(BRANCH_COND_RESULT)
|
||||
//
|
||||
// //Calculation of the branch target / correction
|
||||
// val imm = IMM(input(INSTRUCTION))
|
||||
// val branch_src1,branch_src2 = UInt(32 bits)
|
||||
// switch(input(BRANCH_CTRL)){
|
||||
// is(BranchCtrlEnum.JALR){
|
||||
// branch_src1 := input(RS1).asUInt
|
||||
// branch_src2 := imm.i_sext.asUInt
|
||||
// }
|
||||
// default{
|
||||
// branch_src1 := input(PC)
|
||||
// branch_src2 := (input(PREDICTION_HAD_BRANCHED) ? B(4) | imm.b_sext).asUInt
|
||||
// }
|
||||
// }
|
||||
// val branchAdder = branch_src1 + branch_src2
|
||||
// insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ ((input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? False | branchAdder(0))
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // branch JALR or JAL/Bxx prediction miss corrections
|
||||
// val branchStage = if(earlyBranch) execute else memory
|
||||
// branchStage plug new Area {
|
||||
// import branchStage._
|
||||
// jumpInterface.valid := input(BRANCH_DO) && arbitration.isFiring
|
||||
// jumpInterface.payload := input(BRANCH_CALC)
|
||||
//
|
||||
// when(jumpInterface.valid) {
|
||||
// stages(indexOf(branchStage) - 1).arbitration.flushAll := True
|
||||
// }
|
||||
//
|
||||
// if(catchAddressMisaligned) {
|
||||
// branchExceptionPort.valid := input(INSTRUCTION_READY) && arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1 downto 0) =/= 0
|
||||
// branchExceptionPort.code := 0
|
||||
// branchExceptionPort.badAddr := jumpInterface.payload
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //Update historyCache
|
||||
// if(prediction == DYNAMIC) branchStage plug new Area {
|
||||
// import branchStage._
|
||||
// val newHistory = input(HISTORY_LINE).history.resize(historyWidth + 1) + Mux(input(BRANCH_COND_RESULT),S(-1),S(1))
|
||||
// val noOverflow = newHistory(newHistory.high downto newHistory.high - 1) =/= S"10" && newHistory(newHistory.high downto newHistory.high - 1) =/= S"01"
|
||||
//
|
||||
// historyCacheWrite.valid := arbitration.isFiring && input(BRANCH_CTRL) === BranchCtrlEnum.B && noOverflow
|
||||
// historyCacheWrite.address := input(PC)(2, historyRamSizeLog2 bits)
|
||||
// historyCacheWrite.data.history := newHistory.resized
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def buildDynamicTargetPrediction(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
case class BranchPredictorLine() extends Bundle{
|
||||
val source = Bits(31 - historyRamSizeLog2 bits)
|
||||
val confidence = UInt(2 bits)
|
||||
val target = UInt(32 bits)
|
||||
}
|
||||
|
||||
object PREDICTION_WRITE_HAZARD extends Stageable(Bool)
|
||||
object PREDICTION extends Stageable(BranchPredictorLine())
|
||||
object PREDICTION_HIT extends Stageable(Bool)
|
||||
|
||||
val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
|
||||
val historyWrite = history.writePort
|
||||
|
||||
|
||||
fetch plug new Area{
|
||||
import fetch._
|
||||
val line = history.readSync((prefetch.output(PC) >> 2).resized, prefetch.arbitration.isFiring)
|
||||
// val line = history.readAsync((fetch.output(PC) >> 2).resized)
|
||||
val hit = line.source === (input(PC).asBits >> 1 + historyRamSizeLog2)
|
||||
|
||||
//Avoid write to read hazard
|
||||
val historyWriteLast = RegNext(historyWrite)
|
||||
val hazard = historyWriteLast.valid && historyWriteLast.address === (output(PC) >> 2).resized
|
||||
insert(PREDICTION_WRITE_HAZARD) := hazard
|
||||
|
||||
predictionJumpInterface.valid := line.confidence.msb && hit && arbitration.isFiring && !hazard
|
||||
predictionJumpInterface.payload := line.target
|
||||
|
||||
insert(PREDICTION) := line
|
||||
insert(PREDICTION_HIT) := hit
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Do branch calculations (conditions + target PC)
|
||||
execute plug new Area {
|
||||
import execute._
|
||||
|
||||
val less = input(SRC_LESS)
|
||||
val eq = input(SRC1) === input(SRC2)
|
||||
|
||||
insert(BRANCH_DO) := input(BRANCH_CTRL).mux(
|
||||
BranchCtrlEnum.INC -> False,
|
||||
BranchCtrlEnum.JAL -> True,
|
||||
BranchCtrlEnum.JALR -> True,
|
||||
BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux(
|
||||
B"000" -> eq ,
|
||||
B"001" -> !eq ,
|
||||
M"1-1" -> !less,
|
||||
default -> less
|
||||
)
|
||||
)
|
||||
|
||||
val imm = IMM(input(INSTRUCTION))
|
||||
val branch_src1 = (input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? input(RS1).asUInt | input(PC)
|
||||
val branch_src2 = input(BRANCH_CTRL).mux(
|
||||
BranchCtrlEnum.JAL -> imm.j_sext,
|
||||
BranchCtrlEnum.JALR -> imm.i_sext,
|
||||
default -> imm.b_sext
|
||||
).asUInt
|
||||
|
||||
val branchAdder = branch_src1 + branch_src2
|
||||
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ ((input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? False | branchAdder(0))
|
||||
}
|
||||
|
||||
//Apply branchs (JAL,JALR, Bxx)
|
||||
val branchStage = if(earlyBranch) execute else memory
|
||||
branchStage plug new Area {
|
||||
import branchStage._
|
||||
|
||||
val predictionMissmatch = input(PREDICTION).confidence.msb =/= input(BRANCH_DO) || (input(BRANCH_DO) && input(PREDICTION).target =/= input(BRANCH_CALC))
|
||||
|
||||
historyWrite.valid := False
|
||||
historyWrite.address := (branchStage.output(PC) >> 2).resized
|
||||
historyWrite.data.source := input(PC).asBits >> 1 + historyRamSizeLog2
|
||||
historyWrite.data.target := input(BRANCH_CALC)
|
||||
|
||||
jumpInterface.valid := False
|
||||
jumpInterface.payload := input(BRANCH_CALC)
|
||||
|
||||
|
||||
when(!input(BRANCH_DO)){
|
||||
historyWrite.valid := arbitration.isFiring && input(PREDICTION_HIT)
|
||||
historyWrite.data.confidence := input(PREDICTION).confidence - (input(PREDICTION).confidence =/= 0).asUInt
|
||||
historyWrite.data.target := input(BRANCH_CALC)
|
||||
|
||||
|
||||
jumpInterface.valid := input(PREDICTION_HIT) && input(PREDICTION).confidence.msb && !input(PREDICTION_WRITE_HAZARD) && arbitration.isFiring
|
||||
jumpInterface.payload := input(PC) + 4
|
||||
} otherwise{
|
||||
when(!input(PREDICTION_HIT) || input(PREDICTION_WRITE_HAZARD)){
|
||||
jumpInterface.valid := arbitration.isFiring
|
||||
historyWrite.valid := arbitration.isFiring
|
||||
historyWrite.data.confidence := "10"
|
||||
} otherwise {
|
||||
historyWrite.valid := arbitration.isFiring
|
||||
historyWrite.data.confidence := input(PREDICTION).confidence + (input(PREDICTION).confidence =/= 3).asUInt
|
||||
when(!input(PREDICTION).confidence.msb || input(PREDICTION).target =/= input(BRANCH_CALC)){
|
||||
jumpInterface.valid := arbitration.isFiring
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Prevent rewriting an history which already had hazard
|
||||
historyWrite.valid clearWhen(input(PREDICTION_WRITE_HAZARD))
|
||||
|
||||
|
||||
|
||||
when(jumpInterface.valid) {
|
||||
stages(indexOf(branchStage) - 1).arbitration.flushAll := True
|
||||
}
|
||||
|
||||
if(catchAddressMisaligned) {
|
||||
branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1 downto 0) =/= 0
|
||||
branchExceptionPort.code := 0
|
||||
branchExceptionPort.badAddr := jumpInterface.payload
|
||||
}
|
||||
}
|
||||
|
||||
//Init History
|
||||
val historyInit = pipeline plug new Area{
|
||||
val counter = Reg(UInt(historyRamSizeLog2 + 1 bits)) init(0)
|
||||
when(!counter.msb){
|
||||
prefetch.arbitration.haltByOther := True
|
||||
historyWrite.valid := True
|
||||
historyWrite.address := counter.resized
|
||||
historyWrite.data.confidence := 0
|
||||
counter := counter + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
// def buildDynamicTargetPrediction(pipeline: VexRiscv): Unit = {
|
||||
// import pipeline._
|
||||
// import pipeline.config._
|
||||
//
|
||||
// case class BranchPredictorLine() extends Bundle{
|
||||
// val source = Bits(31 - historyRamSizeLog2 bits)
|
||||
// val confidence = UInt(2 bits)
|
||||
// val target = UInt(32 bits)
|
||||
// }
|
||||
//
|
||||
// object PREDICTION_WRITE_HAZARD extends Stageable(Bool)
|
||||
// object PREDICTION extends Stageable(BranchPredictorLine())
|
||||
// object PREDICTION_HIT extends Stageable(Bool)
|
||||
//
|
||||
// val history = Mem(BranchPredictorLine(), 1 << historyRamSizeLog2)
|
||||
// val historyWrite = history.writePort
|
||||
//
|
||||
//
|
||||
// fetch plug new Area{
|
||||
// import fetch._
|
||||
// val line = history.readSync((prefetch.output(PC) >> 2).resized, prefetch.arbitration.isFiring)
|
||||
//// val line = history.readAsync((fetch.output(PC) >> 2).resized)
|
||||
// val hit = line.source === (input(PC).asBits >> 1 + historyRamSizeLog2)
|
||||
//
|
||||
// //Avoid write to read hazard
|
||||
// val historyWriteLast = RegNext(historyWrite)
|
||||
// val hazard = historyWriteLast.valid && historyWriteLast.address === (output(PC) >> 2).resized
|
||||
// insert(PREDICTION_WRITE_HAZARD) := hazard
|
||||
//
|
||||
// predictionJumpInterface.valid := line.confidence.msb && hit && arbitration.isFiring && !hazard
|
||||
// predictionJumpInterface.payload := line.target
|
||||
//
|
||||
// insert(PREDICTION) := line
|
||||
// insert(PREDICTION_HIT) := hit
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// //Do branch calculations (conditions + target PC)
|
||||
// execute plug new Area {
|
||||
// import execute._
|
||||
//
|
||||
// val less = input(SRC_LESS)
|
||||
// val eq = input(SRC1) === input(SRC2)
|
||||
//
|
||||
// insert(BRANCH_DO) := input(BRANCH_CTRL).mux(
|
||||
// BranchCtrlEnum.INC -> False,
|
||||
// BranchCtrlEnum.JAL -> True,
|
||||
// BranchCtrlEnum.JALR -> True,
|
||||
// BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux(
|
||||
// B"000" -> eq ,
|
||||
// B"001" -> !eq ,
|
||||
// M"1-1" -> !less,
|
||||
// default -> less
|
||||
// )
|
||||
// )
|
||||
//
|
||||
// val imm = IMM(input(INSTRUCTION))
|
||||
// val branch_src1 = (input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? input(RS1).asUInt | input(PC)
|
||||
// val branch_src2 = input(BRANCH_CTRL).mux(
|
||||
// BranchCtrlEnum.JAL -> imm.j_sext,
|
||||
// BranchCtrlEnum.JALR -> imm.i_sext,
|
||||
// default -> imm.b_sext
|
||||
// ).asUInt
|
||||
//
|
||||
// val branchAdder = branch_src1 + branch_src2
|
||||
// insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ ((input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? False | branchAdder(0))
|
||||
// }
|
||||
//
|
||||
// //Apply branchs (JAL,JALR, Bxx)
|
||||
// val branchStage = if(earlyBranch) execute else memory
|
||||
// branchStage plug new Area {
|
||||
// import branchStage._
|
||||
//
|
||||
// val predictionMissmatch = input(PREDICTION).confidence.msb =/= input(BRANCH_DO) || (input(BRANCH_DO) && input(PREDICTION).target =/= input(BRANCH_CALC))
|
||||
//
|
||||
// historyWrite.valid := False
|
||||
// historyWrite.address := (branchStage.output(PC) >> 2).resized
|
||||
// historyWrite.data.source := input(PC).asBits >> 1 + historyRamSizeLog2
|
||||
// historyWrite.data.target := input(BRANCH_CALC)
|
||||
//
|
||||
// jumpInterface.valid := False
|
||||
// jumpInterface.payload := input(BRANCH_CALC)
|
||||
//
|
||||
//
|
||||
// when(!input(BRANCH_DO)){
|
||||
// historyWrite.valid := arbitration.isFiring && input(PREDICTION_HIT)
|
||||
// historyWrite.data.confidence := input(PREDICTION).confidence - (input(PREDICTION).confidence =/= 0).asUInt
|
||||
// historyWrite.data.target := input(BRANCH_CALC)
|
||||
//
|
||||
//
|
||||
// jumpInterface.valid := input(PREDICTION_HIT) && input(PREDICTION).confidence.msb && !input(PREDICTION_WRITE_HAZARD) && arbitration.isFiring
|
||||
// jumpInterface.payload := input(PC) + 4
|
||||
// } otherwise{
|
||||
// when(!input(PREDICTION_HIT) || input(PREDICTION_WRITE_HAZARD)){
|
||||
// jumpInterface.valid := arbitration.isFiring
|
||||
// historyWrite.valid := arbitration.isFiring
|
||||
// historyWrite.data.confidence := "10"
|
||||
// } otherwise {
|
||||
// historyWrite.valid := arbitration.isFiring
|
||||
// historyWrite.data.confidence := input(PREDICTION).confidence + (input(PREDICTION).confidence =/= 3).asUInt
|
||||
// when(!input(PREDICTION).confidence.msb || input(PREDICTION).target =/= input(BRANCH_CALC)){
|
||||
// jumpInterface.valid := arbitration.isFiring
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //Prevent rewriting an history which already had hazard
|
||||
// historyWrite.valid clearWhen(input(PREDICTION_WRITE_HAZARD))
|
||||
//
|
||||
//
|
||||
//
|
||||
// when(jumpInterface.valid) {
|
||||
// stages(indexOf(branchStage) - 1).arbitration.flushAll := True
|
||||
// }
|
||||
//
|
||||
// if(catchAddressMisaligned) {
|
||||
// branchExceptionPort.valid := arbitration.isValid && input(BRANCH_DO) && jumpInterface.payload(1 downto 0) =/= 0
|
||||
// branchExceptionPort.code := 0
|
||||
// branchExceptionPort.badAddr := jumpInterface.payload
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //Init History
|
||||
// val historyInit = pipeline plug new Area{
|
||||
// val counter = Reg(UInt(historyRamSizeLog2 + 1 bits)) init(0)
|
||||
// when(!counter.msb){
|
||||
// prefetch.arbitration.haltByOther := True
|
||||
// historyWrite.valid := True
|
||||
// historyWrite.address := counter.resized
|
||||
// historyWrite.data.confidence := 0
|
||||
// counter := counter + 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -376,8 +376,8 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
|
|||
//Used to make the pipeline empty softly (for interrupts)
|
||||
val pipelineLiberator = new Area{
|
||||
val enable = False.noBackendCombMerge //Verilator Perf
|
||||
prefetch.arbitration.haltByOther setWhen(enable)
|
||||
val done = ! List(fetch, decode, execute, memory, writeBack).map(_.arbitration.isValid).orR
|
||||
decode.arbitration.haltByOther setWhen(enable) //TODO FETCH
|
||||
val done = ! List(execute, memory, writeBack).map(_.arbitration.isValid).orR
|
||||
}
|
||||
|
||||
|
||||
|
@ -388,9 +388,8 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
|
|||
val exceptionValids = Vec(Bool,stages.length)
|
||||
val exceptionValidsRegs = Vec(Reg(Bool) init(False), stages.length).allowUnsetRegToAvoidLatch
|
||||
val exceptionContext = Reg(ExceptionCause())
|
||||
val pipelineHasException = exceptionValids.orR //TODO FMAX maybe could be partialy pipelined
|
||||
|
||||
pipelineLiberator.enable setWhen(pipelineHasException)
|
||||
pipelineLiberator.enable setWhen(exceptionValidsRegs.tail.orR)
|
||||
|
||||
val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => {
|
||||
val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s).sortWith(_.priority > _.priority)
|
||||
|
@ -409,14 +408,16 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
|
|||
})
|
||||
|
||||
val sortedByStage = groupedByStage.sortWith((a, b) => pipeline.indexOf(a.stage) < pipeline.indexOf(b.stage))
|
||||
|
||||
sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat"))
|
||||
exceptionValids := exceptionValidsRegs
|
||||
for(portInfo <- sortedByStage; port = portInfo.port ; stage = portInfo.stage; stageId = indexOf(portInfo.stage)) {
|
||||
when(port.valid) {
|
||||
stages(indexOf(stage) - 1).arbitration.flushAll := True
|
||||
if(indexOf(stage) != 0) stages(indexOf(stage) - 1).arbitration.flushAll := True
|
||||
stage.arbitration.removeIt := True
|
||||
exceptionValids(stageId) := True
|
||||
exceptionContext := port.payload
|
||||
when(!exceptionValidsRegs.takeRight(stages.length-stageId-1).fold(False)(_ || _)) {
|
||||
exceptionContext := port.payload
|
||||
}
|
||||
}
|
||||
}
|
||||
for(stageId <- firstStageIndexWithExceptionPort until stages.length; stage = stages(stageId) ){
|
||||
|
@ -482,6 +483,12 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
|
|||
|
||||
//Interrupt/Exception entry logic
|
||||
pipelineLiberator.enable setWhen(interrupt)
|
||||
|
||||
if(exceptionPortCtrl != null) {
|
||||
when(exception) {
|
||||
exceptionPortCtrl.exceptionValidsRegs.foreach(_ := False)
|
||||
}
|
||||
}
|
||||
when(exception || (interrupt && pipelineLiberator.done)){
|
||||
jumpInterface.valid := True
|
||||
jumpInterface.payload := mtvec
|
||||
|
@ -490,7 +497,7 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
|
|||
mstatus.MPP := privilege
|
||||
mepc := exception mux(
|
||||
True -> writeBack.input(PC),
|
||||
False -> (writeBackWasWfi ? writeBack.input(PC) | prefetch.input(PC_CALC_WITHOUT_JUMP))
|
||||
False -> (writeBackWasWfi ? writeBack.input(PC) | decode.input(PC))
|
||||
)
|
||||
|
||||
mcause.interrupt := interrupt
|
||||
|
|
|
@ -128,6 +128,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w
|
|||
isInjectingOnDecode = Bool()
|
||||
}
|
||||
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
@ -140,7 +141,7 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w
|
|||
val haltIt = RegInit(False)
|
||||
val stepIt = RegInit(False)
|
||||
|
||||
val isPipActive = RegNext(List(fetch, decode, execute, memory, writeBack).map(_.arbitration.isValid).orR)
|
||||
val isPipActive = RegNext(List(decode, execute, memory, writeBack).map(_.arbitration.isValid).orR)
|
||||
val isPipBusy = isPipActive || RegNext(isPipActive)
|
||||
val haltedByBreak = RegInit(False)
|
||||
|
||||
|
@ -201,17 +202,17 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] w
|
|||
|
||||
|
||||
when(execute.arbitration.isFiring && execute.input(IS_EBREAK)) {
|
||||
prefetch.arbitration.haltByOther := True
|
||||
decode.arbitration.haltByOther := True
|
||||
decode.arbitration.flushAll := True
|
||||
haltIt := True
|
||||
haltedByBreak := True
|
||||
}
|
||||
|
||||
when(haltIt) {
|
||||
prefetch.arbitration.haltByOther := True
|
||||
decode.arbitration.haltByOther := True
|
||||
}
|
||||
|
||||
when(stepIt && prefetch.arbitration.isFiring) {
|
||||
when(stepIt && decode.arbitration.isFiring) {
|
||||
haltIt := True
|
||||
}
|
||||
when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) {
|
||||
|
|
|
@ -5,146 +5,149 @@ import vexriscv.ip._
|
|||
import spinal.core._
|
||||
import spinal.lib._
|
||||
|
||||
|
||||
class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] {
|
||||
import config._
|
||||
|
||||
var iBus : InstructionCacheMemBus = null
|
||||
var mmuBus : MemoryTranslatorBus = null
|
||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
var privilegeService : PrivilegeService = null
|
||||
var redoBranch : Flow[UInt] = null
|
||||
|
||||
object FLUSH_ALL extends Stageable(Bool)
|
||||
object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
||||
object IBUS_MMU_MISS extends Stageable(Bool)
|
||||
object IBUS_ILLEGAL_ACCESS extends Stageable(Bool)
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
import Riscv._
|
||||
import pipeline.config._
|
||||
|
||||
def MANAGEMENT = M"-----------------100-----0001111"
|
||||
|
||||
val decoderService = pipeline.service(classOf[DecoderService])
|
||||
decoderService.addDefault(FLUSH_ALL, False)
|
||||
decoderService.add(MANAGEMENT, List(
|
||||
FLUSH_ALL -> True
|
||||
))
|
||||
|
||||
|
||||
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
|
||||
|
||||
if(catchSomething) {
|
||||
val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||
}
|
||||
|
||||
if(pipeline.serviceExist(classOf[MemoryTranslator]))
|
||||
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.fetch, memoryTranslatorPortConfig)
|
||||
|
||||
if(pipeline.serviceExist(classOf[PrivilegeService]))
|
||||
privilegeService = pipeline.service(classOf[PrivilegeService])
|
||||
|
||||
if(pipeline.serviceExist(classOf[ReportService])){
|
||||
val report = pipeline.service(classOf[ReportService])
|
||||
report.add("iBus" -> {
|
||||
val e = new BusReport()
|
||||
val c = new CacheReport()
|
||||
e.kind = "cached"
|
||||
e.flushInstructions.add(0x400F) //invalid instruction cache
|
||||
e.flushInstructions.add(0x13)
|
||||
e.flushInstructions.add(0x13)
|
||||
e.flushInstructions.add(0x13)
|
||||
|
||||
e.info = c
|
||||
c.size = cacheSize
|
||||
c.bytePerLine = bytePerLine
|
||||
|
||||
e
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
// val debugAddressOffset = 28
|
||||
val cache = new InstructionCache(this.config)
|
||||
iBus = master(new InstructionCacheMemBus(this.config)).setName("iBus")
|
||||
iBus <> cache.io.mem
|
||||
iBus.cmd.address.allowOverride := cache.io.mem.cmd.address // - debugAddressOffset
|
||||
|
||||
//Connect prefetch cache side
|
||||
cache.io.cpu.prefetch.isValid := prefetch.arbitration.isValid
|
||||
cache.io.cpu.prefetch.pc := prefetch.output(PC)// + debugAddressOffset
|
||||
prefetch.arbitration.haltItself setWhen(cache.io.cpu.prefetch.haltIt)
|
||||
|
||||
//Connect fetch cache side
|
||||
cache.io.cpu.fetch.isValid := fetch.arbitration.isValid
|
||||
cache.io.cpu.fetch.isStuck := fetch.arbitration.isStuck
|
||||
cache.io.cpu.fetch.pc := fetch.output(PC) // + debugAddressOffset
|
||||
|
||||
if (mmuBus != null) {
|
||||
cache.io.cpu.fetch.mmuBus <> mmuBus
|
||||
} else {
|
||||
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress //- debugAddressOffset
|
||||
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
|
||||
cache.io.cpu.fetch.mmuBus.rsp.allowRead := True
|
||||
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
|
||||
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
|
||||
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
|
||||
cache.io.cpu.fetch.mmuBus.rsp.miss := False
|
||||
}
|
||||
|
||||
if(dataOnDecode){
|
||||
decode.insert(INSTRUCTION) := cache.io.cpu.decode.data
|
||||
}else{
|
||||
fetch.insert(INSTRUCTION) := cache.io.cpu.fetch.data
|
||||
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION))
|
||||
}
|
||||
decode.insert(INSTRUCTION_READY) := True
|
||||
|
||||
cache.io.cpu.decode.pc := decode.output(PC)
|
||||
|
||||
val ownDecode = pipeline.plugins.filter(_.isInstanceOf[InstructionInjector]).foldLeft(True)(_ && !_.asInstanceOf[InstructionInjector].isInjecting(decode))
|
||||
cache.io.cpu.decode.isValid := decode.arbitration.isValid && ownDecode
|
||||
cache.io.cpu.decode.isStuck := decode.arbitration.isStuck
|
||||
cache.io.cpu.decode.isUser := (if(privilegeService != null) privilegeService.isUser(decode) else False)
|
||||
// cache.io.cpu.decode.pc := decode.input(PC)
|
||||
|
||||
redoBranch.valid := decode.arbitration.isValid && ownDecode && cache.io.cpu.decode.cacheMiss && !cache.io.cpu.decode.mmuMiss && !cache.io.cpu.decode.illegalAccess
|
||||
redoBranch.payload := decode.input(PC)
|
||||
when(redoBranch.valid){
|
||||
decode.arbitration.redoIt := True
|
||||
decode.arbitration.flushAll := True
|
||||
}
|
||||
|
||||
// val redo = RegInit(False) clearWhen(decode.arbitration.isValid) setWhen(redoBranch.valid)
|
||||
// when(redoBranch.valid || redo){
|
||||
// service(classOf[InterruptionInhibitor]).inhibateInterrupts()
|
||||
// }
|
||||
|
||||
if(catchSomething){
|
||||
val accessFault = if(catchAccessFault) cache.io.cpu.decode.error else False
|
||||
val mmuMiss = if(catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False
|
||||
val illegalAccess = if(catchIllegalAccess) cache.io.cpu.decode.illegalAccess else False
|
||||
|
||||
decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess)
|
||||
decodeExceptionPort.code := mmuMiss ? U(14) | 1
|
||||
decodeExceptionPort.badAddr := decode.input(PC)
|
||||
}
|
||||
|
||||
memory plug new Area{
|
||||
import memory._
|
||||
cache.io.flush.cmd.valid := False
|
||||
when(arbitration.isValid && input(FLUSH_ALL)){
|
||||
cache.io.flush.cmd.valid := True
|
||||
decode.arbitration.flushAll := True
|
||||
|
||||
when(!cache.io.flush.cmd.ready){
|
||||
arbitration.haltItself := True
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override def build(pipeline: VexRiscv): Unit = ???
|
||||
}
|
||||
//class IBusCachedPlugin(config : InstructionCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] {
|
||||
// import config._
|
||||
//
|
||||
// var iBus : InstructionCacheMemBus = null
|
||||
// var mmuBus : MemoryTranslatorBus = null
|
||||
// var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
// var privilegeService : PrivilegeService = null
|
||||
// var redoBranch : Flow[UInt] = null
|
||||
//
|
||||
// object FLUSH_ALL extends Stageable(Bool)
|
||||
// object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
||||
// object IBUS_MMU_MISS extends Stageable(Bool)
|
||||
// object IBUS_ILLEGAL_ACCESS extends Stageable(Bool)
|
||||
// override def setup(pipeline: VexRiscv): Unit = {
|
||||
// import Riscv._
|
||||
// import pipeline.config._
|
||||
//
|
||||
// def MANAGEMENT = M"-----------------100-----0001111"
|
||||
//
|
||||
// val decoderService = pipeline.service(classOf[DecoderService])
|
||||
// decoderService.addDefault(FLUSH_ALL, False)
|
||||
// decoderService.add(MANAGEMENT, List(
|
||||
// FLUSH_ALL -> True
|
||||
// ))
|
||||
//
|
||||
//
|
||||
// redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
|
||||
//
|
||||
// if(catchSomething) {
|
||||
// val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||
// decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||
// }
|
||||
//
|
||||
// if(pipeline.serviceExist(classOf[MemoryTranslator]))
|
||||
// mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.fetch, memoryTranslatorPortConfig)
|
||||
//
|
||||
// if(pipeline.serviceExist(classOf[PrivilegeService]))
|
||||
// privilegeService = pipeline.service(classOf[PrivilegeService])
|
||||
//
|
||||
// if(pipeline.serviceExist(classOf[ReportService])){
|
||||
// val report = pipeline.service(classOf[ReportService])
|
||||
// report.add("iBus" -> {
|
||||
// val e = new BusReport()
|
||||
// val c = new CacheReport()
|
||||
// e.kind = "cached"
|
||||
// e.flushInstructions.add(0x400F) //invalid instruction cache
|
||||
// e.flushInstructions.add(0x13)
|
||||
// e.flushInstructions.add(0x13)
|
||||
// e.flushInstructions.add(0x13)
|
||||
//
|
||||
// e.info = c
|
||||
// c.size = cacheSize
|
||||
// c.bytePerLine = bytePerLine
|
||||
//
|
||||
// e
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override def build(pipeline: VexRiscv): Unit = {
|
||||
// import pipeline._
|
||||
// import pipeline.config._
|
||||
//// val debugAddressOffset = 28
|
||||
// val cache = new InstructionCache(this.config)
|
||||
// iBus = master(new InstructionCacheMemBus(this.config)).setName("iBus")
|
||||
// iBus <> cache.io.mem
|
||||
// iBus.cmd.address.allowOverride := cache.io.mem.cmd.address // - debugAddressOffset
|
||||
//
|
||||
// //Connect prefetch cache side
|
||||
// cache.io.cpu.prefetch.isValid := prefetch.arbitration.isValid
|
||||
// cache.io.cpu.prefetch.pc := prefetch.output(PC)// + debugAddressOffset
|
||||
// prefetch.arbitration.haltItself setWhen(cache.io.cpu.prefetch.haltIt)
|
||||
//
|
||||
// //Connect fetch cache side
|
||||
// cache.io.cpu.fetch.isValid := fetch.arbitration.isValid
|
||||
// cache.io.cpu.fetch.isStuck := fetch.arbitration.isStuck
|
||||
// cache.io.cpu.fetch.pc := fetch.output(PC) // + debugAddressOffset
|
||||
//
|
||||
// if (mmuBus != null) {
|
||||
// cache.io.cpu.fetch.mmuBus <> mmuBus
|
||||
// } else {
|
||||
// cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress //- debugAddressOffset
|
||||
// cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
|
||||
// cache.io.cpu.fetch.mmuBus.rsp.allowRead := True
|
||||
// cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
|
||||
// cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
|
||||
// cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
|
||||
// cache.io.cpu.fetch.mmuBus.rsp.miss := False
|
||||
// }
|
||||
//
|
||||
// if(dataOnDecode){
|
||||
// decode.insert(INSTRUCTION) := cache.io.cpu.decode.data
|
||||
// }else{
|
||||
// fetch.insert(INSTRUCTION) := cache.io.cpu.fetch.data
|
||||
// decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION))
|
||||
// }
|
||||
// decode.insert(INSTRUCTION_READY) := True
|
||||
//
|
||||
// cache.io.cpu.decode.pc := decode.output(PC)
|
||||
//
|
||||
// val ownDecode = pipeline.plugins.filter(_.isInstanceOf[InstructionInjector]).foldLeft(True)(_ && !_.asInstanceOf[InstructionInjector].isInjecting(decode))
|
||||
// cache.io.cpu.decode.isValid := decode.arbitration.isValid && ownDecode
|
||||
// cache.io.cpu.decode.isStuck := decode.arbitration.isStuck
|
||||
// cache.io.cpu.decode.isUser := (if(privilegeService != null) privilegeService.isUser(decode) else False)
|
||||
//// cache.io.cpu.decode.pc := decode.input(PC)
|
||||
//
|
||||
// redoBranch.valid := decode.arbitration.isValid && ownDecode && cache.io.cpu.decode.cacheMiss && !cache.io.cpu.decode.mmuMiss && !cache.io.cpu.decode.illegalAccess
|
||||
// redoBranch.payload := decode.input(PC)
|
||||
// when(redoBranch.valid){
|
||||
// decode.arbitration.redoIt := True
|
||||
// decode.arbitration.flushAll := True
|
||||
// }
|
||||
//
|
||||
//// val redo = RegInit(False) clearWhen(decode.arbitration.isValid) setWhen(redoBranch.valid)
|
||||
//// when(redoBranch.valid || redo){
|
||||
//// service(classOf[InterruptionInhibitor]).inhibateInterrupts()
|
||||
//// }
|
||||
//
|
||||
// if(catchSomething){
|
||||
// val accessFault = if(catchAccessFault) cache.io.cpu.decode.error else False
|
||||
// val mmuMiss = if(catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False
|
||||
// val illegalAccess = if(catchIllegalAccess) cache.io.cpu.decode.illegalAccess else False
|
||||
//
|
||||
// decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess)
|
||||
// decodeExceptionPort.code := mmuMiss ? U(14) | 1
|
||||
// decodeExceptionPort.badAddr := decode.input(PC)
|
||||
// }
|
||||
//
|
||||
// memory plug new Area{
|
||||
// import memory._
|
||||
// cache.io.flush.cmd.valid := False
|
||||
// when(arbitration.isValid && input(FLUSH_ALL)){
|
||||
// cache.io.flush.cmd.valid := True
|
||||
// decode.arbitration.flushAll := True
|
||||
//
|
||||
// when(!cache.io.flush.cmd.ready){
|
||||
// arbitration.haltItself := True
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package vexriscv.plugin
|
||||
|
||||
import vexriscv.{Stageable, ExceptionService, ExceptionCause, VexRiscv}
|
||||
import vexriscv._
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import spinal.lib.bus.amba4.axi._
|
||||
import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
|
||||
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
|
||||
case class IBusSimpleCmd() extends Bundle{
|
||||
|
@ -12,15 +14,66 @@ case class IBusSimpleCmd() extends Bundle{
|
|||
}
|
||||
|
||||
case class IBusSimpleRsp() extends Bundle with IMasterSlave{
|
||||
val ready = Bool
|
||||
val error = Bool
|
||||
val inst = Bits(32 bits)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(ready,error,inst)
|
||||
out(error,inst)
|
||||
}
|
||||
}
|
||||
|
||||
object StreamVexPimper{
|
||||
implicit class StreamFlushPimper[T <: Data](pimped : Stream[T]){
|
||||
def m2sPipe(flush : Bool, collapsBubble : Boolean = true): Stream[T] = {
|
||||
val ret = cloneOf(pimped)
|
||||
|
||||
val rValid = RegInit(False)
|
||||
val rData = Reg(pimped.dataType)
|
||||
|
||||
pimped.ready := (Bool(collapsBubble) && !ret.valid) || ret.ready
|
||||
|
||||
when(pimped.ready) {
|
||||
rValid := pimped.valid
|
||||
rData := pimped.payload
|
||||
}
|
||||
|
||||
ret.valid := rValid
|
||||
ret.payload := rData
|
||||
|
||||
rValid.clearWhen(flush)
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
def s2mPipe(flush : Bool): Stream[T] = {
|
||||
val ret = cloneOf(pimped)
|
||||
|
||||
val rValid = RegInit(False)
|
||||
val rBits = Reg(pimped.dataType)
|
||||
|
||||
ret.valid := pimped.valid || rValid
|
||||
pimped.ready := !rValid
|
||||
ret.payload := Mux(rValid, rBits, pimped.payload)
|
||||
|
||||
when(ret.ready) {
|
||||
rValid := False
|
||||
}
|
||||
|
||||
when(pimped.ready && (!ret.ready)) {
|
||||
rValid := pimped.valid
|
||||
rBits := pimped.payload
|
||||
}
|
||||
|
||||
rValid.clearWhen(flush)
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
import StreamVexPimper._
|
||||
|
||||
object IBusSimpleBus{
|
||||
def getAxi4Config() = Axi4Config(
|
||||
addressWidth = 32,
|
||||
|
@ -40,12 +93,12 @@ object IBusSimpleBus{
|
|||
dataWidth = 32
|
||||
).getReadOnlyConfig.copy(
|
||||
useResponse = true,
|
||||
maximumPendingReadTransactions = 1
|
||||
maximumPendingReadTransactions = 8
|
||||
)
|
||||
}
|
||||
case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMasterSlave{
|
||||
var cmd = Stream(IBusSimpleCmd())
|
||||
var rsp = IBusSimpleRsp()
|
||||
var rsp = Flow(IBusSimpleRsp())
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
|
@ -64,7 +117,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
|
|||
cmd.ready := axi.ar.ready
|
||||
|
||||
|
||||
rsp.ready := axi.r.valid
|
||||
rsp.valid := axi.r.valid
|
||||
rsp.inst := axi.r.data
|
||||
rsp.error := !axi.r.isOKAY()
|
||||
axi.r.ready := True
|
||||
|
@ -87,7 +140,7 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
|
|||
mm.address := (cmd.pc >> 2) @@ U"00"
|
||||
cmd.ready := mm.waitRequestn
|
||||
|
||||
rsp.ready := mm.readDataValid
|
||||
rsp.valid := mm.readDataValid
|
||||
rsp.inst := mm.readData
|
||||
rsp.error := mm.response =/= AvalonMM.Response.OKAY
|
||||
|
||||
|
@ -95,66 +148,196 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
|
|||
}
|
||||
}
|
||||
|
||||
class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{
|
||||
class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean, pendingMax : Int = 7) extends Plugin[VexRiscv] with JumpService{
|
||||
var iBus : IBusSimpleBus = null
|
||||
var prefetchExceptionPort : Flow[ExceptionCause] = null
|
||||
def resetVector = BigInt(0x80000000l)
|
||||
def keepPcPlus4 = false
|
||||
|
||||
case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
|
||||
val jumpInfos = ArrayBuffer[JumpInfo]()
|
||||
override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
|
||||
val interface = Flow(UInt(32 bits))
|
||||
jumpInfos += JumpInfo(interface,stage, priority)
|
||||
interface
|
||||
}
|
||||
|
||||
|
||||
object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
iBus = master(IBusSimpleBus(interfaceKeepData)).setName("iBus")
|
||||
if(catchAccessFault) {
|
||||
val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1).setName("iBusErrorExceptionnPort")
|
||||
}
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
iBus = master(IBusSimpleBus(interfaceKeepData)).setName("iBus")
|
||||
prefetch plug new Area {
|
||||
val pendingCmd = RegInit(False) clearWhen (iBus.rsp.ready) setWhen (iBus.cmd.fire)
|
||||
|
||||
//Emit iBus.cmd request
|
||||
iBus.cmd.valid := prefetch.arbitration.isValid && !prefetch.arbitration.removeIt && !prefetch.arbitration.isStuckByOthers && !(pendingCmd && !iBus.rsp.ready) //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
||||
iBus.cmd.pc := prefetch.output(PC)
|
||||
prefetch.arbitration.haltItself setWhen (!iBus.cmd.ready || (pendingCmd && !iBus.rsp.ready))
|
||||
}
|
||||
pipeline plug new Area {
|
||||
val pcCalc = new Area {
|
||||
val output = Stream(UInt(32 bits))
|
||||
|
||||
//Bus rsp buffer
|
||||
val rspBuffer = if(!interfaceKeepData) new Area{
|
||||
val valid = RegInit(False) setWhen(iBus.rsp.ready) clearWhen(!fetch.arbitration.isStuck)
|
||||
val error = Reg(Bool)
|
||||
val data = Reg(Bits(32 bits))
|
||||
when(!valid) {
|
||||
data := iBus.rsp.inst
|
||||
error := iBus.rsp.error
|
||||
//PC calculation without Jump
|
||||
val pcReg = Reg(UInt(32 bits)) init (resetVector) addAttribute (Verilator.public)
|
||||
val pcPlus4 = pcReg + 4
|
||||
if (keepPcPlus4) KeepAttribute(pcPlus4)
|
||||
when(output.fire) {
|
||||
pcReg := pcPlus4
|
||||
}
|
||||
|
||||
//JumpService hardware implementation
|
||||
val jump = new Area {
|
||||
val sortedByStage = jumpInfos.sortWith((a, b) => {
|
||||
(pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
|
||||
(pipeline.indexOf(a.stage) == pipeline.indexOf(b.stage) && a.priority > b.priority)
|
||||
})
|
||||
val valids = sortedByStage.map(_.interface.valid)
|
||||
val pcs = sortedByStage.map(_.interface.payload)
|
||||
|
||||
val pcLoad = Flow(UInt(32 bits))
|
||||
pcLoad.valid := jumpInfos.map(_.interface.valid).orR
|
||||
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
|
||||
|
||||
//application of the selected jump request
|
||||
when(pcLoad.valid) {
|
||||
pcReg := pcLoad.payload
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
output.valid := (RegNext(True) init (False)) // && !jump.pcLoad.valid
|
||||
output.payload := pcReg
|
||||
}
|
||||
} else null
|
||||
|
||||
//Insert iBus.rsp into INSTRUCTION
|
||||
fetch.insert(INSTRUCTION) := iBus.rsp.inst
|
||||
fetch.insert(IBUS_ACCESS_ERROR) := iBus.rsp.error
|
||||
if(!interfaceKeepData) {
|
||||
when(rspBuffer.valid) {
|
||||
fetch.insert(INSTRUCTION) := rspBuffer.data
|
||||
fetch.insert(IBUS_ACCESS_ERROR) := rspBuffer.error
|
||||
def flush = pcCalc.jump.pcLoad.valid
|
||||
|
||||
|
||||
val iBusCmd = new Area {
|
||||
def input = pcCalc.output
|
||||
|
||||
val output = input.continueWhen(iBus.cmd.fire)
|
||||
|
||||
//Avoid sending to many iBus cmd
|
||||
val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||
val pendingCmdNext = pendingCmd + iBus.cmd.fire.asUInt - iBus.rsp.fire.asUInt
|
||||
pendingCmd := pendingCmdNext
|
||||
|
||||
iBus.cmd.valid := input.valid && output.ready && pendingCmd =/= pendingMax
|
||||
iBus.cmd.pc := input.payload
|
||||
}
|
||||
}
|
||||
|
||||
fetch.insert(IBUS_ACCESS_ERROR) clearWhen(!fetch.arbitration.isValid) //Avoid interference with instruction injection from the debug plugin
|
||||
val iBusRsp = new Area {
|
||||
val input = iBusCmd.output.m2sPipe(flush)// ASYNC .throwWhen(flush)
|
||||
|
||||
if(interfaceKeepData)
|
||||
fetch.arbitration.haltItself setWhen(fetch.arbitration.isValid && !iBus.rsp.ready)
|
||||
else
|
||||
fetch.arbitration.haltItself setWhen(fetch.arbitration.isValid && !iBus.rsp.ready && !rspBuffer.valid)
|
||||
//Manage flush for iBus transactions in flight
|
||||
val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0)
|
||||
discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt
|
||||
when(flush) {
|
||||
discardCounter := iBusCmd.pendingCmdNext
|
||||
}
|
||||
|
||||
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION))
|
||||
decode.insert(INSTRUCTION_READY) := True
|
||||
val rsp = iBus.rsp.throwWhen(discardCounter =/= 0).toStream.s2mPipe(flush)
|
||||
|
||||
if(catchAccessFault){
|
||||
decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
|
||||
decodeExceptionPort.code := 1
|
||||
decodeExceptionPort.badAddr := decode.input(PC)
|
||||
case class FetchRsp() extends Bundle {
|
||||
val pc = UInt(32 bits)
|
||||
val rsp = IBusSimpleRsp()
|
||||
}
|
||||
|
||||
val fetchRsp = FetchRsp()
|
||||
fetchRsp.pc := input.payload
|
||||
fetchRsp.rsp := rsp.payload
|
||||
fetchRsp.rsp.error.clearWhen(!rsp.valid) //Avoid interference with instruction injection from the debug plugin
|
||||
|
||||
|
||||
val output = StreamJoin(Seq(input, rsp), fetchRsp)
|
||||
|
||||
}
|
||||
|
||||
|
||||
val injector = new Area {
|
||||
val input = iBusRsp.output.s2mPipe(flush)
|
||||
val stage = input.m2sPipe(flush, false)
|
||||
stage.ready := !decode.arbitration.isStuck
|
||||
decode.arbitration.isValid.setAsComb().removeAssignments()
|
||||
decode.arbitration.isValid := stage.valid
|
||||
decode.insert(PC) := stage.pc
|
||||
decode.insert(INSTRUCTION) := stage.rsp.inst
|
||||
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), input.rsp.inst)
|
||||
decode.insert(INSTRUCTION_READY) := True
|
||||
|
||||
if(catchAccessFault){
|
||||
decodeExceptionPort.valid := decode.arbitration.isValid && stage.rsp.error
|
||||
decodeExceptionPort.code := 1
|
||||
decodeExceptionPort.badAddr := decode.input(PC)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{
|
||||
// var iBus : IBusSimpleBus = null
|
||||
//
|
||||
// object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
||||
// var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
// override def setup(pipeline: VexRiscv): Unit = {
|
||||
// if(catchAccessFault) {
|
||||
// val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||
// decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override def build(pipeline: VexRiscv): Unit = {
|
||||
// import pipeline._
|
||||
// import pipeline.config._
|
||||
// iBus = master(IBusSimpleBus(interfaceKeepData)).setName("iBus")
|
||||
// prefetch plug new Area {
|
||||
// val pendingCmd = RegInit(False) clearWhen (iBus.rsp.ready) setWhen (iBus.cmd.fire)
|
||||
//
|
||||
// //Emit iBus.cmd request
|
||||
// iBus.cmd.valid := prefetch.arbitration.isValid && !prefetch.arbitration.removeIt && !prefetch.arbitration.isStuckByOthers && !(pendingCmd && !iBus.rsp.ready) //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
||||
// iBus.cmd.pc := prefetch.output(PC)
|
||||
// prefetch.arbitration.haltItself setWhen (!iBus.cmd.ready || (pendingCmd && !iBus.rsp.ready))
|
||||
// }
|
||||
//
|
||||
// //Bus rsp buffer
|
||||
// val rspBuffer = if(!interfaceKeepData) new Area{
|
||||
// val valid = RegInit(False) setWhen(iBus.rsp.ready) clearWhen(!fetch.arbitration.isStuck)
|
||||
// val error = Reg(Bool)
|
||||
// val data = Reg(Bits(32 bits))
|
||||
// when(!valid) {
|
||||
// data := iBus.rsp.inst
|
||||
// error := iBus.rsp.error
|
||||
// }
|
||||
// } else null
|
||||
//
|
||||
// //Insert iBus.rsp into INSTRUCTION
|
||||
// fetch.insert(INSTRUCTION) := iBus.rsp.inst
|
||||
// fetch.insert(IBUS_ACCESS_ERROR) := iBus.rsp.error
|
||||
// if(!interfaceKeepData) {
|
||||
// when(rspBuffer.valid) {
|
||||
// fetch.insert(INSTRUCTION) := rspBuffer.data
|
||||
// fetch.insert(IBUS_ACCESS_ERROR) := rspBuffer.error
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fetch.insert(IBUS_ACCESS_ERROR) clearWhen(!fetch.arbitration.isValid) //Avoid interference with instruction injection from the debug plugin
|
||||
//
|
||||
// if(interfaceKeepData)
|
||||
// fetch.arbitration.haltItself setWhen(fetch.arbitration.isValid && !iBus.rsp.ready)
|
||||
// else
|
||||
// fetch.arbitration.haltItself setWhen(fetch.arbitration.isValid && !iBus.rsp.ready && !rspBuffer.valid)
|
||||
//
|
||||
// decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION))
|
||||
// decode.insert(INSTRUCTION_READY) := True
|
||||
//
|
||||
// if(catchAccessFault){
|
||||
// decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
|
||||
// decodeExceptionPort.code := 1
|
||||
// decodeExceptionPort.badAddr := decode.input(PC)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -20,130 +20,139 @@ object KeepAttribute{
|
|||
|
||||
def apply[T <: Data](that : T) = that.addAttribute(keep).addAttribute(syn_keep_verilog).addAttribute(syn_keep_vhdl)
|
||||
}
|
||||
|
||||
|
||||
class PcManagerSimplePlugin(resetVector : BigInt,
|
||||
relaxedPcCalculation : Boolean = false,
|
||||
keepPcPlus4 : Boolean = true) extends Plugin[VexRiscv] with JumpService{
|
||||
//FetchService interface
|
||||
case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
|
||||
val jumpInfos = ArrayBuffer[JumpInfo]()
|
||||
override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
|
||||
val interface = Flow(UInt(32 bits))
|
||||
jumpInfos += JumpInfo(interface,stage, priority)
|
||||
interface
|
||||
}
|
||||
var prefetchExceptionPort : Flow[ExceptionCause] = null
|
||||
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
if(!relaxedPcCalculation) pipeline.unremovableStages += pipeline.prefetch
|
||||
}
|
||||
keepPcPlus4 : Boolean = true) extends Plugin[VexRiscv]{
|
||||
override def build(pipeline: VexRiscv): Unit = ???
|
||||
}
|
||||
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline.config._
|
||||
import pipeline._
|
||||
|
||||
if(relaxedPcCalculation)
|
||||
relaxedImpl(pipeline)
|
||||
else
|
||||
cycleEffectiveImpl(pipeline)
|
||||
|
||||
//Formal verification signals generation
|
||||
prefetch.insert(FORMAL_PC_NEXT) := prefetch.input(PC) + 4
|
||||
jumpInfos.foreach(info => {
|
||||
when(info.interface.valid){
|
||||
info.stage.output(FORMAL_PC_NEXT) := info.interface.payload
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//reduce combinatorial path, and expose the PC to the pipeline as a register
|
||||
def relaxedImpl(pipeline: VexRiscv): Unit = {
|
||||
import pipeline.config._
|
||||
import pipeline._
|
||||
|
||||
prefetch plug new Area {
|
||||
import prefetch._
|
||||
//Stage always valid
|
||||
arbitration.isValid := True
|
||||
|
||||
//PC calculation without Jump
|
||||
val pcReg = Reg(UInt(32 bits)) init(resetVector) addAttribute(Verilator.public)
|
||||
val pcPlus4 = pcReg + 4
|
||||
if(keepPcPlus4) KeepAttribute(pcPlus4)
|
||||
when(arbitration.isFiring){
|
||||
pcReg := pcPlus4
|
||||
}
|
||||
|
||||
//JumpService hardware implementation
|
||||
val jump = if(jumpInfos.length != 0) new Area {
|
||||
val sortedByStage = jumpInfos.sortWith((a, b) => {
|
||||
(pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
|
||||
(pipeline.indexOf(a.stage) == pipeline.indexOf(b.stage) && a.priority > b.priority)
|
||||
})
|
||||
val valids = sortedByStage.map(_.interface.valid)
|
||||
val pcs = sortedByStage.map(_.interface.payload)
|
||||
|
||||
val pcLoad = Flow(UInt(32 bits))
|
||||
pcLoad.valid := jumpInfos.map(_.interface.valid).orR
|
||||
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
|
||||
|
||||
//application of the selected jump request
|
||||
when(pcLoad.valid) {
|
||||
pcReg := pcLoad.payload
|
||||
}
|
||||
}
|
||||
|
||||
insert(PC_CALC_WITHOUT_JUMP) := pcReg
|
||||
insert(PC) := pcReg
|
||||
}
|
||||
}
|
||||
|
||||
//Jump take effect instantly (save one cycle), but expose the PC to the pipeline as a 'long' combinatorial path
|
||||
def cycleEffectiveImpl(pipeline: VexRiscv): Unit = {
|
||||
import pipeline.config._
|
||||
import pipeline.prefetch
|
||||
|
||||
prefetch plug new Area {
|
||||
import prefetch._
|
||||
//Stage always valid
|
||||
arbitration.isValid := True
|
||||
|
||||
//PC calculation without Jump
|
||||
val pcReg = Reg(UInt(32 bits)) init(resetVector) addAttribute(Verilator.public)
|
||||
val inc = RegInit(False)
|
||||
val pcBeforeJumps = pcReg + (inc ## B"00").asUInt
|
||||
insert(PC_CALC_WITHOUT_JUMP) := pcBeforeJumps
|
||||
val pc = UInt(32 bits)
|
||||
pc := input(PC_CALC_WITHOUT_JUMP)
|
||||
|
||||
val samplePcNext = False
|
||||
|
||||
//JumpService hardware implementation
|
||||
val jump = if(jumpInfos.length != 0) new Area {
|
||||
val sortedByStage = jumpInfos.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage))
|
||||
val valids = sortedByStage.map(_.interface.valid)
|
||||
val pcs = sortedByStage.map(_.interface.payload)
|
||||
|
||||
val pcLoad = Flow(UInt(32 bits))
|
||||
pcLoad.valid := jumpInfos.map(_.interface.valid).orR
|
||||
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
|
||||
|
||||
//application of the selected jump request
|
||||
when(pcLoad.valid) {
|
||||
inc := False
|
||||
samplePcNext := True
|
||||
pc := pcLoad.payload
|
||||
}
|
||||
}
|
||||
|
||||
when(arbitration.isFiring){
|
||||
inc := True
|
||||
samplePcNext := True
|
||||
}
|
||||
|
||||
when(samplePcNext) { pcReg := pc }
|
||||
|
||||
insert(PC) := pc
|
||||
}
|
||||
}
|
||||
}
|
||||
//class PcManagerSimplePlugin(resetVector : BigInt,
|
||||
// relaxedPcCalculation : Boolean = false,
|
||||
// keepPcPlus4 : Boolean = true) extends Plugin[VexRiscv] with JumpService{
|
||||
// //FetchService interface
|
||||
// case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
|
||||
// val jumpInfos = ArrayBuffer[JumpInfo]()
|
||||
// override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
|
||||
// val interface = Flow(UInt(32 bits))
|
||||
// jumpInfos += JumpInfo(interface,stage, priority)
|
||||
// interface
|
||||
// }
|
||||
// var prefetchExceptionPort : Flow[ExceptionCause] = null
|
||||
//
|
||||
// override def setup(pipeline: VexRiscv): Unit = {
|
||||
// if(!relaxedPcCalculation) pipeline.unremovableStages += pipeline.prefetch
|
||||
// }
|
||||
//
|
||||
//
|
||||
// override def build(pipeline: VexRiscv): Unit = {
|
||||
// import pipeline.config._
|
||||
// import pipeline._
|
||||
//
|
||||
// if(relaxedPcCalculation)
|
||||
// relaxedImpl(pipeline)
|
||||
// else
|
||||
// cycleEffectiveImpl(pipeline)
|
||||
//
|
||||
// //Formal verification signals generation
|
||||
// prefetch.insert(FORMAL_PC_NEXT) := prefetch.input(PC) + 4
|
||||
// jumpInfos.foreach(info => {
|
||||
// when(info.interface.valid){
|
||||
// info.stage.output(FORMAL_PC_NEXT) := info.interface.payload
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// //reduce combinatorial path, and expose the PC to the pipeline as a register
|
||||
// def relaxedImpl(pipeline: VexRiscv): Unit = {
|
||||
// import pipeline.config._
|
||||
// import pipeline._
|
||||
//
|
||||
// prefetch plug new Area {
|
||||
// import prefetch._
|
||||
// //Stage always valid
|
||||
// arbitration.isValid := True
|
||||
//
|
||||
// //PC calculation without Jump
|
||||
// val pcReg = Reg(UInt(32 bits)) init(resetVector) addAttribute(Verilator.public)
|
||||
// val pcPlus4 = pcReg + 4
|
||||
// if(keepPcPlus4) KeepAttribute(pcPlus4)
|
||||
// when(arbitration.isFiring){
|
||||
// pcReg := pcPlus4
|
||||
// }
|
||||
//
|
||||
// //JumpService hardware implementation
|
||||
// val jump = if(jumpInfos.length != 0) new Area {
|
||||
// val sortedByStage = jumpInfos.sortWith((a, b) => {
|
||||
// (pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage)) ||
|
||||
// (pipeline.indexOf(a.stage) == pipeline.indexOf(b.stage) && a.priority > b.priority)
|
||||
// })
|
||||
// val valids = sortedByStage.map(_.interface.valid)
|
||||
// val pcs = sortedByStage.map(_.interface.payload)
|
||||
//
|
||||
// val pcLoad = Flow(UInt(32 bits))
|
||||
// pcLoad.valid := jumpInfos.map(_.interface.valid).orR
|
||||
// pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
|
||||
//
|
||||
// //application of the selected jump request
|
||||
// when(pcLoad.valid) {
|
||||
// pcReg := pcLoad.payload
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// insert(PC_CALC_WITHOUT_JUMP) := pcReg
|
||||
// insert(PC) := pcReg
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //Jump take effect instantly (save one cycle), but expose the PC to the pipeline as a 'long' combinatorial path
|
||||
// def cycleEffectiveImpl(pipeline: VexRiscv): Unit = {
|
||||
// import pipeline.config._
|
||||
// import pipeline.prefetch
|
||||
//
|
||||
// prefetch plug new Area {
|
||||
// import prefetch._
|
||||
// //Stage always valid
|
||||
// arbitration.isValid := True
|
||||
//
|
||||
// //PC calculation without Jump
|
||||
// val pcReg = Reg(UInt(32 bits)) init(resetVector) addAttribute(Verilator.public)
|
||||
// val inc = RegInit(False)
|
||||
// val pcBeforeJumps = pcReg + (inc ## B"00").asUInt
|
||||
// insert(PC_CALC_WITHOUT_JUMP) := pcBeforeJumps
|
||||
// val pc = UInt(32 bits)
|
||||
// pc := input(PC_CALC_WITHOUT_JUMP)
|
||||
//
|
||||
// val samplePcNext = False
|
||||
//
|
||||
// //JumpService hardware implementation
|
||||
// val jump = if(jumpInfos.length != 0) new Area {
|
||||
// val sortedByStage = jumpInfos.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage))
|
||||
// val valids = sortedByStage.map(_.interface.valid)
|
||||
// val pcs = sortedByStage.map(_.interface.payload)
|
||||
//
|
||||
// val pcLoad = Flow(UInt(32 bits))
|
||||
// pcLoad.valid := jumpInfos.map(_.interface.valid).orR
|
||||
// pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
|
||||
//
|
||||
// //application of the selected jump request
|
||||
// when(pcLoad.valid) {
|
||||
// inc := False
|
||||
// samplePcNext := True
|
||||
// pc := pcLoad.payload
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// when(arbitration.isFiring){
|
||||
// inc := True
|
||||
// samplePcNext := True
|
||||
// }
|
||||
//
|
||||
// when(samplePcNext) { pcReg := pc }
|
||||
//
|
||||
// insert(PC) := pc
|
||||
// }
|
||||
// }
|
||||
//}
|
|
@ -10,6 +10,6 @@ class SingleInstructionLimiterPlugin() extends Plugin[VexRiscv] {
|
|||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
prefetch.arbitration.haltByOther.setWhen(List(fetch,decode,execute,memory,writeBack).map(_.arbitration.isValid).orR)
|
||||
decode.arbitration.haltByOther.setWhen(List(decode,execute,memory,writeBack).map(_.arbitration.isValid).orR)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -386,7 +386,7 @@ public:
|
|||
#ifdef REF
|
||||
if(bootPc != -1) top->VexRiscv->core->prefetch_pc = bootPc;
|
||||
#else
|
||||
if(bootPc != -1) top->VexRiscv->prefetch_PcManagerSimplePlugin_pcReg = bootPc;
|
||||
if(bootPc != -1) top->VexRiscv->IBusSimplePlugin_pcCalc_pcReg = bootPc;
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -511,7 +511,7 @@ public:
|
|||
|
||||
virtual void onReset(){
|
||||
top->iBus_cmd_ready = 1;
|
||||
top->iBus_rsp_ready = 1;
|
||||
top->iBus_rsp_valid = 0;
|
||||
}
|
||||
|
||||
virtual void preCycle(){
|
||||
|
@ -523,12 +523,12 @@ public:
|
|||
}
|
||||
//TODO doesn't catch when instruction removed ?
|
||||
virtual void postCycle(){
|
||||
top->iBus_rsp_ready = !pending;
|
||||
top->iBus_rsp_valid = 0;
|
||||
if(pending && (!ws->iStall || VL_RANDOM_I(7) < 100)){
|
||||
top->iBus_rsp_inst = inst_next;
|
||||
top->iBus_rsp_payload_inst = inst_next;
|
||||
pending = false;
|
||||
top->iBus_rsp_ready = 1;
|
||||
top->iBus_rsp_error = error_next;
|
||||
top->iBus_rsp_valid = 1;
|
||||
top->iBus_rsp_payload_error = error_next;
|
||||
}
|
||||
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && !pending;
|
||||
}
|
||||
|
@ -1426,8 +1426,9 @@ public:
|
|||
|
||||
uint32_t readCmd(uint32_t size, uint32_t address){
|
||||
accessCmd(false, 2, address, VL_RANDOM_I(32));
|
||||
if(recv(clientSocket, buffer, 4, 0) != 4){
|
||||
printf("Should read 4 bytes");
|
||||
int error;
|
||||
if((error = recv(clientSocket, buffer, 4, 0)) != 4){
|
||||
printf("Should read 4 bytes, had %d", error);
|
||||
fail();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,117 +1,117 @@
|
|||
package vexriscv
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib.master
|
||||
import vexriscv.ip.InstructionCacheConfig
|
||||
import vexriscv.plugin._
|
||||
|
||||
object PlayGen extends App{
|
||||
def cpu() = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new IBusCachedPlugin(
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 16,
|
||||
bytePerLine = 4,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchIllegalAccess = false,
|
||||
catchAccessFault = false,
|
||||
catchMemoryTranslationMiss = false,
|
||||
asyncTagMemory = false,
|
||||
twoCycleRam = false,
|
||||
preResetFlush = false
|
||||
)
|
||||
),
|
||||
new FormalPlugin,
|
||||
new HaltOnExceptionPlugin,
|
||||
new PcManagerSimplePlugin(
|
||||
resetVector = 0x00000000l,
|
||||
relaxedPcCalculation = false
|
||||
),
|
||||
// new IBusSimplePlugin(
|
||||
// interfaceKeepData = false,
|
||||
//package vexriscv
|
||||
//
|
||||
//import spinal.core._
|
||||
//import spinal.lib.master
|
||||
//import vexriscv.ip.InstructionCacheConfig
|
||||
//import vexriscv.plugin._
|
||||
//
|
||||
//object PlayGen extends App{
|
||||
// def cpu() = new VexRiscv(
|
||||
// config = VexRiscvConfig(
|
||||
// plugins = List(
|
||||
// new IBusCachedPlugin(
|
||||
// config = InstructionCacheConfig(
|
||||
// cacheSize = 16,
|
||||
// bytePerLine = 4,
|
||||
// wayCount = 1,
|
||||
// addressWidth = 32,
|
||||
// cpuDataWidth = 32,
|
||||
// memDataWidth = 32,
|
||||
// catchIllegalAccess = false,
|
||||
// catchAccessFault = false,
|
||||
// catchMemoryTranslationMiss = false,
|
||||
// asyncTagMemory = false,
|
||||
// twoCycleRam = false,
|
||||
// preResetFlush = false
|
||||
// )
|
||||
// ),
|
||||
// new FormalPlugin,
|
||||
// new HaltOnExceptionPlugin,
|
||||
// new PcManagerSimplePlugin(
|
||||
// resetVector = 0x00000000l,
|
||||
// relaxedPcCalculation = false
|
||||
// ),
|
||||
//// new IBusSimplePlugin(
|
||||
//// interfaceKeepData = false,
|
||||
//// catchAccessFault = false
|
||||
//// ),
|
||||
// new DBusSimplePlugin(
|
||||
// catchAddressMisaligned = true,
|
||||
// catchAccessFault = false
|
||||
// ),
|
||||
new DBusSimplePlugin(
|
||||
catchAddressMisaligned = true,
|
||||
catchAccessFault = false
|
||||
),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = true,
|
||||
forceLegalInstructionComputation = true
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
zeroBoot = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false,
|
||||
executeInsertion = false
|
||||
),
|
||||
new FullBarrielShifterPlugin,
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = false,
|
||||
bypassMemory = false,
|
||||
bypassWriteBack = false,
|
||||
bypassWriteBackBuffer = false,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new BranchPlugin(
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = true,
|
||||
prediction = NONE
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
)
|
||||
)
|
||||
// Wrap with input/output registers
|
||||
def wrap(that : => VexRiscv) : Component = {
|
||||
val c = that
|
||||
// c.rework {
|
||||
// for (e <- c.getOrdredNodeIo) {
|
||||
// if (e.isInput) {
|
||||
// e.asDirectionLess()
|
||||
// e := RegNext(RegNext(in(cloneOf(e))))
|
||||
// new DecoderSimplePlugin(
|
||||
// catchIllegalInstruction = true,
|
||||
// forceLegalInstructionComputation = true
|
||||
// ),
|
||||
// new RegFilePlugin(
|
||||
// regFileReadyKind = plugin.SYNC,
|
||||
// zeroBoot = false
|
||||
// ),
|
||||
// new IntAluPlugin,
|
||||
// new SrcPlugin(
|
||||
// separatedAddSub = false,
|
||||
// executeInsertion = false
|
||||
// ),
|
||||
// new FullBarrielShifterPlugin,
|
||||
// new HazardSimplePlugin(
|
||||
// bypassExecute = false,
|
||||
// bypassMemory = false,
|
||||
// bypassWriteBack = false,
|
||||
// bypassWriteBackBuffer = false,
|
||||
// pessimisticUseSrc = false,
|
||||
// pessimisticWriteRegFile = false,
|
||||
// pessimisticAddressMatch = false
|
||||
// ),
|
||||
// new BranchPlugin(
|
||||
// earlyBranch = false,
|
||||
// catchAddressMisaligned = true,
|
||||
// prediction = NONE
|
||||
// ),
|
||||
// new YamlPlugin("cpu0.yaml")
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// // Wrap with input/output registers
|
||||
// def wrap(that : => VexRiscv) : Component = {
|
||||
// val c = that
|
||||
//// c.rework {
|
||||
//// for (e <- c.getOrdredNodeIo) {
|
||||
//// if (e.isInput) {
|
||||
//// e.asDirectionLess()
|
||||
//// e := RegNext(RegNext(in(cloneOf(e))))
|
||||
////
|
||||
//// } else {
|
||||
//// e.asDirectionLess()
|
||||
//// out(cloneOf(e)) := RegNext(RegNext(e))
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//
|
||||
// } else {
|
||||
// e.asDirectionLess()
|
||||
// out(cloneOf(e)) := RegNext(RegNext(e))
|
||||
// c.rework{
|
||||
// c.config.plugins.foreach{
|
||||
// case p : IBusCachedPlugin => {
|
||||
// p.iBus.asDirectionLess().unsetName()
|
||||
// val iBusNew = master(IBusSimpleBus(false)).setName("iBus")
|
||||
//
|
||||
// iBusNew.cmd.valid := p.iBus.cmd.valid
|
||||
// iBusNew.cmd.pc := p.iBus.cmd.address
|
||||
// p.iBus.cmd.ready := iBusNew.cmd.ready
|
||||
//
|
||||
// val pending = RegInit(False) clearWhen(iBusNew.rsp.ready) setWhen (iBusNew.cmd.fire)
|
||||
// p.iBus.rsp.valid := iBusNew.rsp.ready & pending
|
||||
// p.iBus.rsp.error := iBusNew.rsp.error
|
||||
// p.iBus.rsp.data := iBusNew.rsp.inst
|
||||
// }
|
||||
// case _ =>
|
||||
// }
|
||||
// }
|
||||
|
||||
c.rework{
|
||||
c.config.plugins.foreach{
|
||||
case p : IBusCachedPlugin => {
|
||||
p.iBus.asDirectionLess().unsetName()
|
||||
val iBusNew = master(IBusSimpleBus(false)).setName("iBus")
|
||||
|
||||
iBusNew.cmd.valid := p.iBus.cmd.valid
|
||||
iBusNew.cmd.pc := p.iBus.cmd.address
|
||||
p.iBus.cmd.ready := iBusNew.cmd.ready
|
||||
|
||||
val pending = RegInit(False) clearWhen(iBusNew.rsp.ready) setWhen (iBusNew.cmd.fire)
|
||||
p.iBus.rsp.valid := iBusNew.rsp.ready & pending
|
||||
p.iBus.rsp.error := iBusNew.rsp.error
|
||||
p.iBus.rsp.data := iBusNew.rsp.inst
|
||||
}
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
c
|
||||
}
|
||||
SpinalConfig(
|
||||
defaultConfigForClockDomains = ClockDomainConfig(
|
||||
resetKind = spinal.core.SYNC,
|
||||
resetActiveLevel = spinal.core.HIGH
|
||||
),
|
||||
inlineRom = true
|
||||
).generateVerilog(wrap(cpu()))
|
||||
}
|
||||
// c
|
||||
// }
|
||||
// SpinalConfig(
|
||||
// defaultConfigForClockDomains = ClockDomainConfig(
|
||||
// resetKind = spinal.core.SYNC,
|
||||
// resetActiveLevel = spinal.core.HIGH
|
||||
// ),
|
||||
// inlineRom = true
|
||||
// ).generateVerilog(wrap(cpu()))
|
||||
//}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue