mirror of
https://github.com/SpinalHDL/VexRiscv.git
synced 2025-04-24 22:17:05 -04:00
1038 lines
41 KiB
Scala
1038 lines
41 KiB
Scala
package vexriscv.plugin
|
|
|
|
import spinal.core._
|
|
import spinal.lib._
|
|
import vexriscv._
|
|
import vexriscv.Riscv._
|
|
import vexriscv.plugin.IntAluPlugin.{ALU_BITWISE_CTRL, ALU_CTRL, AluBitwiseCtrlEnum, AluCtrlEnum}
|
|
|
|
import scala.collection.mutable.ArrayBuffer
|
|
import scala.collection.mutable
|
|
|
|
/**
|
|
* Created by spinalvm on 21.03.17.
|
|
*/
|
|
|
|
trait CsrAccess{
|
|
def canWrite : Boolean = false
|
|
def canRead : Boolean = false
|
|
}
|
|
object CsrAccess {
|
|
object WRITE_ONLY extends CsrAccess{
|
|
override def canWrite : Boolean = true
|
|
}
|
|
object READ_ONLY extends CsrAccess{
|
|
override def canRead : Boolean = true
|
|
}
|
|
object READ_WRITE extends CsrAccess{
|
|
override def canWrite : Boolean = true
|
|
override def canRead : Boolean = true
|
|
}
|
|
object NONE extends CsrAccess
|
|
}
|
|
|
|
case class ExceptionPortInfo(port : Flow[ExceptionCause],stage : Stage, priority : Int)
|
|
case class CsrPluginConfig(
|
|
catchIllegalAccess : Boolean,
|
|
mvendorid : BigInt,
|
|
marchid : BigInt,
|
|
mimpid : BigInt,
|
|
mhartid : BigInt,
|
|
misaExtensionsInit : Int,
|
|
misaAccess : CsrAccess,
|
|
mtvecAccess : CsrAccess,
|
|
mtvecInit : BigInt,
|
|
mepcAccess : CsrAccess,
|
|
mscratchGen : Boolean,
|
|
mcauseAccess : CsrAccess,
|
|
mbadaddrAccess : CsrAccess,
|
|
mcycleAccess : CsrAccess,
|
|
minstretAccess : CsrAccess,
|
|
ucycleAccess : CsrAccess,
|
|
wfiGenAsWait : Boolean,
|
|
ecallGen : Boolean,
|
|
xtvecModeGen : Boolean = false,
|
|
noCsrAlu : Boolean = false,
|
|
wfiGenAsNop : Boolean = false,
|
|
ebreakGen : Boolean = false,
|
|
userGen : Boolean = false,
|
|
supervisorGen : Boolean = false,
|
|
sscratchGen : Boolean = false,
|
|
stvecAccess : CsrAccess = CsrAccess.NONE,
|
|
sepcAccess : CsrAccess = CsrAccess.NONE,
|
|
scauseAccess : CsrAccess = CsrAccess.NONE,
|
|
sbadaddrAccess : CsrAccess = CsrAccess.NONE,
|
|
scycleAccess : CsrAccess = CsrAccess.NONE,
|
|
sinstretAccess : CsrAccess = CsrAccess.NONE,
|
|
satpAccess : CsrAccess = CsrAccess.NONE,
|
|
medelegAccess : CsrAccess = CsrAccess.NONE,
|
|
midelegAccess : CsrAccess = CsrAccess.NONE,
|
|
pipelineCsrRead : Boolean = false,
|
|
deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes
|
|
){
|
|
assert(!ucycleAccess.canWrite)
|
|
def privilegeGen = userGen || supervisorGen
|
|
def noException = this.copy(ecallGen = false, ebreakGen = false, catchIllegalAccess = false)
|
|
}
|
|
|
|
object CsrPluginConfig{
|
|
def all : CsrPluginConfig = all(0x00000020l)
|
|
def small : CsrPluginConfig = small(0x00000020l)
|
|
def smallest : CsrPluginConfig = smallest(0x00000020l)
|
|
def linuxMinimal(mtVecInit : BigInt) = CsrPluginConfig(
|
|
catchIllegalAccess = true,
|
|
mvendorid = 1,
|
|
marchid = 2,
|
|
mimpid = 3,
|
|
mhartid = 0,
|
|
misaExtensionsInit = 0, //TODO
|
|
misaAccess = CsrAccess.NONE, //Read required by some regressions
|
|
mtvecAccess = CsrAccess.WRITE_ONLY, //Read required by some regressions
|
|
mtvecInit = mtVecInit,
|
|
mepcAccess = CsrAccess.READ_WRITE,
|
|
mscratchGen = true,
|
|
mcauseAccess = CsrAccess.READ_ONLY,
|
|
mbadaddrAccess = CsrAccess.READ_ONLY,
|
|
mcycleAccess = CsrAccess.NONE,
|
|
minstretAccess = CsrAccess.NONE,
|
|
ucycleAccess = CsrAccess.NONE,
|
|
wfiGenAsWait = true,
|
|
ecallGen = true,
|
|
xtvecModeGen = false,
|
|
noCsrAlu = false,
|
|
wfiGenAsNop = false,
|
|
ebreakGen = true,
|
|
userGen = true,
|
|
supervisorGen = true,
|
|
sscratchGen = true,
|
|
stvecAccess = CsrAccess.READ_WRITE,
|
|
sepcAccess = CsrAccess.READ_WRITE,
|
|
scauseAccess = CsrAccess.READ_WRITE,
|
|
sbadaddrAccess = CsrAccess.READ_WRITE,
|
|
scycleAccess = CsrAccess.NONE,
|
|
sinstretAccess = CsrAccess.NONE,
|
|
satpAccess = CsrAccess.NONE, //Implemented into the MMU plugin
|
|
medelegAccess = CsrAccess.WRITE_ONLY,
|
|
midelegAccess = CsrAccess.WRITE_ONLY,
|
|
pipelineCsrRead = false,
|
|
deterministicInteruptionEntry = false
|
|
)
|
|
|
|
|
|
def linuxFull(mtVecInit : BigInt) = CsrPluginConfig(
|
|
catchIllegalAccess = true,
|
|
mvendorid = 1,
|
|
marchid = 2,
|
|
mimpid = 3,
|
|
mhartid = 0,
|
|
misaExtensionsInit = 0, //TODO
|
|
misaAccess = CsrAccess.READ_WRITE,
|
|
mtvecAccess = CsrAccess.READ_WRITE,
|
|
mtvecInit = mtVecInit,
|
|
mepcAccess = CsrAccess.READ_WRITE,
|
|
mscratchGen = true,
|
|
mcauseAccess = CsrAccess.READ_WRITE,
|
|
mbadaddrAccess = CsrAccess.READ_WRITE,
|
|
mcycleAccess = CsrAccess.READ_WRITE,
|
|
minstretAccess = CsrAccess.READ_WRITE,
|
|
ucycleAccess = CsrAccess.READ_ONLY,
|
|
wfiGenAsWait = true,
|
|
ecallGen = true,
|
|
xtvecModeGen = false,
|
|
noCsrAlu = false,
|
|
wfiGenAsNop = false,
|
|
ebreakGen = true,
|
|
userGen = true,
|
|
supervisorGen = true,
|
|
sscratchGen = true,
|
|
stvecAccess = CsrAccess.READ_WRITE,
|
|
sepcAccess = CsrAccess.READ_WRITE,
|
|
scauseAccess = CsrAccess.READ_WRITE,
|
|
sbadaddrAccess = CsrAccess.READ_WRITE,
|
|
scycleAccess = CsrAccess.READ_WRITE,
|
|
sinstretAccess = CsrAccess.READ_WRITE,
|
|
satpAccess = CsrAccess.NONE, //Implemented into the MMU plugin
|
|
medelegAccess = CsrAccess.READ_WRITE,
|
|
midelegAccess = CsrAccess.READ_WRITE,
|
|
pipelineCsrRead = false,
|
|
deterministicInteruptionEntry = false
|
|
)
|
|
|
|
def all(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig(
|
|
catchIllegalAccess = true,
|
|
mvendorid = 11,
|
|
marchid = 22,
|
|
mimpid = 33,
|
|
mhartid = 0,
|
|
misaExtensionsInit = 66,
|
|
misaAccess = CsrAccess.READ_WRITE,
|
|
mtvecAccess = CsrAccess.READ_WRITE,
|
|
mtvecInit = mtvecInit,
|
|
mepcAccess = CsrAccess.READ_WRITE,
|
|
mscratchGen = true,
|
|
mcauseAccess = CsrAccess.READ_WRITE,
|
|
mbadaddrAccess = CsrAccess.READ_WRITE,
|
|
mcycleAccess = CsrAccess.READ_WRITE,
|
|
minstretAccess = CsrAccess.READ_WRITE,
|
|
ecallGen = true,
|
|
wfiGenAsWait = true,
|
|
ucycleAccess = CsrAccess.READ_ONLY
|
|
)
|
|
|
|
def all2(mtvecInit : BigInt) : CsrPluginConfig = CsrPluginConfig(
|
|
catchIllegalAccess = true,
|
|
mvendorid = 11,
|
|
marchid = 22,
|
|
mimpid = 33,
|
|
mhartid = 0,
|
|
misaExtensionsInit = 66,
|
|
misaAccess = CsrAccess.READ_WRITE,
|
|
mtvecAccess = CsrAccess.READ_WRITE,
|
|
mtvecInit = mtvecInit,
|
|
mepcAccess = CsrAccess.READ_WRITE,
|
|
mscratchGen = true,
|
|
mcauseAccess = CsrAccess.READ_WRITE,
|
|
mbadaddrAccess = CsrAccess.READ_WRITE,
|
|
mcycleAccess = CsrAccess.READ_WRITE,
|
|
minstretAccess = CsrAccess.READ_WRITE,
|
|
ecallGen = true,
|
|
wfiGenAsWait = true,
|
|
ucycleAccess = CsrAccess.READ_ONLY,
|
|
supervisorGen = true,
|
|
sscratchGen = true,
|
|
stvecAccess = CsrAccess.READ_WRITE,
|
|
sepcAccess = CsrAccess.READ_WRITE,
|
|
scauseAccess = CsrAccess.READ_WRITE,
|
|
sbadaddrAccess = CsrAccess.READ_WRITE,
|
|
scycleAccess = CsrAccess.READ_WRITE,
|
|
sinstretAccess = CsrAccess.READ_WRITE,
|
|
satpAccess = CsrAccess.READ_WRITE,
|
|
medelegAccess = CsrAccess.READ_WRITE,
|
|
midelegAccess = CsrAccess.READ_WRITE
|
|
)
|
|
|
|
def small(mtvecInit : BigInt) = CsrPluginConfig(
|
|
catchIllegalAccess = false,
|
|
mvendorid = null,
|
|
marchid = null,
|
|
mimpid = null,
|
|
mhartid = null,
|
|
misaExtensionsInit = 66,
|
|
misaAccess = CsrAccess.NONE,
|
|
mtvecAccess = CsrAccess.NONE,
|
|
mtvecInit = mtvecInit,
|
|
mepcAccess = CsrAccess.READ_WRITE,
|
|
mscratchGen = false,
|
|
mcauseAccess = CsrAccess.READ_ONLY,
|
|
mbadaddrAccess = CsrAccess.READ_ONLY,
|
|
mcycleAccess = CsrAccess.NONE,
|
|
minstretAccess = CsrAccess.NONE,
|
|
ecallGen = false,
|
|
wfiGenAsWait = false,
|
|
ucycleAccess = CsrAccess.NONE
|
|
)
|
|
|
|
def smallest(mtvecInit : BigInt) = CsrPluginConfig(
|
|
catchIllegalAccess = false,
|
|
mvendorid = null,
|
|
marchid = null,
|
|
mimpid = null,
|
|
mhartid = null,
|
|
misaExtensionsInit = 66,
|
|
misaAccess = CsrAccess.NONE,
|
|
mtvecAccess = CsrAccess.NONE,
|
|
mtvecInit = mtvecInit,
|
|
mepcAccess = CsrAccess.NONE,
|
|
mscratchGen = false,
|
|
mcauseAccess = CsrAccess.READ_ONLY,
|
|
mbadaddrAccess = CsrAccess.NONE,
|
|
mcycleAccess = CsrAccess.NONE,
|
|
minstretAccess = CsrAccess.NONE,
|
|
ecallGen = false,
|
|
wfiGenAsWait = false,
|
|
ucycleAccess = CsrAccess.NONE
|
|
)
|
|
|
|
}
|
|
case class CsrWrite(that : Data, bitOffset : Int)
|
|
case class CsrRead(that : Data , bitOffset : Int)
|
|
case class CsrReadToWriteOverride(that : Data, bitOffset : Int) //Used for special cases, as MIP where there shadow stuff
|
|
case class CsrOnWrite(doThat :() => Unit)
|
|
case class CsrOnRead(doThat : () => Unit)
|
|
case class CsrMapping() extends CsrInterface{
|
|
val mapping = mutable.HashMap[Int,ArrayBuffer[Any]]()
|
|
def addMappingAt(address : Int,that : Any) = mapping.getOrElseUpdate(address,new ArrayBuffer[Any]) += that
|
|
override def r(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrRead(that,bitOffset))
|
|
override def w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrWrite(that,bitOffset))
|
|
override def r2w(csrAddress : Int, bitOffset : Int, that : Data): Unit = addMappingAt(csrAddress, CsrReadToWriteOverride(that,bitOffset))
|
|
override def onWrite(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnWrite(() => body))
|
|
override def onRead(csrAddress: Int)(body: => Unit): Unit = addMappingAt(csrAddress, CsrOnRead(() => {body}))
|
|
}
|
|
|
|
|
|
trait CsrInterface{
|
|
def onWrite(csrAddress : Int)(doThat : => Unit) : Unit
|
|
def onRead(csrAddress : Int)(doThat : => Unit) : Unit
|
|
def r(csrAddress : Int, bitOffset : Int, that : Data): Unit
|
|
def w(csrAddress : Int, bitOffset : Int, that : Data): Unit
|
|
def rw(csrAddress : Int, bitOffset : Int,that : Data): Unit ={
|
|
r(csrAddress,bitOffset,that)
|
|
w(csrAddress,bitOffset,that)
|
|
}
|
|
|
|
def r2w(csrAddress : Int, bitOffset : Int,that : Data): Unit
|
|
|
|
def rw(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) rw(csrAddress,that._1, that._2)
|
|
def w(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) w(csrAddress,that._1, that._2)
|
|
def r(csrAddress : Int, thats : (Int, Data)*) : Unit = for(that <- thats) r(csrAddress,that._1, that._2)
|
|
def rw[T <: Data](csrAddress : Int, that : T): Unit = rw(csrAddress,0,that)
|
|
def w[T <: Data](csrAddress : Int, that : T): Unit = w(csrAddress,0,that)
|
|
def r [T <: Data](csrAddress : Int, that : T): Unit = r(csrAddress,0,that)
|
|
def isWriting(csrAddress : Int) : Bool = {
|
|
val ret = False
|
|
onWrite(csrAddress){
|
|
ret := True
|
|
}
|
|
ret
|
|
}
|
|
|
|
def isReading(csrAddress : Int) : Bool = {
|
|
val ret = False
|
|
onRead(csrAddress){
|
|
ret := True
|
|
}
|
|
ret
|
|
}
|
|
}
|
|
|
|
|
|
trait IContextSwitching{
|
|
def isContextSwitching : Bool
|
|
}
|
|
|
|
class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{
|
|
import config._
|
|
import CsrAccess._
|
|
|
|
assert(!(wfiGenAsNop && wfiGenAsWait))
|
|
|
|
def xlen = 32
|
|
|
|
//Mannage ExceptionService calls
|
|
val exceptionPortsInfos = ArrayBuffer[ExceptionPortInfo]()
|
|
def exceptionCodeWidth = 4
|
|
override def newExceptionPort(stage : Stage, priority : Int = 0) = {
|
|
val interface = Flow(ExceptionCause())
|
|
exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority)
|
|
interface
|
|
}
|
|
|
|
var exceptionPending : Bool = null
|
|
override def isExceptionPending(): Bool = exceptionPending
|
|
|
|
var jumpInterface : Flow[UInt] = null
|
|
var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null
|
|
var externalInterruptS : Bool = null
|
|
var forceMachineWire : Bool = null
|
|
var privilege : UInt = null
|
|
var selfException : Flow[ExceptionCause] = null
|
|
var contextSwitching : Bool = null
|
|
override def isContextSwitching = contextSwitching
|
|
|
|
object EnvCtrlEnum extends SpinalEnum(binarySequential){
|
|
val NONE, XRET = newElement()
|
|
val WFI = if(wfiGenAsWait) newElement() else null
|
|
val ECALL = if(ecallGen) newElement() else null
|
|
val EBREAK = if(ebreakGen) newElement() else null
|
|
}
|
|
|
|
object ENV_CTRL extends Stageable(EnvCtrlEnum())
|
|
object IS_CSR extends Stageable(Bool)
|
|
object CSR_WRITE_OPCODE extends Stageable(Bool)
|
|
object CSR_READ_OPCODE extends Stageable(Bool)
|
|
object PIPELINED_CSR_READ extends Stageable(Bits(32 bits))
|
|
|
|
var allowInterrupts : Bool = null
|
|
var allowException : Bool = null
|
|
|
|
val csrMapping = new CsrMapping()
|
|
|
|
//Interruption and exception data model
|
|
case class Delegator(var enable : Bool, privilege : Int)
|
|
case class InterruptSpec(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator])
|
|
case class ExceptionSpec(id : Int, delegators : List[Delegator])
|
|
var interruptSpecs = ArrayBuffer[InterruptSpec]()
|
|
var exceptionSpecs = ArrayBuffer[ExceptionSpec]()
|
|
|
|
def addInterrupt(cond : Bool, id : Int, privilege : Int, delegators : List[Delegator]): Unit = {
|
|
interruptSpecs += InterruptSpec(cond, id, privilege, delegators)
|
|
}
|
|
|
|
override def r(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r(csrAddress, bitOffset, that)
|
|
override def w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.w(csrAddress, bitOffset, that)
|
|
override def r2w(csrAddress: Int, bitOffset: Int, that: Data): Unit = csrMapping.r2w(csrAddress, bitOffset, that)
|
|
override def onWrite(csrAddress: Int)(body: => Unit): Unit = csrMapping.onWrite(csrAddress)(body)
|
|
override def onRead(csrAddress: Int)(body: => Unit): Unit = csrMapping.onRead(csrAddress)(body)
|
|
|
|
override def setup(pipeline: VexRiscv): Unit = {
|
|
import pipeline.config._
|
|
|
|
val defaultEnv = List[(Stageable[_ <: BaseType],Any)](
|
|
)
|
|
|
|
val defaultCsrActions = List[(Stageable[_ <: BaseType],Any)](
|
|
IS_CSR -> True,
|
|
REGFILE_WRITE_VALID -> True,
|
|
BYPASSABLE_EXECUTE_STAGE -> False,
|
|
BYPASSABLE_MEMORY_STAGE -> True
|
|
) ++ (if(catchIllegalAccess) List(HAS_SIDE_EFFECT -> True) else Nil)
|
|
|
|
val nonImmediatActions = defaultCsrActions ++ List(
|
|
SRC1_CTRL -> Src1CtrlEnum.RS,
|
|
RS1_USE -> True
|
|
)
|
|
|
|
val immediatActions = defaultCsrActions ++ List(
|
|
SRC1_CTRL -> Src1CtrlEnum.URS1
|
|
)
|
|
|
|
val decoderService = pipeline.service(classOf[DecoderService])
|
|
|
|
decoderService.addDefault(ENV_CTRL, EnvCtrlEnum.NONE)
|
|
decoderService.addDefault(IS_CSR, False)
|
|
decoderService.add(List(
|
|
CSRRW -> nonImmediatActions,
|
|
CSRRS -> nonImmediatActions,
|
|
CSRRC -> nonImmediatActions,
|
|
CSRRWI -> immediatActions,
|
|
CSRRSI -> immediatActions,
|
|
CSRRCI -> immediatActions,
|
|
MRET -> (defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.XRET, HAS_SIDE_EFFECT -> True)),
|
|
SRET -> (defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.XRET, HAS_SIDE_EFFECT -> True))
|
|
))
|
|
if(wfiGenAsWait) decoderService.add(WFI, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.WFI))
|
|
if(wfiGenAsNop) decoderService.add(WFI, Nil)
|
|
if(ecallGen) decoderService.add(ECALL, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.ECALL, HAS_SIDE_EFFECT -> True))
|
|
if(ebreakGen) decoderService.add(EBREAK, defaultEnv ++ List(ENV_CTRL -> EnvCtrlEnum.EBREAK, HAS_SIDE_EFFECT -> True))
|
|
|
|
val pcManagerService = pipeline.service(classOf[JumpService])
|
|
jumpInterface = pcManagerService.createJumpInterface(pipeline.stages.last)
|
|
jumpInterface.valid := False
|
|
jumpInterface.payload.assignDontCare()
|
|
|
|
exceptionPending = False
|
|
timerInterrupt = in Bool() setName("timerInterrupt")
|
|
externalInterrupt = in Bool() setName("externalInterrupt")
|
|
softwareInterrupt = in Bool() setName("softwareInterrupt") default(False)
|
|
if(supervisorGen){
|
|
// timerInterruptS = in Bool() setName("timerInterruptS")
|
|
externalInterruptS = in Bool() setName("externalInterruptS")
|
|
}
|
|
contextSwitching = Bool().setName("contextSwitching")
|
|
|
|
privilege = UInt(2 bits).setName("CsrPlugin_privilege")
|
|
forceMachineWire = False
|
|
|
|
if(catchIllegalAccess || ecallGen || ebreakGen)
|
|
selfException = newExceptionPort(pipeline.execute)
|
|
|
|
allowInterrupts = True
|
|
allowException = True
|
|
|
|
for (i <- interruptSpecs) i.cond = i.cond.pull()
|
|
|
|
|
|
pipeline.update(MPP, UInt(2 bits))
|
|
}
|
|
|
|
def inhibateInterrupts() : Unit = allowInterrupts := False
|
|
def inhibateException() : Unit = allowException := False
|
|
|
|
override def isUser() : Bool = privilege === 0
|
|
override def isSupervisor(): Bool = privilege === 1
|
|
override def isMachine(): Bool = privilege === 3
|
|
override def forceMachine(): Unit = forceMachineWire := True
|
|
|
|
override def build(pipeline: VexRiscv): Unit = {
|
|
import pipeline._
|
|
import pipeline.config._
|
|
val fetcher = service(classOf[IBusFetcher])
|
|
|
|
//Define CSR mapping utilities
|
|
implicit class CsrAccessPimper(csrAccess : CsrAccess){
|
|
def apply(csrAddress : Int, thats : (Int, Data)*) : Unit = {
|
|
if(csrAccess == `WRITE_ONLY` || csrAccess == `READ_WRITE`) for(that <- thats) csrMapping.w(csrAddress,that._1, that._2)
|
|
if(csrAccess == `READ_ONLY` || csrAccess == `READ_WRITE`) for(that <- thats) csrMapping.r(csrAddress,that._1, that._2)
|
|
}
|
|
def apply(csrAddress : Int, that : Data) : Unit = {
|
|
if(csrAccess == `WRITE_ONLY` || csrAccess == `READ_WRITE`) csrMapping.w(csrAddress, 0, that)
|
|
if(csrAccess == `READ_ONLY` || csrAccess == `READ_WRITE`) csrMapping.r(csrAddress, 0, that)
|
|
}
|
|
}
|
|
|
|
|
|
case class Xtvec() extends Bundle {
|
|
val mode = Bits(2 bits)
|
|
val base = UInt(xlen-2 bits)
|
|
}
|
|
|
|
val privilegeReg = privilegeGen generate RegInit(U"11")
|
|
privilege := (if(privilegeGen) privilegeReg else U"11")
|
|
|
|
when(forceMachineWire) { privilege := 3 }
|
|
|
|
val machineCsr = pipeline plug new Area{
|
|
//Define CSR registers
|
|
// Status => MXR, SUM, TVM, TW, TSE ?
|
|
val misa = new Area{
|
|
val base = Reg(UInt(2 bits)) init(U"01") allowUnsetRegToAvoidLatch
|
|
val extensions = Reg(Bits(26 bits)) init(misaExtensionsInit) allowUnsetRegToAvoidLatch
|
|
}
|
|
|
|
val mtvec = Reg(Xtvec()).allowUnsetRegToAvoidLatch
|
|
|
|
if(mtvecInit != null) mtvec.mode init(mtvecInit & 0x3)
|
|
if(mtvecInit != null) mtvec.base init(mtvecInit / 4)
|
|
val mepc = Reg(UInt(xlen bits))
|
|
val mstatus = new Area{
|
|
val MIE, MPIE = RegInit(False)
|
|
val MPP = RegInit(U"11")
|
|
}
|
|
val mip = new Area{
|
|
val MEIP = RegNext(externalInterrupt)
|
|
val MTIP = RegNext(timerInterrupt)
|
|
val MSIP = RegNext(softwareInterrupt)
|
|
}
|
|
val mie = new Area{
|
|
val MEIE, MTIE, MSIE = RegInit(False)
|
|
}
|
|
val mscratch = if(mscratchGen) Reg(Bits(xlen bits)) else null
|
|
val mcause = new Area{
|
|
val interrupt = Reg(Bool)
|
|
val exceptionCode = Reg(UInt(exceptionCodeWidth bits))
|
|
}
|
|
val mtval = Reg(UInt(xlen bits))
|
|
val mcycle = Reg(UInt(64 bits)) randBoot()
|
|
val minstret = Reg(UInt(64 bits)) randBoot()
|
|
|
|
|
|
val medeleg = supervisorGen generate new Area {
|
|
val IAM, IAF, II, LAM, LAF, SAM, SAF, EU, ES, IPF, LPF, SPF = RegInit(False)
|
|
val mapping = mutable.HashMap(0 -> IAM, 1 -> IAF, 2 -> II, 4 -> LAM, 5 -> LAF, 6 -> SAM, 7 -> SAF, 8 -> EU, 9 -> ES, 12 -> IPF, 13 -> LPF, 15 -> SPF)
|
|
}
|
|
val mideleg = supervisorGen generate new Area {
|
|
val ST, SE, SS = RegInit(False)
|
|
}
|
|
|
|
if(mvendorid != null) READ_ONLY(CSR.MVENDORID, U(mvendorid))
|
|
if(marchid != null) READ_ONLY(CSR.MARCHID , U(marchid ))
|
|
if(mimpid != null) READ_ONLY(CSR.MIMPID , U(mimpid ))
|
|
if(mhartid != null) READ_ONLY(CSR.MHARTID , U(mhartid ))
|
|
misaAccess(CSR.MISA, xlen-2 -> misa.base , 0 -> misa.extensions)
|
|
|
|
//Machine CSR
|
|
READ_WRITE(CSR.MSTATUS,11 -> mstatus.MPP, 7 -> mstatus.MPIE, 3 -> mstatus.MIE)
|
|
READ_ONLY(CSR.MIP, 11 -> mip.MEIP, 7 -> mip.MTIP)
|
|
READ_WRITE(CSR.MIP, 3 -> mip.MSIP)
|
|
READ_WRITE(CSR.MIE, 11 -> mie.MEIE, 7 -> mie.MTIE, 3 -> mie.MSIE)
|
|
|
|
mtvecAccess(CSR.MTVEC, 2 -> mtvec.base, 0 -> mtvec.mode)
|
|
mepcAccess(CSR.MEPC, mepc)
|
|
if(mscratchGen) READ_WRITE(CSR.MSCRATCH, mscratch)
|
|
mcauseAccess(CSR.MCAUSE, xlen-1 -> mcause.interrupt, 0 -> mcause.exceptionCode)
|
|
mbadaddrAccess(CSR.MBADADDR, mtval)
|
|
mcycleAccess(CSR.MCYCLE, mcycle(31 downto 0))
|
|
mcycleAccess(CSR.MCYCLEH, mcycle(63 downto 32))
|
|
minstretAccess(CSR.MINSTRET, minstret(31 downto 0))
|
|
minstretAccess(CSR.MINSTRETH, minstret(63 downto 32))
|
|
|
|
if(supervisorGen) {
|
|
for((id, enable) <- medeleg.mapping) medelegAccess(CSR.MEDELEG, id -> enable)
|
|
midelegAccess(CSR.MIDELEG, 9 -> mideleg.SE, 5 -> mideleg.ST, 1 -> mideleg.SS)
|
|
}
|
|
|
|
//User CSR
|
|
ucycleAccess(CSR.UCYCLE, mcycle(31 downto 0))
|
|
ucycleAccess(CSR.UCYCLEH, mcycle(63 downto 32))
|
|
|
|
pipeline(MPP) := mstatus.MPP
|
|
}
|
|
|
|
val supervisorCsr = ifGen(supervisorGen) {
|
|
pipeline plug new Area {
|
|
val sstatus = new Area {
|
|
val SIE, SPIE = RegInit(False)
|
|
val SPP = RegInit(U"1")
|
|
}
|
|
|
|
val sip = new Area {
|
|
val SEIP_SOFT = RegInit(False)
|
|
val SEIP_INPUT = RegNext(externalInterruptS)
|
|
val SEIP_OR = SEIP_SOFT || SEIP_INPUT
|
|
val STIP = RegInit(False)
|
|
val SSIP = RegInit(False)
|
|
}
|
|
val sie = new Area {
|
|
val SEIE, STIE, SSIE = RegInit(False)
|
|
}
|
|
val stvec = Reg(Xtvec()).allowUnsetRegToAvoidLatch
|
|
val sscratch = if (sscratchGen) Reg(Bits(xlen bits)) else null
|
|
|
|
val scause = new Area {
|
|
val interrupt = Reg(Bool)
|
|
val exceptionCode = Reg(UInt(exceptionCodeWidth bits))
|
|
}
|
|
val stval = Reg(UInt(xlen bits))
|
|
val sepc = Reg(UInt(xlen bits))
|
|
val satp = new Area {
|
|
val PPN = Reg(Bits(22 bits))
|
|
val ASID = Reg(Bits(9 bits))
|
|
val MODE = Reg(Bits(1 bits))
|
|
}
|
|
|
|
//Supervisor CSR
|
|
for(offset <- List(CSR.MSTATUS, CSR.SSTATUS)) READ_WRITE(offset,8 -> sstatus.SPP, 5 -> sstatus.SPIE, 1 -> sstatus.SIE)
|
|
for(offset <- List(CSR.MIP, CSR.SIP)) {
|
|
READ_WRITE(offset, 5 -> sip.STIP, 1 -> sip.SSIP)
|
|
READ_ONLY(offset, 9 -> sip.SEIP_OR)
|
|
WRITE_ONLY(offset, 9 -> sip.SEIP_SOFT)
|
|
r2w(offset, 9, sip.SEIP_SOFT)
|
|
}
|
|
|
|
for(offset <- List(CSR.MIE, CSR.SIE)) READ_WRITE(offset, 9 -> sie.SEIE, 5 -> sie.STIE, 1 -> sie.SSIE)
|
|
|
|
|
|
stvecAccess(CSR.STVEC, 2 -> stvec.base, 0 -> stvec.mode)
|
|
sepcAccess(CSR.SEPC, sepc)
|
|
if(sscratchGen) READ_WRITE(CSR.SSCRATCH, sscratch)
|
|
scauseAccess(CSR.SCAUSE, xlen-1 -> scause.interrupt, 0 -> scause.exceptionCode)
|
|
sbadaddrAccess(CSR.SBADADDR, stval)
|
|
satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pipeline plug new Area{
|
|
import machineCsr._
|
|
import supervisorCsr._
|
|
|
|
val lastStage = pipeline.stages.last
|
|
val beforeLastStage = pipeline.stages(pipeline.stages.size-2)
|
|
val stagesFromExecute = pipeline.stages.dropWhile(_ != execute)
|
|
|
|
//Manage counters
|
|
mcycle := mcycle + 1
|
|
when(lastStage.arbitration.isFiring) {
|
|
minstret := minstret + 1
|
|
}
|
|
|
|
|
|
if(supervisorGen) {
|
|
addInterrupt(sip.STIP && sie.STIE, id = 5, privilege = 1, delegators = List(Delegator(mideleg.ST, 3)))
|
|
addInterrupt(sip.SSIP && sie.SSIE, id = 1, privilege = 1, delegators = List(Delegator(mideleg.SS, 3)))
|
|
addInterrupt(sip.SEIP_OR && sie.SEIE, id = 9, privilege = 1, delegators = List(Delegator(mideleg.SE, 3)))
|
|
|
|
for((id, enable) <- medeleg.mapping) exceptionSpecs += ExceptionSpec(id, List(Delegator(enable, 3)))
|
|
}
|
|
|
|
addInterrupt(mip.MTIP && mie.MTIE, id = 7, privilege = 3, delegators = Nil)
|
|
addInterrupt(mip.MSIP && mie.MSIE, id = 3, privilege = 3, delegators = Nil)
|
|
addInterrupt(mip.MEIP && mie.MEIE, id = 11, privilege = 3, delegators = Nil)
|
|
|
|
|
|
val mepcCaptureStage = if(exceptionPortsInfos.nonEmpty) lastStage else decode
|
|
|
|
|
|
//Aggregate all exception port and remove required instructions
|
|
val exceptionPortCtrl = if(exceptionPortsInfos.nonEmpty) new Area{
|
|
val firstStageIndexWithExceptionPort = exceptionPortsInfos.map(i => indexOf(i.stage)).min
|
|
val exceptionValids = Vec(stages.map(s => Bool().setPartialName(s.getName())))
|
|
val exceptionValidsRegs = Vec(stages.map(s => Reg(Bool).init(False).setPartialName(s.getName()))).allowUnsetRegToAvoidLatch
|
|
val exceptionContext = Reg(ExceptionCause())
|
|
val exceptionTargetPrivilegeUncapped = U"11"
|
|
|
|
switch(exceptionContext.code){
|
|
for(s <- exceptionSpecs){
|
|
is(s.id){
|
|
var exceptionPrivilegs = if (supervisorGen) List(1, 3) else List(3)
|
|
while(exceptionPrivilegs.length != 1){
|
|
val p = exceptionPrivilegs.head
|
|
if (exceptionPrivilegs.tail.forall(e => s.delegators.exists(_.privilege == e))) {
|
|
val delegUpOn = s.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _)
|
|
val delegDownOff = !s.delegators.filter(_.privilege <= p).map(_.enable).orR
|
|
when(delegUpOn && delegDownOff) {
|
|
exceptionTargetPrivilegeUncapped := p
|
|
}
|
|
}
|
|
exceptionPrivilegs = exceptionPrivilegs.tail
|
|
}
|
|
}
|
|
}
|
|
}
|
|
val exceptionTargetPrivilege = privilege.max(exceptionTargetPrivilegeUncapped)
|
|
|
|
val groupedByStage = exceptionPortsInfos.map(_.stage).distinct.map(s => {
|
|
val stagePortsInfos = exceptionPortsInfos.filter(_.stage == s).sortWith(_.priority > _.priority)
|
|
val stagePort = stagePortsInfos.length match{
|
|
case 1 => stagePortsInfos.head.port
|
|
case _ => {
|
|
val groupedPort = Flow(ExceptionCause())
|
|
val valids = stagePortsInfos.map(_.port.valid)
|
|
val codes = stagePortsInfos.map(_.port.payload)
|
|
groupedPort.valid := valids.orR
|
|
groupedPort.payload := MuxOH(OHMasking.first(stagePortsInfos.map(_.port.valid).asBits), codes)
|
|
groupedPort
|
|
}
|
|
}
|
|
ExceptionPortInfo(stagePort,s,0)
|
|
})
|
|
|
|
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) {
|
|
if(indexOf(stage) != 0) stages(indexOf(stage) - 1).arbitration.flushAll := True
|
|
stage.arbitration.removeIt := True
|
|
exceptionValids(stageId) := True
|
|
exceptionContext := port.payload
|
|
}
|
|
}
|
|
|
|
for(stageId <- firstStageIndexWithExceptionPort until stages.length; stage = stages(stageId) ){
|
|
val previousStage = if(stageId == firstStageIndexWithExceptionPort) stage else stages(stageId-1)
|
|
when(!stage.arbitration.isStuck){
|
|
exceptionValidsRegs(stageId) := (if(stageId != firstStageIndexWithExceptionPort) exceptionValids(stageId-1) && !previousStage.arbitration.isStuck else False)
|
|
}otherwise{
|
|
if(stage != stages.last)
|
|
exceptionValidsRegs(stageId) := exceptionValids(stageId)
|
|
else
|
|
exceptionValidsRegs(stageId) := False
|
|
}
|
|
when(stage.arbitration.isFlushed){
|
|
exceptionValids(stageId) := False
|
|
}
|
|
}
|
|
|
|
when(exceptionValidsRegs.orR){
|
|
fetcher.haltIt()
|
|
}
|
|
|
|
//Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc)
|
|
stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last
|
|
exceptionPending setWhen(exceptionValidsRegs.orR)
|
|
} else null
|
|
|
|
|
|
|
|
|
|
|
|
//Process interrupt request, code and privilege
|
|
val interrupt = False
|
|
val interruptCode = UInt(4 bits).assignDontCare().addTag(Verilator.public)
|
|
var interruptPrivilegs = if (supervisorGen) List(1, 3) else List(3)
|
|
val interruptTargetPrivilege = UInt(2 bits).assignDontCare()
|
|
val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]()
|
|
if(supervisorGen) privilegeAllowInterrupts += 1 -> ((sstatus.SIE && privilege === "01") || privilege < "01")
|
|
privilegeAllowInterrupts += 3 -> (mstatus.MIE || privilege < "11")
|
|
while(interruptPrivilegs.nonEmpty){
|
|
val p = interruptPrivilegs.head
|
|
when(privilegeAllowInterrupts(p)){
|
|
for(i <- interruptSpecs
|
|
if i.privilege <= p //EX : Machine timer interrupt can't go into supervisor mode
|
|
if interruptPrivilegs.tail.forall(e => i.delegators.exists(_.privilege == e))){ // EX : Supervisor timer need to have machine mode delegator
|
|
val delegUpOn = i.delegators.filter(_.privilege > p).map(_.enable).fold(True)(_ && _)
|
|
val delegDownOff = !i.delegators.filter(_.privilege <= p).map(_.enable).orR
|
|
when(i.cond && delegUpOn && delegDownOff){
|
|
interrupt := True
|
|
interruptCode := i.id
|
|
interruptTargetPrivilege := p
|
|
}
|
|
}
|
|
}
|
|
interruptPrivilegs = interruptPrivilegs.tail
|
|
}
|
|
|
|
interrupt.clearWhen(!allowInterrupts)
|
|
|
|
val exception = if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionValids.last && allowException else False
|
|
val lastStageWasWfi = if(wfiGenAsWait) RegNext(lastStage.arbitration.isFiring && lastStage.input(ENV_CTRL) === EnvCtrlEnum.WFI) init(False) else False
|
|
|
|
|
|
|
|
//Used to make the pipeline empty softly (for interrupts)
|
|
val pipelineLiberator = new Area{
|
|
when(interrupt){
|
|
decode.arbitration.haltByOther := decode.arbitration.isValid
|
|
}
|
|
|
|
val done = !stagesFromExecute.map(_.arbitration.isValid).orR && fetcher.pcValid(mepcCaptureStage)
|
|
if(exceptionPortCtrl != null) done.clearWhen(exceptionPortCtrl.exceptionValidsRegs.tail.orR)
|
|
}
|
|
|
|
//Interrupt/Exception entry logic
|
|
val interruptJump = Bool.addTag(Verilator.public)
|
|
interruptJump := interrupt && pipelineLiberator.done
|
|
|
|
val hadException = RegNext(exception) init(False)
|
|
pipelineLiberator.done.clearWhen(hadException)
|
|
|
|
|
|
val targetPrivilege = CombInit(interruptTargetPrivilege)
|
|
if(exceptionPortCtrl != null) when(hadException) {
|
|
targetPrivilege := exceptionPortCtrl.exceptionTargetPrivilege
|
|
}
|
|
|
|
val trapCause = CombInit(interruptCode)
|
|
if(exceptionPortCtrl != null) when( hadException){
|
|
trapCause := exceptionPortCtrl.exceptionContext.code
|
|
}
|
|
|
|
val xtvec = Xtvec().assignDontCare()
|
|
switch(targetPrivilege){
|
|
if(supervisorGen) is(1) { xtvec := supervisorCsr.stvec }
|
|
is(3){ xtvec := machineCsr.mtvec }
|
|
}
|
|
|
|
when(hadException || interruptJump){
|
|
fetcher.haltIt() //Avoid having the fetch confused by the incomming privilege switch
|
|
|
|
jumpInterface.valid := True
|
|
jumpInterface.payload := (if(!xtvecModeGen) xtvec.base @@ "00" else (xtvec.mode === 0 || hadException) ? (xtvec.base @@ "00") | ((xtvec.base + trapCause) @@ "00") )
|
|
beforeLastStage.arbitration.flushAll := True
|
|
|
|
if(privilegeGen) privilegeReg := targetPrivilege
|
|
|
|
switch(targetPrivilege){
|
|
if(supervisorGen) is(1) {
|
|
sstatus.SIE := False
|
|
sstatus.SPIE := sstatus.SIE
|
|
sstatus.SPP := privilege(0 downto 0)
|
|
scause.interrupt := !hadException
|
|
scause.exceptionCode := trapCause
|
|
sepc := mepcCaptureStage.input(PC)
|
|
if (exceptionPortCtrl != null) when(hadException){
|
|
stval := exceptionPortCtrl.exceptionContext.badAddr
|
|
}
|
|
}
|
|
|
|
is(3){
|
|
mstatus.MIE := False
|
|
mstatus.MPIE := mstatus.MIE
|
|
mstatus.MPP := privilege
|
|
mcause.interrupt := !hadException
|
|
mcause.exceptionCode := trapCause
|
|
mepc := mepcCaptureStage.input(PC)
|
|
if(exceptionPortCtrl != null) when(hadException){
|
|
mtval := exceptionPortCtrl.exceptionContext.badAddr
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
lastStage plug new Area{
|
|
import lastStage._
|
|
|
|
//Manage MRET / SRET instructions
|
|
when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) {
|
|
fetcher.haltIt()
|
|
jumpInterface.valid := True
|
|
beforeLastStage.arbitration.flushAll := True
|
|
switch(input(INSTRUCTION)(29 downto 28)){
|
|
is(3){
|
|
mstatus.MPP := U"00"
|
|
mstatus.MIE := mstatus.MPIE
|
|
mstatus.MPIE := True
|
|
jumpInterface.payload := mepc
|
|
if(privilegeGen) privilegeReg := mstatus.MPP
|
|
}
|
|
if(supervisorGen) is(1){
|
|
sstatus.SPP := U"0"
|
|
sstatus.SIE := sstatus.SPIE
|
|
sstatus.SPIE := True
|
|
jumpInterface.payload := sepc
|
|
if(privilegeGen) privilegeReg := U"0" @@ sstatus.SPP
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
contextSwitching := jumpInterface.valid
|
|
|
|
//CSR read/write instructions management
|
|
decode plug new Area{
|
|
import decode._
|
|
|
|
val imm = IMM(input(INSTRUCTION))
|
|
insert(CSR_WRITE_OPCODE) := ! (
|
|
(input(INSTRUCTION)(14 downto 13) === "01" && input(INSTRUCTION)(rs1Range) === 0)
|
|
|| (input(INSTRUCTION)(14 downto 13) === "11" && imm.z === 0)
|
|
)
|
|
insert(CSR_READ_OPCODE) := input(INSTRUCTION)(13 downto 7) =/= B"0100000"
|
|
}
|
|
|
|
|
|
execute plug new Area{
|
|
import execute._
|
|
//Manage WFI instructions
|
|
val inWfi = False.addTag(Verilator.public)
|
|
if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){
|
|
inWfi := True
|
|
when(!interrupt){
|
|
arbitration.haltItself := True
|
|
}
|
|
}
|
|
}
|
|
|
|
decode.arbitration.haltByOther setWhen(stagesFromExecute.map(s => s.arbitration.isValid && s.input(ENV_CTRL) === EnvCtrlEnum.XRET).asBits.orR)
|
|
|
|
execute plug new Area {
|
|
import execute._
|
|
def previousStage = decode
|
|
val blockedBySideEffects = stagesFromExecute.tail.map(s => s.arbitration.isValid).asBits().orR // && s.input(HAS_SIDE_EFFECT) to improve be less pessimistic
|
|
|
|
val illegalAccess = True
|
|
val illegalInstruction = False
|
|
if(selfException != null) {
|
|
selfException.valid := False
|
|
selfException.code.assignDontCare()
|
|
selfException.badAddr := input(INSTRUCTION).asUInt
|
|
if(catchIllegalAccess) when(illegalAccess || illegalInstruction){
|
|
selfException.valid := True
|
|
selfException.code := 2
|
|
}
|
|
}
|
|
|
|
//Manage MRET / SRET instructions
|
|
when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.XRET) {
|
|
when(input(INSTRUCTION)(29 downto 28).asUInt > privilege) {
|
|
illegalInstruction := True
|
|
}
|
|
}
|
|
|
|
|
|
//Manage ECALL instructions
|
|
if(ecallGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.ECALL){
|
|
selfException.valid := True
|
|
switch(privilege) {
|
|
is(0) { selfException.code := 8 }
|
|
if(supervisorGen) is(1) { selfException.code := 9 }
|
|
default { selfException.code := 11 }
|
|
}
|
|
}
|
|
|
|
|
|
if(ebreakGen) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.EBREAK){
|
|
selfException.valid := True
|
|
selfException.code := 3
|
|
}
|
|
|
|
|
|
val imm = IMM(input(INSTRUCTION))
|
|
def writeSrc = input(SRC1)
|
|
// val readDataValid = True
|
|
val readData = B(0, 32 bits)
|
|
val writeInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_WRITE_OPCODE)
|
|
val readInstruction = arbitration.isValid && input(IS_CSR) && input(CSR_READ_OPCODE)
|
|
val writeEnable = writeInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && readDataRegValid
|
|
val readEnable = readInstruction && ! blockedBySideEffects && !arbitration.isStuckByOthers// && !readDataRegValid
|
|
//arbitration.isStuckByOthers, in case of the hazardPlugin is in the executeStage
|
|
|
|
|
|
// def readDataReg = memory.input(REGFILE_WRITE_DATA) //PIPE OPT
|
|
// val readDataRegValid = Reg(Bool) setWhen(arbitration.isValid) clearWhen(!arbitration.isStuck)
|
|
// val writeDataEnable = input(INSTRUCTION)(13) ? writeSrc | B"xFFFFFFFF"
|
|
// val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux(
|
|
// False -> writeSrc,
|
|
// True -> Mux(input(INSTRUCTION)(12), ~writeSrc, writeSrc)
|
|
// )
|
|
|
|
val readToWriteData = CombInit(readData)
|
|
val writeData = if(noCsrAlu) writeSrc else input(INSTRUCTION)(13).mux(
|
|
False -> writeSrc,
|
|
True -> Mux(input(INSTRUCTION)(12), readToWriteData & ~writeSrc, readToWriteData | writeSrc)
|
|
)
|
|
|
|
|
|
|
|
// arbitration.haltItself setWhen(writeInstruction && !readDataRegValid)
|
|
|
|
|
|
when(arbitration.isValid && input(IS_CSR)) {
|
|
if(!pipelineCsrRead) output(REGFILE_WRITE_DATA) := readData
|
|
arbitration.haltItself setWhen(blockedBySideEffects)
|
|
}
|
|
if(pipelineCsrRead){
|
|
insert(PIPELINED_CSR_READ) := readData
|
|
when(memory.arbitration.isValid && memory.input(IS_CSR)) {
|
|
memory.output(REGFILE_WRITE_DATA) := memory.input(PIPELINED_CSR_READ)
|
|
}
|
|
}
|
|
//
|
|
// Component.current.rework{
|
|
// when(arbitration.isFiring && input(IS_CSR)) {
|
|
// memory.input(REGFILE_WRITE_DATA).getDrivingReg := readData
|
|
// }
|
|
// }
|
|
|
|
//Translation of the csrMapping into real logic
|
|
val csrAddress = input(INSTRUCTION)(csrRange)
|
|
Component.current.addPrePopTask(() => {
|
|
switch(csrAddress) {
|
|
for ((address, jobs) <- csrMapping.mapping) {
|
|
is(address) {
|
|
val withWrite = jobs.exists(j => j.isInstanceOf[CsrWrite] || j.isInstanceOf[CsrOnWrite])
|
|
val withRead = jobs.exists(j => j.isInstanceOf[CsrRead] || j.isInstanceOf[CsrOnRead])
|
|
if(withRead && withWrite) {
|
|
illegalAccess := False
|
|
} else {
|
|
if (withWrite) illegalAccess.clearWhen(input(CSR_WRITE_OPCODE))
|
|
if (withRead) illegalAccess.clearWhen(input(CSR_READ_OPCODE))
|
|
}
|
|
|
|
when(writeEnable) {
|
|
for (element <- jobs) element match {
|
|
case element: CsrWrite => element.that.assignFromBits(writeData(element.bitOffset, element.that.getBitsWidth bits))
|
|
case element: CsrOnWrite =>
|
|
element.doThat()
|
|
case _ =>
|
|
}
|
|
}
|
|
|
|
for (element <- jobs) element match {
|
|
case element: CsrRead if element.that.getBitsWidth != 0 => readData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
|
|
case _ =>
|
|
}
|
|
|
|
when(readEnable) {
|
|
for (element <- jobs) element match {
|
|
case element: CsrOnRead =>
|
|
element.doThat()
|
|
case _ =>
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch(csrAddress) {
|
|
for ((address, jobs) <- csrMapping.mapping if jobs.exists(_.isInstanceOf[CsrReadToWriteOverride])) {
|
|
is(address) {
|
|
for (element <- jobs) element match {
|
|
case element: CsrReadToWriteOverride if element.that.getBitsWidth != 0 => readToWriteData(element.bitOffset, element.that.getBitsWidth bits) := element.that.asBits
|
|
case _ =>
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
illegalAccess setWhen(privilege < csrAddress(9 downto 8).asUInt)
|
|
illegalAccess clearWhen(!arbitration.isValid || !input(IS_CSR))
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|