mirror of
https://github.com/SpinalHDL/VexRiscv.git
synced 2025-04-24 05:57:07 -04:00
Add Arbitration.flushIt
Add ExceptionService Add unremovableStage Add MachineCsr (untested)
This commit is contained in:
parent
c49373f3d1
commit
e9d3977737
11 changed files with 201 additions and 15 deletions
|
@ -1,7 +1,8 @@
|
|||
package SpinalRiscv
|
||||
|
||||
import SpinalRiscv.Plugin.Plugin
|
||||
import SpinalRiscv.Plugin._
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
@ -11,6 +12,7 @@ trait Pipeline {
|
|||
type T <: Pipeline
|
||||
val plugins = ArrayBuffer[Plugin[T]]()
|
||||
var stages = ArrayBuffer[Stage]()
|
||||
var unremovableStages = mutable.Set[Stage]()
|
||||
// val services = ArrayBuffer[Any]()
|
||||
|
||||
def indexOf(stage : Stage) = stages.indexOf(stage)
|
||||
|
@ -99,6 +101,14 @@ trait Pipeline {
|
|||
}
|
||||
|
||||
//Arbitration
|
||||
for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)) {
|
||||
if(!unremovableStages.contains(stage))
|
||||
stage.arbitration.removeIt setWhen stages.drop(stageIndex).map(_.arbitration.flushIt).orR
|
||||
else
|
||||
assert(stage.arbitration.removeIt === False,"removeIt should never be asserted on this stage")
|
||||
|
||||
}
|
||||
|
||||
for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
|
||||
stage.arbitration.isStuckByOthers := stages.takeRight(stages.length - stageIndex - 1).map(s => s.arbitration.haltIt && !s.arbitration.removeIt).foldLeft(False)(_ || _)
|
||||
stage.arbitration.isStuck := stage.arbitration.haltIt || stage.arbitration.isStuckByOthers
|
||||
|
|
|
@ -159,7 +159,7 @@ class BranchPlugin(earlyBranch : Boolean,prediction : BranchPrediction,historyRa
|
|||
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.removeIt := True
|
||||
fetch.arbitration.flushIt := True
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,9 +209,10 @@ class BranchPlugin(earlyBranch : Boolean,prediction : BranchPrediction,historyRa
|
|||
jumpInterface.payload := input(BRANCH_CALC)
|
||||
|
||||
when(jumpInterface.valid) {
|
||||
fetch.arbitration.removeIt := True
|
||||
decode.arbitration.removeIt := True
|
||||
if(!earlyBranch) execute.arbitration.removeIt := True
|
||||
stages(indexOf(branchStage) - 1).arbitration.flushIt := True
|
||||
// fetch.arbitration.removeIt := True
|
||||
// decode.arbitration.removeIt := True
|
||||
// if(!earlyBranch) execute.arbitration.removeIt := True
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class IBusSimplePlugin(interfaceKeepData : Boolean) extends Plugin[VexRiscv]{
|
|||
//Emit iCmd request
|
||||
require(interfaceKeepData)
|
||||
iCmd = master(Stream(IBusSimpleCmd())).setName("iCmd")
|
||||
iCmd.valid := prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
||||
iCmd.valid := prefetch.arbitration.isFiring //prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
|
||||
iCmd.pc := prefetch.output(PC)
|
||||
prefetch.arbitration.haltIt setWhen(!iCmd.ready)
|
||||
|
||||
|
|
148
src/main/scala/SpinalRiscv/Plugin/MachineCsr.scala
Normal file
148
src/main/scala/SpinalRiscv/Plugin/MachineCsr.scala
Normal file
|
@ -0,0 +1,148 @@
|
|||
package SpinalRiscv.Plugin
|
||||
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import SpinalRiscv._
|
||||
import SpinalRiscv.Riscv._
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
/**
|
||||
* Created by spinalvm on 21.03.17.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
case class ExceptionPortInfo(port : Flow[UInt],stage : Stage)
|
||||
case class MachineCsrConfig()
|
||||
|
||||
class MachineCsr extends Plugin[VexRiscv] with ExceptionService{
|
||||
val exceptionPortsInfos = ArrayBuffer[ExceptionPortInfo]()
|
||||
def exceptionCodeWidth = 4
|
||||
override def newExceptionPort(stage : Stage) = {
|
||||
val interface = Flow(UInt(exceptionCodeWidth bits))
|
||||
exceptionPortsInfos += ExceptionPortInfo(interface,stage)
|
||||
interface
|
||||
}
|
||||
|
||||
var jumpInterface : Flow[UInt] = null
|
||||
|
||||
object EnvCtrlEnum extends SpinalEnum(binarySequential){
|
||||
val NONE, EBREAK, ECALL, MRET = newElement()
|
||||
}
|
||||
|
||||
object ENV_CTRL extends Stageable(EnvCtrlEnum())
|
||||
object EXCEPTION extends Stageable(Bool)
|
||||
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
import pipeline.config._
|
||||
|
||||
val defaultEnv = List[(Stageable[_ <: BaseType],Any)](
|
||||
LEGAL_INSTRUCTION -> True
|
||||
)
|
||||
|
||||
val defaultActions = List[(Stageable[_ <: BaseType],Any)](
|
||||
LEGAL_INSTRUCTION -> True,
|
||||
REGFILE_WRITE_VALID -> True,
|
||||
BYPASSABLE_EXECUTE_STAGE -> False,
|
||||
BYPASSABLE_MEMORY_STAGE -> False
|
||||
)
|
||||
|
||||
val nonImmediatActions = defaultActions ++ List(
|
||||
SRC1_CTRL -> Src1CtrlEnum.RS
|
||||
)
|
||||
|
||||
val immediatActions = defaultActions
|
||||
|
||||
val decoderService = pipeline.service(classOf[DecoderService])
|
||||
|
||||
decoderService.addDefault(ENV_CTRL, EnvCtrlEnum.NONE)
|
||||
decoderService.add(List(
|
||||
CSRRW -> nonImmediatActions,
|
||||
CSRRS -> nonImmediatActions,
|
||||
CSRRC -> nonImmediatActions,
|
||||
CSRRWI -> immediatActions,
|
||||
CSRRSI -> immediatActions,
|
||||
CSRRCI -> immediatActions,
|
||||
ECALL -> (defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.ECALL)),
|
||||
EBREAK -> (defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.EBREAK)),
|
||||
MRET -> (defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.MRET))
|
||||
))
|
||||
|
||||
pipeline.fetch.insert(EXCEPTION) := False
|
||||
|
||||
val pcManagerService = pipeline.service(classOf[JumpService])
|
||||
jumpInterface = pcManagerService.createJumpInterface(pipeline.execute)
|
||||
jumpInterface.valid := False
|
||||
jumpInterface.payload.assignDontCare()
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
|
||||
|
||||
val mtvec = UInt(32 bits)
|
||||
val mepc = Reg(UInt(32 bits))
|
||||
|
||||
val mstatus = new Area{
|
||||
val MIE, MPIE = Reg(Bool) init(False)
|
||||
}
|
||||
|
||||
val pipelineLiberator = new Area{
|
||||
val enable = False
|
||||
decode.arbitration.haltIt setWhen(enable)
|
||||
val done = ! List(fetch, decode, execute, memory, writeBack).map(_.arbitration.isValid).orR
|
||||
}
|
||||
|
||||
val exceptionPortCtrl = new Area{
|
||||
val pipelineHasException = List(fetch, decode, execute, memory, writeBack).map(s => s.arbitration.isValid && s.input(EXCEPTION)).orR
|
||||
decode.arbitration.haltIt setWhen(pipelineHasException)
|
||||
|
||||
val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => {
|
||||
val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s)
|
||||
val stagePort = stagePortsInfos.length match{
|
||||
case 1 => stagePortsInfos.head.port
|
||||
case _ => {
|
||||
val groupedPort = Flow(UInt(exceptionCodeWidth bits))
|
||||
val valids = stagePortsInfos.map(_.port.valid)
|
||||
val codes = stagePortsInfos.map(_.port.payload)
|
||||
groupedPort.valid := valids.orR
|
||||
groupedPort.payload := MuxOH(stagePortsInfos.map(_.port.valid), codes)
|
||||
groupedPort
|
||||
}
|
||||
}
|
||||
ExceptionPortInfo(stagePort,s)
|
||||
})
|
||||
val sortedByStage = groupedByStage.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage))
|
||||
|
||||
for(portInfo <- sortedByStage; port = portInfo.port ; stage = portInfo.stage){
|
||||
when(port.valid){
|
||||
stages(indexOf(stage)).arbitration.flushIt := True
|
||||
stage.input(EXCEPTION) := True
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val interrupt = False
|
||||
val exception = writeBack.arbitration.isValid && writeBack.input(EXCEPTION)
|
||||
|
||||
when(mstatus.MIE){
|
||||
pipelineLiberator.enable := True
|
||||
when(exception || (interrupt && pipelineLiberator.done)){
|
||||
jumpInterface.valid := True
|
||||
jumpInterface.payload := mtvec
|
||||
mstatus.MIE := False
|
||||
mstatus.MPIE := mstatus.MIE
|
||||
mepc := exception ? writeBack.input(PC) | prefetch.input(PC_CALC_WITHOUT_JUMP)
|
||||
}
|
||||
}
|
||||
|
||||
when(memory.arbitration.isFiring && memory.input(ENV_CTRL) === EnvCtrlEnum.MRET){
|
||||
jumpInterface.valid := True
|
||||
jumpInterface.payload := mepc
|
||||
mstatus.MIE := mstatus.MPIE
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,10 @@ class PcManagerSimplePlugin(resetVector : BigInt,fastPcCalculation : Boolean) ex
|
|||
interface
|
||||
}
|
||||
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
pipeline.unremovableStages += pipeline.prefetch
|
||||
}
|
||||
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline.config._
|
||||
|
@ -31,7 +35,7 @@ class PcManagerSimplePlugin(resetVector : BigInt,fastPcCalculation : Boolean) ex
|
|||
//PC calculation without Jump
|
||||
val pcReg = Reg(UInt(pcWidth bits)) init(resetVector) addAttribute("verilator public")
|
||||
val inc = RegInit(False)
|
||||
val pc = if(fastPcCalculation){
|
||||
val pcBeforeJumps = if(fastPcCalculation){
|
||||
val pcPlus4 = pcReg + U(4)
|
||||
pcPlus4.addAttribute("keep")
|
||||
Mux(inc,pcPlus4,pcReg)
|
||||
|
@ -39,6 +43,10 @@ class PcManagerSimplePlugin(resetVector : BigInt,fastPcCalculation : Boolean) ex
|
|||
pcReg + Mux[UInt](inc,4,0)
|
||||
}
|
||||
|
||||
insert(PC_CALC_WITHOUT_JUMP) := pcBeforeJumps
|
||||
val pc = UInt(pcWidth bits)
|
||||
pc := input(PC_CALC_WITHOUT_JUMP)
|
||||
|
||||
val samplePcNext = False
|
||||
|
||||
//JumpService hardware implementation
|
||||
|
@ -48,8 +56,8 @@ class PcManagerSimplePlugin(resetVector : BigInt,fastPcCalculation : Boolean) ex
|
|||
val pcs = sortedByStage.map(_.interface.payload)
|
||||
|
||||
val pcLoad = Flow(UInt(pcWidth bits))
|
||||
pcLoad.valid := jumpInfos.foldLeft(False)(_ || _.interface.valid)
|
||||
pcLoad.payload := MuxOH(valids, pcs)
|
||||
pcLoad.valid := jumpInfos.map(_.interface.valid).orR
|
||||
pcLoad.payload := MuxOH(OHMasking.first(valids.asBits), pcs)
|
||||
|
||||
//application of the selected jump request
|
||||
when(pcLoad.valid) {
|
||||
|
|
|
@ -70,5 +70,16 @@ object Riscv{
|
|||
def AUIPC = M"-------------------------0010111"
|
||||
|
||||
def MULX = M"0000001----------0-------0110011"
|
||||
def DIVX = M"0000001----------1-------0110011"
|
||||
def DIVX = M"0000001----------1-------0110011"
|
||||
|
||||
def CSRRW = M"-----------------001-----1110011"
|
||||
def CSRRS = M"-----------------010-----1110011"
|
||||
def CSRRC = M"-----------------011-----1110011"
|
||||
def CSRRWI = M"-----------------101-----1110011"
|
||||
def CSRRSI = M"-----------------110-----1110011"
|
||||
def CSRRCI = M"-----------------111-----1110011"
|
||||
|
||||
def ECALL = M"00000000000000000000000001110011"
|
||||
def EBREAK = M"00000000000100000000000001110011"
|
||||
def MRET = M"00110000001000000000000001110011"
|
||||
}
|
||||
|
|
|
@ -11,4 +11,8 @@ trait DecoderService{
|
|||
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: BaseType],Any)])
|
||||
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: BaseType],Any)])])
|
||||
def addDefault(key : Stageable[_ <: BaseType], value : Any)
|
||||
}
|
||||
|
||||
trait ExceptionService{
|
||||
def newExceptionPort(stage : Stage) : Flow[UInt]
|
||||
}
|
|
@ -47,6 +47,7 @@ class Stage() extends Area{
|
|||
val arbitration = new Area{
|
||||
val haltIt = False
|
||||
val removeIt = False
|
||||
val flushIt = False
|
||||
val isValid = RegInit(False)
|
||||
val isStuck = Bool
|
||||
val isStuckByOthers = Bool
|
||||
|
|
|
@ -40,12 +40,12 @@ object TopLevel {
|
|||
new FullBarrielShifterPlugin,
|
||||
// new LightShifterPlugin,
|
||||
new DBusSimplePlugin,
|
||||
new HazardSimplePlugin(false, true, false, true),
|
||||
// new HazardSimplePlugin(true, true, true, true),
|
||||
// new HazardSimplePlugin(false, true, false, true),
|
||||
new HazardSimplePlugin(true, true, true, true),
|
||||
// new HazardSimplePlugin(false, false, false, false),
|
||||
new MulPlugin,
|
||||
new DivPlugin,
|
||||
new BranchPlugin(false, NONE)
|
||||
new BranchPlugin(false, DYNAMIC)
|
||||
)
|
||||
|
||||
val toplevel = new VexRiscv(config)
|
||||
|
|
|
@ -17,6 +17,7 @@ case class VexRiscvConfig(pcWidth : Int){
|
|||
object REG2_USE extends Stageable(Bool)
|
||||
object RESULT extends Stageable(UInt(32 bits))
|
||||
object PC extends Stageable(UInt(pcWidth bits))
|
||||
object PC_CALC_WITHOUT_JUMP extends Stageable(UInt(pcWidth bits))
|
||||
object INSTRUCTION extends Stageable(Bits(32 bits))
|
||||
object LEGAL_INSTRUCTION extends Stageable(Bool)
|
||||
object REGFILE_WRITE_VALID extends Stageable(Bool)
|
||||
|
|
|
@ -522,11 +522,13 @@ int main(int argc, char **argv, char **env) {
|
|||
}
|
||||
|
||||
uint64_t duration = timer_end(startedAt);
|
||||
cout << endl << "****************************************************************" << endl;
|
||||
cout << "Had simulate " << Workspace::cycles << " clock cycles in " << duration*1e-9 << " s (" << Workspace::cycles / (duration*1e-9) << " Khz)" << endl;
|
||||
if(successCounter == testsCounter)
|
||||
cout << "Success " << successCounter << "/" << testsCounter << endl;
|
||||
cout << "SUCCESS " << successCounter << "/" << testsCounter << endl;
|
||||
else
|
||||
cout << "Failure " << testsCounter - successCounter << "/" << testsCounter << endl;
|
||||
cout<< "FAILURE " << testsCounter - successCounter << "/" << testsCounter << endl;
|
||||
cout << "****************************************************************" << endl << endl;
|
||||
|
||||
|
||||
exit(0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue