Merge remote-tracking branch 'origin/reworkInstructionCache'
This commit is contained in:
commit
0270ee26fa
56
README.md
56
README.md
|
@ -92,10 +92,14 @@ VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) ->
|
|||
Cyclone II -> 149 Mhz 780 LUT 578 FF
|
||||
|
||||
VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) ->
|
||||
Artix 7 -> 309 Mhz 703 LUT 557 FF
|
||||
Cyclone V -> 152 Mhz 502 ALMs
|
||||
Cyclone IV -> 147 Mhz 1,062 LUT 552 FF
|
||||
Cyclone II -> 120 Mhz 1,072 LUT 551 FF
|
||||
Artix 7 -> 327 Mhz 698 LUT 558 FF
|
||||
Cyclone V -> 158 Mhz 524 ALMs
|
||||
Cyclone IV -> 146 Mhz 1,061 LUT 552 FF
|
||||
|
||||
VexRiscv small and productive with I$ (RV32I, 0.72 DMIPS/Mhz, 4KB-I$) ->
|
||||
Artix 7 -> 331 Mhz 727 LUT 600 FF
|
||||
Cyclone V -> 152 Mhz 536 ALMs
|
||||
Cyclone IV -> 156 Mhz 1,075 LUT 565 FF
|
||||
|
||||
VexRiscv full no cache (RV32IM, 1.22 DMIPS/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
|
||||
Artix 7 -> 310 Mhz 1391 LUT 934 FF
|
||||
|
@ -104,21 +108,19 @@ VexRiscv full no cache (RV32IM, 1.22 DMIPS/Mhz, single cycle barrel shifter, deb
|
|||
Cyclone II -> 108 Mhz 1,939 LUT 959 FF
|
||||
|
||||
VexRiscv full (RV32IM, 1.21 DMIPS/Mhz with cache trashing, 4KB-I$,4KB-D$, single cycle barrel shifter, debug module, catch exceptions, static branch) ->
|
||||
Artix 7 -> 250 Mhz 1911 LUT 1501 FF
|
||||
Cyclone V -> 132 Mhz 1,266 ALMs
|
||||
Cyclone IV -> 127 Mhz 2,733 LUT 1,762 FF
|
||||
Cyclone II -> 103 Mhz 2,791 LUT 1,760 FF
|
||||
Artix 7 -> 249 Mhz 1822 LUT 1362 FF
|
||||
Cyclone V -> 128 Mhz 1,187 ALMs
|
||||
Cyclone IV -> 107 Mhz 2,560 LUT 1,671 FF
|
||||
|
||||
VexRiscv full max perf -> (RV32IM, 1.44 DMIPS/Mhz, 16KB-I$,16KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch prediction in the fetch stage, branch and shift operations done in the Execute stage) ->
|
||||
Artix 7 -> 198 Mhz 1920 LUT 1528 FF
|
||||
Cyclone V -> 90 Mhz 1,261 ALMs
|
||||
Cyclone IV -> 88 Mhz 2,780 LUT 1,788 FF
|
||||
Artix 7 -> 192 Mhz 1858 LUT 1392 FF
|
||||
Cyclone V -> 89 Mhz 1,246 ALMs
|
||||
Cyclone IV -> 85 Mhz 2,673 LUT 1,679 FF
|
||||
|
||||
VexRiscv full with MMU (RV32IM, 1.26 DMIPS/Mhz with cache trashing, 4KB-I$, 4KB-D$, single cycle barrel shifter, debug module, catch exceptions, dynamic branch, MMU) ->
|
||||
Artix 7 -> 223 Mhz 2085 LUT 2020 FF
|
||||
Cyclone V -> 110 Mhz 1,503 ALMs
|
||||
Cyclone IV -> 108 Mhz 3,153 LUT 2,281 FF
|
||||
Cyclone II -> 94 Mhz 3,187 LUT 2,281 FF
|
||||
Artix 7 -> 208 Mhz 2092 LUT 1881 FF
|
||||
Cyclone V - > 112 Mhz 1,435 ALMs
|
||||
Cyclone IV -> 94 Mhz 2,980 LUT 2,169 FF
|
||||
```
|
||||
|
||||
There is a summary of the configuration which produce 1.44 DMIPS :
|
||||
|
@ -293,9 +295,9 @@ You can find some FPGA project which instantiate the Briey SoC there (DE1-SoC, D
|
|||
There is some measurements of Briey SoC timings and area :
|
||||
|
||||
```
|
||||
Artix 7 -> 231 Mhz 3339 LUT 3533 FF
|
||||
Cyclone V -> 124 Mhz 2,264 ALMs
|
||||
Cyclone IV -> 124 Mhz 4,709 LUT 3,716 FF
|
||||
Artix 7 -> 239 Mhz 3227 LUT 3410 FF
|
||||
Cyclone V -> 125 Mhz 2,207 ALMs
|
||||
Cyclone IV -> 112 Mhz 4,594 LUT 3,620
|
||||
```
|
||||
|
||||
## Murax SoC
|
||||
|
@ -695,7 +697,23 @@ This plugin fit in the fetch stage
|
|||
|
||||
#### IBusCachedPlugin
|
||||
|
||||
Single way cache implementation, documentation WIP
|
||||
Simple and light multi way instruction cache.
|
||||
|
||||
| Parameters | type | description |
|
||||
| ------ | ----------- | ------ |
|
||||
| cacheSize | Int | Total storage capacity of the cache |
|
||||
| bytePerLine | Int | Number of byte per cache line |
|
||||
| wayCount | Int | Number of cache way |
|
||||
| twoCycleRam | Boolean | Check the tags values in the decode stage instead of the fetch stage to relax timings |
|
||||
| asyncTagMemory | Boolean | Read the cache tags in a asyncronus manner instead of syncronous one |
|
||||
| addressWidth | Int | Address width, should be 32 |
|
||||
| cpuDataWidth | Int | Cpu data width, should be 32 |
|
||||
| memDataWidth | Int | Memory data width, could potentialy be something else than 32, but only 32 is currently tested |
|
||||
| catchIllegalAccess | Boolean | Catch when an memory access is done on non valid memory address (MMU) |
|
||||
| catchAccessFault | Boolean | Catch when the memeory bus is responding with an error |
|
||||
| catchMemoryTranslationMiss | Boolean | Catch when the MMU miss a TLB |
|
||||
|
||||
Note : If you enable the twoCycleRam and and the wayCount is bigger than one, then the register file plugin should be configured to read the regFile in a asyncronus manner.
|
||||
|
||||
#### DecoderSimplePlugin
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ trait Pipeline {
|
|||
for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
|
||||
stage.arbitration.isStuckByOthers := stage.arbitration.haltByOther || stages.takeRight(stages.length - stageIndex - 1).map(s => s.arbitration.haltItself/* && !s.arbitration.removeIt*/).foldLeft(False)(_ || _)
|
||||
stage.arbitration.isStuck := stage.arbitration.haltItself || stage.arbitration.isStuckByOthers
|
||||
stage.arbitration.isMoving := !stage.arbitration.isStuck && !stage.arbitration.removeIt
|
||||
stage.arbitration.isFiring := stage.arbitration.isValid && !stage.arbitration.isStuck && !stage.arbitration.removeIt
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import spinal.lib._
|
|||
import scala.beans.BeanProperty
|
||||
|
||||
trait JumpService{
|
||||
def createJumpInterface(stage : Stage) : Flow[UInt]
|
||||
def createJumpInterface(stage : Stage, priority : Int = 0) : Flow[UInt]
|
||||
}
|
||||
|
||||
trait DecoderService{
|
||||
|
|
|
@ -48,11 +48,13 @@ class Stage() extends Area{
|
|||
val haltByOther = False //When settable, stuck the instruction, should only be set by something else than the stucked instruction
|
||||
val removeIt = False //When settable, unschedule the instruction as if it was never executed (no side effect)
|
||||
val flushAll = False //When settable, unschedule instructions in the current stage and all prior ones
|
||||
val redoIt = False //Allow to notify that a given instruction in a pipeline is rescheduled
|
||||
val isValid = RegInit(False) //Inform if a instruction is in the current stage
|
||||
val isStuck = Bool //Inform if the instruction is stuck (haltItself || haltByOther)
|
||||
val isStuckByOthers = Bool //Inform if the instruction is stuck by sombody else
|
||||
def isRemoved = removeIt //Inform if the instruction is going to be unschedule the current cycle
|
||||
val isFlushed = Bool //Inform if the instruction is flushed (flushAll set in the current or subsequents stages)
|
||||
val isMoving = Bool //Inform if the instruction is going somewere else (next stage or unscheduled)
|
||||
val isFiring = Bool //Inform if the current instruction will go to the next stage the next cycle (isValid && !isStuck && !removeIt)
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,9 @@ object TestsWorkspace {
|
|||
// ),
|
||||
new IBusCachedPlugin(
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 4096*4,
|
||||
cacheSize = 2048,
|
||||
bytePerLine = 32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -52,7 +51,7 @@ object TestsWorkspace {
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = false
|
||||
),
|
||||
askMemoryTranslation = true,
|
||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
|
@ -95,7 +94,7 @@ object TestsWorkspace {
|
|||
catchIllegalInstruction = true
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
regFileReadyKind = plugin.ASYNC,
|
||||
zeroBoot = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
|
@ -117,7 +116,7 @@ object TestsWorkspace {
|
|||
// new HazardSimplePlugin(false, false, false, false),
|
||||
new MulPlugin,
|
||||
new DivPlugin,
|
||||
new CsrPlugin(CsrPluginConfig.all(0x80000020l)),
|
||||
new CsrPlugin(CsrPluginConfig.all(0x80000020l).copy(deterministicInteruptionEntry = false)),
|
||||
new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||
new BranchPlugin(
|
||||
earlyBranch = true,
|
||||
|
|
|
@ -66,6 +66,7 @@ class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
|
|||
decode.input(config.INSTRUCTION).addAttribute(Verilator.public)
|
||||
decode.input(config.PC).addAttribute(Verilator.public)
|
||||
decode.arbitration.isValid.addAttribute(Verilator.public)
|
||||
decode.arbitration.flushAll.addAttribute(Verilator.public)
|
||||
decode.arbitration.haltItself.addAttribute(Verilator.public)
|
||||
writeBack.input(config.INSTRUCTION) keep() addAttribute(Verilator.public)
|
||||
writeBack.input(config.PC) keep() addAttribute(Verilator.public)
|
||||
|
|
|
@ -57,7 +57,6 @@ object BrieyConfig{
|
|||
cacheSize = 4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -65,7 +64,7 @@ object BrieyConfig{
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = true
|
||||
)
|
||||
// askMemoryTranslation = true,
|
||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
|
|
|
@ -46,6 +46,12 @@ object DhrystoneBench extends App{
|
|||
test = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no"
|
||||
)
|
||||
|
||||
getDmips(
|
||||
name = "GenSmallAndProductiveWithICache",
|
||||
gen = GenSmallAndProductiveICache.main(null),
|
||||
test = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no"
|
||||
)
|
||||
|
||||
|
||||
getDmips(
|
||||
name = "GenFullNoMmuNoCache",
|
||||
|
|
|
@ -11,7 +11,7 @@ object FormalSimple extends App{
|
|||
def cpu() = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new FomalPlugin,
|
||||
new FormalPlugin,
|
||||
new HaltOnExceptionPlugin,
|
||||
new PcManagerSimplePlugin(
|
||||
resetVector = 0x00000000l,
|
||||
|
|
|
@ -21,7 +21,6 @@ object GenFull extends App{
|
|||
cacheSize = 4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -29,7 +28,7 @@ object GenFull extends App{
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = true
|
||||
),
|
||||
askMemoryTranslation = true,
|
||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
|
|
|
@ -21,7 +21,6 @@ object GenFullNoMmu extends App{
|
|||
cacheSize = 4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -29,7 +28,7 @@ object GenFullNoMmu extends App{
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = true
|
||||
)
|
||||
),
|
||||
new DBusCachedPlugin(
|
||||
|
|
|
@ -21,7 +21,6 @@ object GenFullNoMmuMaxPerf extends App{
|
|||
cacheSize = 4096*4,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -29,7 +28,7 @@ object GenFullNoMmuMaxPerf extends App{
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = false,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = true
|
||||
)
|
||||
),
|
||||
new DBusCachedPlugin(
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package vexriscv.demo
|
||||
|
||||
import vexriscv.plugin._
|
||||
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
|
||||
import spinal.core._
|
||||
import vexriscv.ip.InstructionCacheConfig
|
||||
|
||||
/**
|
||||
* Created by spinalvm on 15.06.17.
|
||||
*/
|
||||
object GenSmallAndProductiveICache extends App{
|
||||
def cpu() = new VexRiscv(
|
||||
config = VexRiscvConfig(
|
||||
plugins = List(
|
||||
new PcManagerSimplePlugin(
|
||||
resetVector = 0x00000000l,
|
||||
relaxedPcCalculation = false
|
||||
),
|
||||
new IBusCachedPlugin(
|
||||
config = InstructionCacheConfig(
|
||||
cacheSize = 4096,
|
||||
bytePerLine = 32,
|
||||
wayCount = 1,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
catchIllegalAccess = false,
|
||||
catchAccessFault = false,
|
||||
catchMemoryTranslationMiss = false,
|
||||
asyncTagMemory = false,
|
||||
twoCycleRam = false
|
||||
),
|
||||
askMemoryTranslation = false
|
||||
),
|
||||
new DBusSimplePlugin(
|
||||
catchAddressMisaligned = false,
|
||||
catchAccessFault = false
|
||||
),
|
||||
new CsrPlugin(CsrPluginConfig.smallest),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = false
|
||||
),
|
||||
new RegFilePlugin(
|
||||
regFileReadyKind = plugin.SYNC,
|
||||
zeroBoot = false
|
||||
),
|
||||
new IntAluPlugin,
|
||||
new SrcPlugin(
|
||||
separatedAddSub = false,
|
||||
executeInsertion = true
|
||||
),
|
||||
new LightShifterPlugin,
|
||||
new HazardSimplePlugin(
|
||||
bypassExecute = true,
|
||||
bypassMemory = true,
|
||||
bypassWriteBack = true,
|
||||
bypassWriteBackBuffer = true,
|
||||
pessimisticUseSrc = false,
|
||||
pessimisticWriteRegFile = false,
|
||||
pessimisticAddressMatch = false
|
||||
),
|
||||
new BranchPlugin(
|
||||
earlyBranch = false,
|
||||
catchAddressMisaligned = false,
|
||||
prediction = NONE
|
||||
),
|
||||
new YamlPlugin("cpu0.yaml")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
SpinalVerilog(cpu())
|
||||
}
|
|
@ -49,6 +49,12 @@ object VexRiscvSynthesisBench {
|
|||
SpinalVerilog(wrap(GenSmallAndProductive.cpu()).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val smallAndProductiveWithICache = new Rtl {
|
||||
override def getName(): String = "VexRiscv small and productive with instruction cache"
|
||||
override def getRtlPath(): String = "VexRiscvSmallAndProductiveICache.v"
|
||||
SpinalVerilog(wrap(GenSmallAndProductiveICache.cpu()).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val fullNoMmuNoCache = new Rtl {
|
||||
override def getName(): String = "VexRiscv full no MMU no cache"
|
||||
override def getRtlPath(): String = "VexRiscvFullNoMmuNoCache.v"
|
||||
|
@ -78,8 +84,9 @@ object VexRiscvSynthesisBench {
|
|||
SpinalVerilog(wrap(GenFull.cpu()).setDefinitionName(getRtlPath().split("\\.").head))
|
||||
}
|
||||
|
||||
val rtls = List(smallestNoCsr, smallest, smallAndProductive, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full)
|
||||
// val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache, fullNoMmuNoCache, noCacheNoMmuMaxPerf, fullNoMmuMaxPerf, fullNoMmu, full)
|
||||
// val rtls = List(noCacheNoMmuMaxPerf, fullNoMmuMaxPerf)
|
||||
val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full)
|
||||
|
||||
val targets = XilinxStdTargets(
|
||||
vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
|
||||
|
|
|
@ -39,7 +39,6 @@ object VexRiscvAvalonForSim{
|
|||
cacheSize = 4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -47,7 +46,7 @@ object VexRiscvAvalonForSim{
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = true
|
||||
)
|
||||
// askMemoryTranslation = true,
|
||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
|
|
|
@ -38,7 +38,6 @@ object VexRiscvAvalonWithIntegratedJtag{
|
|||
cacheSize = 4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -46,7 +45,7 @@ object VexRiscvAvalonWithIntegratedJtag{
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = true
|
||||
)
|
||||
// askMemoryTranslation = true,
|
||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
|
|
|
@ -39,7 +39,6 @@ object VexRiscvAxi4WithIntegratedJtag{
|
|||
cacheSize = 4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32,
|
||||
|
@ -47,7 +46,7 @@ object VexRiscvAxi4WithIntegratedJtag{
|
|||
catchAccessFault = true,
|
||||
catchMemoryTranslationMiss = true,
|
||||
asyncTagMemory = false,
|
||||
twoStageLogic = true
|
||||
twoCycleRam = true
|
||||
)
|
||||
// askMemoryTranslation = true,
|
||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||
|
|
|
@ -10,7 +10,6 @@ import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
|
|||
case class InstructionCacheConfig( cacheSize : Int,
|
||||
bytePerLine : Int,
|
||||
wayCount : Int,
|
||||
wrappedMemAccess : Boolean,
|
||||
addressWidth : Int,
|
||||
cpuDataWidth : Int,
|
||||
memDataWidth : Int,
|
||||
|
@ -18,7 +17,10 @@ case class InstructionCacheConfig( cacheSize : Int,
|
|||
catchAccessFault : Boolean,
|
||||
catchMemoryTranslationMiss : Boolean,
|
||||
asyncTagMemory : Boolean,
|
||||
twoStageLogic : Boolean){
|
||||
twoCycleRam : Boolean = false,
|
||||
preResetFlush : Boolean = false){
|
||||
|
||||
def dataOnDecode = twoCycleRam && wayCount > 1
|
||||
def burstSize = bytePerLine*8/memDataWidth
|
||||
def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess
|
||||
|
||||
|
@ -36,7 +38,6 @@ case class InstructionCacheConfig( cacheSize : Int,
|
|||
addressWidth = addressWidth,
|
||||
dataWidth = memDataWidth,
|
||||
burstCountWidth = log2Up(burstSize + 1)).getReadOnlyConfig.copy(
|
||||
linewrapBursts = wrappedMemAccess,
|
||||
useResponse = true,
|
||||
constantBurstBehavior = true
|
||||
)
|
||||
|
@ -47,72 +48,65 @@ case class InstructionCacheConfig( cacheSize : Int,
|
|||
|
||||
case class InstructionCacheCpuPrefetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||
val isValid = Bool
|
||||
val isFiring = Bool
|
||||
val haltIt = Bool
|
||||
val address = UInt(p.addressWidth bit)
|
||||
val pc = UInt(p.addressWidth bit)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isFiring, address)
|
||||
out(isValid, pc)
|
||||
in(haltIt)
|
||||
}
|
||||
}
|
||||
|
||||
case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
|
||||
val isValid = Bool
|
||||
val haltIt = if(!p.twoStageLogic) Bool else null
|
||||
val isStuck = Bool
|
||||
val isStuckByOthers = if(!p.twoStageLogic) Bool else null
|
||||
val address = UInt(p.addressWidth bit)
|
||||
val data = if(!p.twoStageLogic) Bits(32 bit) else null
|
||||
val error = if(!p.twoStageLogic && p.catchAccessFault) Bool else null
|
||||
val mmuBus = if(p.twoStageLogic) MemoryTranslatorBus() else null
|
||||
val pc = UInt(p.addressWidth bits)
|
||||
val data = Bits(p.cpuDataWidth bits)
|
||||
val mmuBus = MemoryTranslatorBus()
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isStuck, address)
|
||||
outWithNull(isStuckByOthers)
|
||||
inWithNull(error,data,haltIt)
|
||||
out(isValid, isStuck, pc)
|
||||
inWithNull(data)
|
||||
slaveWithNull(mmuBus)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
|
||||
require(p.twoStageLogic)
|
||||
val isValid = Bool
|
||||
val haltIt = Bool
|
||||
val isStuck = Bool
|
||||
val isUser = Bool
|
||||
val address = UInt(p.addressWidth bit)
|
||||
val data = Bits(32 bit)
|
||||
val dataAnticipated = Bits(32 bits)
|
||||
val isStuck = Bool
|
||||
val pc = UInt(p.addressWidth bits)
|
||||
val redo = Bool
|
||||
val data = ifGen(p.dataOnDecode) (Bits(p.cpuDataWidth bits))
|
||||
val error = if(p.catchAccessFault) Bool else null
|
||||
val mmuMiss = if(p.catchMemoryTranslationMiss) Bool else null
|
||||
val illegalAccess = if(p.catchIllegalAccess) Bool else null
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isStuck, address, isUser)
|
||||
in(haltIt, data, dataAnticipated)
|
||||
inWithNull(error,mmuMiss,illegalAccess)
|
||||
out(isValid, isUser, isStuck, pc)
|
||||
in(redo)
|
||||
inWithNull(error,mmuMiss,illegalAccess,data)
|
||||
}
|
||||
}
|
||||
|
||||
case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||
val prefetch = InstructionCacheCpuPrefetch(p)
|
||||
val fetch = InstructionCacheCpuFetch(p)
|
||||
val decode = if(p.twoStageLogic) InstructionCacheCpuDecode(p) else null
|
||||
val decode = InstructionCacheCpuDecode(p)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(prefetch)
|
||||
master(fetch)
|
||||
if(p.twoStageLogic) master(decode)
|
||||
master(prefetch, fetch, decode)
|
||||
}
|
||||
}
|
||||
|
||||
case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{
|
||||
val address = UInt(p.addressWidth bit)
|
||||
val size = UInt(log2Up(log2Up(p.bytePerLine) + 1) bits)
|
||||
}
|
||||
|
||||
case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{
|
||||
val data = Bits(32 bit)
|
||||
val data = Bits(p.memDataWidth bit)
|
||||
val error = Bool
|
||||
}
|
||||
|
||||
|
@ -134,9 +128,6 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit
|
|||
mm.readCmd.addr := cmd.address
|
||||
mm.readCmd.prot := "110"
|
||||
mm.readCmd.cache := "1111"
|
||||
if(p.wrappedMemAccess)
|
||||
mm.readCmd.setBurstWRAP()
|
||||
else
|
||||
mm.readCmd.setBurstINCR()
|
||||
cmd.ready := mm.readCmd.ready
|
||||
rsp.valid := mm.readRsp.valid
|
||||
|
@ -173,21 +164,21 @@ case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{
|
|||
|
||||
class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||
import p._
|
||||
assert(wayCount == 1)
|
||||
assert(cpuDataWidth == memDataWidth)
|
||||
assert(cpuDataWidth == memDataWidth, "Need testing")
|
||||
val io = new Bundle{
|
||||
val flush = slave(InstructionCacheFlushBus())
|
||||
// val translator = master(InstructionCacheTranslationBus(p))
|
||||
val cpu = slave(InstructionCacheCpuBus(p))
|
||||
val mem = master(InstructionCacheMemBus(p))
|
||||
}
|
||||
// val haltCpu = False
|
||||
|
||||
val lineWidth = bytePerLine*8
|
||||
val lineCount = cacheSize/bytePerLine
|
||||
val wordWidth = Math.max(memDataWidth,32)
|
||||
val wordWidthLog2 = log2Up(wordWidth)
|
||||
val wordPerLine = lineWidth/wordWidth
|
||||
val memWordPerLine = lineWidth/memDataWidth
|
||||
val bytePerWord = wordWidth/8
|
||||
val bytePerMemWord = memDataWidth/8
|
||||
val wayLineCount = lineCount/wayCount
|
||||
val wayLineLog2 = log2Up(wayLineCount)
|
||||
val wayWordCount = wayLineCount * wordPerLine
|
||||
|
@ -195,44 +186,41 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine)
|
||||
val lineRange = tagRange.low-1 downto log2Up(bytePerLine)
|
||||
val wordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord)
|
||||
val memWordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerMemWord)
|
||||
val memWordToCpuWordRange = log2Up(bytePerMemWord)-1 downto log2Up(bytePerWord)
|
||||
val tagLineRange = tagRange.high downto lineRange.low
|
||||
val lineWordRange = lineRange.high downto wordRange.low
|
||||
|
||||
class LineInfo extends Bundle{
|
||||
case class LineTag() extends Bundle{
|
||||
val valid = Bool
|
||||
val loading = Bool
|
||||
val error = if(catchAccessFault) Bool else null
|
||||
val error = Bool
|
||||
val address = UInt(tagRange.length bit)
|
||||
}
|
||||
|
||||
class LineInfoWithHit extends LineInfo{
|
||||
val hit = Bool
|
||||
|
||||
val ways = Seq.fill(wayCount)(new Area{
|
||||
val tags = Mem(LineTag(),wayLineCount)
|
||||
val datas = Mem(Bits(memDataWidth bits),wayWordCount)
|
||||
|
||||
if(preResetFlush){
|
||||
tags.initBigInt(List.fill(wayLineCount)(BigInt(0)))
|
||||
}
|
||||
|
||||
def LineInfoWithHit(lineInfo : LineInfo, testTag : UInt) = {
|
||||
val ret = new LineInfoWithHit()
|
||||
ret.assignSomeByName(lineInfo)
|
||||
ret.hit := lineInfo.valid && lineInfo.address === testTag
|
||||
ret
|
||||
}
|
||||
|
||||
|
||||
val ways = Array.fill(wayCount)(new Area{
|
||||
val tags = Mem(new LineInfo(),wayLineCount)
|
||||
val datas = Mem(Bits(wordWidth bits),wayWordCount)
|
||||
})
|
||||
|
||||
|
||||
io.cpu.prefetch.haltIt := False
|
||||
|
||||
|
||||
|
||||
|
||||
val lineLoader = new Area{
|
||||
val requestIn = Stream(wrap(new Bundle{
|
||||
val addr = UInt(addressWidth bits)
|
||||
}))
|
||||
val fire = False
|
||||
val valid = RegInit(False) clearWhen(fire)
|
||||
val address = Reg(UInt(addressWidth bits))
|
||||
val hadError = RegInit(False) clearWhen(fire)
|
||||
|
||||
io.cpu.prefetch.haltIt setWhen(valid)
|
||||
|
||||
|
||||
val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(0)
|
||||
val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(if(preResetFlush) wayLineCount else 0)
|
||||
when(!flushCounter.msb){
|
||||
io.cpu.prefetch.haltIt := True
|
||||
flushCounter := flushCounter + 1
|
||||
|
@ -241,6 +229,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
io.cpu.prefetch.haltIt := True
|
||||
}
|
||||
val flushFromInterface = RegInit(False)
|
||||
io.flush.cmd.ready := !(valid || io.cpu.fetch.isValid) //io.cpu.fetch.isValid will avoid bug on first cycle miss
|
||||
when(io.flush.cmd.valid){
|
||||
io.cpu.prefetch.haltIt := True
|
||||
when(io.flush.cmd.ready){
|
||||
|
@ -251,204 +240,110 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
|||
|
||||
io.flush.rsp := flushCounter.msb.rise && flushFromInterface
|
||||
|
||||
val loadingWithErrorReg = if(catchAccessFault) RegInit(False) else null
|
||||
val loadingWithError = if(catchAccessFault) Bool else null
|
||||
if(catchAccessFault) {
|
||||
loadingWithError := loadingWithErrorReg
|
||||
loadingWithErrorReg := loadingWithError
|
||||
|
||||
|
||||
val cmdSent = RegInit(False) setWhen(io.mem.cmd.fire) clearWhen(fire)
|
||||
io.mem.cmd.valid := valid && !cmdSent
|
||||
io.mem.cmd.address := address(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
|
||||
io.mem.cmd.size := log2Up(p.bytePerLine)
|
||||
|
||||
val wayToAllocate = Counter(wayCount, fire)
|
||||
val wordIndex = Reg(UInt(log2Up(memWordPerLine) bits)) init(0)
|
||||
|
||||
|
||||
val write = new Area{
|
||||
val tag = ways.map(_.tags.writePort)
|
||||
val data = ways.map(_.datas.writePort)
|
||||
}
|
||||
|
||||
for(wayId <- 0 until wayCount){
|
||||
val wayHit = wayToAllocate === wayId
|
||||
val tag = write.tag(wayId)
|
||||
tag.valid := ((wayHit && fire) || !flushCounter.msb)
|
||||
tag.address := (flushCounter.msb ? address(lineRange) | flushCounter(flushCounter.high-1 downto 0))
|
||||
tag.data.valid := flushCounter.msb
|
||||
tag.data.error := hadError || io.mem.rsp.error
|
||||
tag.data.address := address(tagRange)
|
||||
|
||||
val data = write.data(wayId)
|
||||
data.valid := io.mem.rsp.valid && wayHit
|
||||
data.address := address(lineRange) @@ wordIndex
|
||||
data.data := io.mem.rsp.data
|
||||
}
|
||||
|
||||
val request = requestIn.stage()
|
||||
|
||||
|
||||
//Send memory requests
|
||||
val memCmdSended = RegInit(False) setWhen(io.mem.cmd.fire)
|
||||
io.mem.cmd.valid := request.valid && !memCmdSended
|
||||
if(wrappedMemAccess)
|
||||
io.mem.cmd.address := request.addr(tagRange.high downto wordRange.low) @@ U(0,wordRange.low bit)
|
||||
else
|
||||
io.mem.cmd.address := request.addr(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
|
||||
|
||||
val wordIndex = Reg(UInt(log2Up(wordPerLine) bit))
|
||||
val loadedWordsNext = Bits(wordPerLine bit)
|
||||
val loadedWords = RegNext(loadedWordsNext)
|
||||
val loadedWordsReadable = RegNext(loadedWords)
|
||||
loadedWordsNext := loadedWords
|
||||
|
||||
val waysDatasWritePort = ways(0).datas.writePort //Not multi ways
|
||||
waysDatasWritePort.valid := io.mem.rsp.valid
|
||||
waysDatasWritePort.address := request.addr(lineRange) @@ wordIndex
|
||||
waysDatasWritePort.data := io.mem.rsp.data
|
||||
when(io.mem.rsp.valid) {
|
||||
wordIndex := wordIndex + 1
|
||||
loadedWordsNext(wordIndex) := True
|
||||
if(catchAccessFault) loadingWithError setWhen io.mem.rsp.error
|
||||
wordIndex := (wordIndex + 1).resized
|
||||
hadError.setWhen(io.mem.rsp.error)
|
||||
when(wordIndex === wordIndex.maxValue) {
|
||||
fire := True
|
||||
}
|
||||
|
||||
val memRspLast = loadedWordsNext === B(loadedWordsNext.range -> true)
|
||||
|
||||
val readyDelay = Reg(UInt(1 bit))
|
||||
when(memRspLast){
|
||||
readyDelay := readyDelay + 1
|
||||
}
|
||||
request.ready := readyDelay === 1
|
||||
|
||||
val waysTagsWritePort = ways(0).tags.writePort //not multi way
|
||||
waysTagsWritePort.valid := io.mem.rsp.valid || !flushCounter.msb
|
||||
waysTagsWritePort.address := Mux(flushCounter.msb,request.addr(lineRange),flushCounter(flushCounter.high-1 downto 0))
|
||||
waysTagsWritePort.data.valid := flushCounter.msb
|
||||
waysTagsWritePort.data.address := request.addr(tagRange)
|
||||
waysTagsWritePort.data.loading := !memRspLast
|
||||
if(catchAccessFault) waysTagsWritePort.data.error := loadingWithError
|
||||
|
||||
|
||||
when(requestIn.ready){
|
||||
memCmdSended := False
|
||||
wordIndex := requestIn.addr(wordRange)
|
||||
loadedWords := 0
|
||||
loadedWordsReadable := 0
|
||||
readyDelay := 0
|
||||
if(catchAccessFault) loadingWithErrorReg := False
|
||||
}
|
||||
}
|
||||
|
||||
val task = if(!twoStageLogic) new Area{
|
||||
val waysHitValid = False
|
||||
val waysHitError = Bool.assignDontCare()
|
||||
val waysHitWord = Bits(wordWidth bit)
|
||||
|
||||
val waysRead = for(way <- ways) yield new Area{
|
||||
val readAddress = Mux(io.cpu.fetch.isStuck,io.cpu.fetch.address,io.cpu.prefetch.address) //TODO FMAX
|
||||
val tag = if(asyncTagMemory)
|
||||
way.tags.readAsync(io.cpu.fetch.address(lineRange),writeFirst)
|
||||
else
|
||||
way.tags.readSync(readAddress(lineRange),readUnderWrite = readFirst)
|
||||
|
||||
val data = way.datas.readSync(readAddress(lineRange.high downto wordRange.low))
|
||||
waysHitWord := data //Not applicable to multi way
|
||||
when(tag.valid && tag.address === io.cpu.fetch.address(tagRange)) {
|
||||
waysHitValid := True
|
||||
if(catchAccessFault) waysHitError := tag.error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val hit = waysHitValid && !(waysRead(0).tag.loading && !(if(asyncTagMemory) lineLoader.loadedWords else RegNext(lineLoader.loadedWords))(io.cpu.fetch.address(wordRange)))
|
||||
io.cpu.fetch.haltIt := io.cpu.fetch.isValid && !hit
|
||||
io.cpu.fetch.data := waysHitWord
|
||||
if(catchAccessFault) io.cpu.fetch.error := waysRead(0).tag.error
|
||||
lineLoader.requestIn.valid := io.cpu.fetch.isValid && !hit //TODO avoid duplicated request
|
||||
lineLoader.requestIn.addr := io.cpu.fetch.address
|
||||
} else new Area{
|
||||
//Long readValidPath
|
||||
// def writeFirstMemWrap[T <: Data](readValid : Bool, readAddress : UInt, lastAddress : UInt, readData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = {
|
||||
// val hit = writeValid && (readValid ? readAddress | lastAddress) === writeAddress
|
||||
// val overrideValid = RegInit(False) clearWhen(readValid) setWhen(hit)
|
||||
// val overrideValue = RegNextWhen(writeData,hit)
|
||||
// overrideValid ? overrideValue | readData
|
||||
// }
|
||||
|
||||
//shot readValid path
|
||||
def writeFirstMemWrap[T <: Data](readValid : Bool, readLastAddress : UInt, readData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = {
|
||||
val writeSample = readValid || (writeValid && writeAddress === readLastAddress)
|
||||
val writeValidReg = RegNextWhen(writeValid,writeSample)
|
||||
val writeAddressReg = RegNextWhen(writeAddress,writeSample)
|
||||
val writeDataReg = RegNextWhen(writeData,writeSample)
|
||||
(writeValidReg && writeAddressReg === readLastAddress) ? writeDataReg | readData
|
||||
val fetchStage = new Area{
|
||||
val read = new Area{
|
||||
val waysValues = for(way <- ways) yield new Area{
|
||||
val tag = if(asyncTagMemory) {
|
||||
way.tags.readAsync(io.cpu.fetch.pc(lineRange))
|
||||
}else {
|
||||
way.tags.readSync(io.cpu.prefetch.pc(lineRange), !io.cpu.fetch.isStuck)
|
||||
}
|
||||
|
||||
//Long sample path
|
||||
// def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,lastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) : (T,T) = {
|
||||
// val hit = writeValid && (sample ? sampleAddress | lastAddress) === writeAddress
|
||||
// val bypass = hit ? writeData | readData
|
||||
// val reg = RegNextWhen(bypass,sample || hit)
|
||||
// (reg,bypass)
|
||||
// }
|
||||
|
||||
//Short sample path
|
||||
def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) = {
|
||||
val preWrite = (writeValid && sampleAddress === writeAddress)
|
||||
val postWrite = (writeValid && sampleLastAddress === writeAddress)
|
||||
val bypass = (!sample || preWrite) ? writeData | readData
|
||||
val regEn = sample || postWrite
|
||||
val reg = RegNextWhen(bypass,regEn)
|
||||
(reg,bypass,regEn,preWrite,postWrite)
|
||||
val data = way.datas.readSync(io.cpu.prefetch.pc(lineRange.high downto memWordRange.low), !io.cpu.fetch.isStuck)
|
||||
}
|
||||
// def writeFirstRegWrap[T <: Data](sample : Bool, sampleAddress : UInt,sampleLastAddress : UInt, readData : T, writeValid : Bool, writeAddress : UInt, writeData : T) = {
|
||||
// val bypass = (!sample || (writeValid && sampleAddress === writeAddress)) ? writeData | readData
|
||||
// val regEn = sample || (writeValid && sampleLastAddress === writeAddress)
|
||||
// val reg = RegNextWhen(bypass,regEn)
|
||||
// (reg,bypass,regEn,False,False)
|
||||
// }
|
||||
require(wayCount == 1)
|
||||
val memRead = new Area{
|
||||
val way = ways(0)
|
||||
val tag = if(asyncTagMemory)
|
||||
way.tags.readAsync(io.cpu.fetch.address(lineRange),writeFirst)
|
||||
else
|
||||
writeFirstMemWrap(
|
||||
readValid = !io.cpu.fetch.isStuck,
|
||||
// readAddress = io.cpu.prefetch.address(lineRange),
|
||||
readLastAddress = io.cpu.fetch.address(lineRange),
|
||||
readData = way.tags.readSync(io.cpu.prefetch.address(lineRange),enable = !io.cpu.fetch.isStuck),
|
||||
writeValid = lineLoader.waysTagsWritePort.valid,
|
||||
writeAddress = lineLoader.waysTagsWritePort.address,
|
||||
writeData = lineLoader.waysTagsWritePort.data
|
||||
)
|
||||
|
||||
val data = writeFirstMemWrap(
|
||||
readValid = !io.cpu.fetch.isStuck,
|
||||
// readAddress = io.cpu.prefetch.address(lineWordRange),
|
||||
readLastAddress = io.cpu.fetch.address(lineWordRange),
|
||||
readData = way.datas.readSync(io.cpu.prefetch.address(lineWordRange),enable = !io.cpu.fetch.isStuck),
|
||||
writeValid = lineLoader.waysDatasWritePort.valid,
|
||||
writeAddress = lineLoader.waysDatasWritePort.address,
|
||||
writeData = lineLoader.waysDatasWritePort.data
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
val tag = writeFirstRegWrap(
|
||||
sample = !io.cpu.decode.isStuck,
|
||||
sampleAddress = io.cpu.fetch.address(lineRange),
|
||||
sampleLastAddress = io.cpu.decode.address(lineRange),
|
||||
readData = LineInfoWithHit(memRead.tag,io.cpu.fetch.address(tagRange)),
|
||||
writeValid = lineLoader.waysTagsWritePort.valid,
|
||||
writeAddress = lineLoader.waysTagsWritePort.address,
|
||||
writeData = LineInfoWithHit(lineLoader.waysTagsWritePort.data,io.cpu.fetch.address(tagRange)) //TODO wrong address src
|
||||
)._1
|
||||
val hit = if(!twoCycleRam) new Area{
|
||||
val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuBus.rsp.physicalAddress(tagRange))
|
||||
val valid = Cat(hits).orR
|
||||
val id = OHToUInt(hits)
|
||||
val error = read.waysValues.map(_.tag.error).read(id)
|
||||
val data = read.waysValues.map(_.data).read(id)
|
||||
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
|
||||
io.cpu.fetch.data := word
|
||||
} else null
|
||||
|
||||
val (data,dataRegIn,dataRegEn,dataPreWrite,dataPostWrite) = writeFirstRegWrap(
|
||||
sample = !io.cpu.decode.isStuck,
|
||||
sampleAddress = io.cpu.fetch.address(lineWordRange),
|
||||
sampleLastAddress = io.cpu.decode.address(lineWordRange),
|
||||
readData = memRead.data,
|
||||
writeValid = lineLoader.waysDatasWritePort.valid,
|
||||
writeAddress = lineLoader.waysDatasWritePort.address,
|
||||
writeData = lineLoader.waysDatasWritePort.data
|
||||
)
|
||||
if(twoCycleRam && wayCount == 1){
|
||||
io.cpu.fetch.data := read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
|
||||
}
|
||||
|
||||
io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid
|
||||
io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.address
|
||||
io.cpu.fetch.mmuBus.cmd.virtualAddress := io.cpu.fetch.pc
|
||||
io.cpu.fetch.mmuBus.cmd.bypassTranslation := False
|
||||
val mmuRsp = RegNextWhen(io.cpu.fetch.mmuBus.rsp,!io.cpu.decode.isStuck)
|
||||
}
|
||||
|
||||
val hit = tag.valid && tag.address === mmuRsp.physicalAddress(tagRange) && !(tag.loading && !lineLoader.loadedWords(mmuRsp.physicalAddress(wordRange)))
|
||||
|
||||
io.cpu.decode.haltIt := io.cpu.decode.isValid && !hit //TODO PERF not halit it when removed, Should probably be applyed in many other places
|
||||
io.cpu.decode.data := data
|
||||
// io.cpu.decode.dataAnticipated := dataRegEn ? dataRegIn | data
|
||||
io.cpu.decode.dataAnticipated := io.cpu.decode.isStuck ? Mux(dataPostWrite,lineLoader.waysDatasWritePort.data,data) | Mux(dataPreWrite,lineLoader.waysDatasWritePort.data,memRead.data)
|
||||
if(catchAccessFault) io.cpu.decode.error := tag.error
|
||||
val decodeStage = new Area{
|
||||
def stage[T <: Data](that : T) = RegNextWhen(that,!io.cpu.decode.isStuck)
|
||||
val mmuRsp = stage(io.cpu.fetch.mmuBus.rsp)
|
||||
|
||||
val hit = if(!twoCycleRam) new Area{
|
||||
val valid = stage(fetchStage.hit.valid)
|
||||
val error = stage(fetchStage.hit.error)
|
||||
} else new Area{
|
||||
val tags = fetchStage.read.waysValues.map(way => stage(way.tag))
|
||||
val hits = tags.map(tag => tag.valid && tag.address === mmuRsp.physicalAddress(tagRange))
|
||||
val valid = Cat(hits).orR
|
||||
val id = OHToUInt(hits)
|
||||
val error = tags(id).error
|
||||
if(dataOnDecode) {
|
||||
val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id)
|
||||
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange))
|
||||
io.cpu.decode.data := word
|
||||
}
|
||||
}
|
||||
|
||||
io.cpu.decode.redo := io.cpu.decode.isValid && !hit.valid
|
||||
when(io.cpu.decode.redo){
|
||||
io.cpu.prefetch.haltIt := True
|
||||
lineLoader.valid := True
|
||||
lineLoader.address := mmuRsp.physicalAddress //Could be optimise if mmu not used
|
||||
}
|
||||
|
||||
if(catchAccessFault) io.cpu.decode.error := hit.error
|
||||
if(catchMemoryTranslationMiss) io.cpu.decode.mmuMiss := mmuRsp.miss
|
||||
if(catchIllegalAccess) io.cpu.decode.illegalAccess := !mmuRsp.allowExecute || (io.cpu.decode.isUser && !mmuRsp.allowUser)
|
||||
|
||||
lineLoader.requestIn.valid := io.cpu.decode.isValid && !hit && !mmuRsp.miss//TODO avoid duplicated request
|
||||
lineLoader.requestIn.addr := mmuRsp.physicalAddress
|
||||
}
|
||||
|
||||
io.flush.cmd.ready := !(lineLoader.request.valid || io.cpu.fetch.isValid || (if(twoStageLogic) io.cpu.decode.isValid else False))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,9 @@ case class CsrPluginConfig(
|
|||
minstretAccess : CsrAccess,
|
||||
ucycleAccess : CsrAccess,
|
||||
wfiGen : Boolean,
|
||||
ecallGen : Boolean
|
||||
ecallGen : Boolean,
|
||||
deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes
|
||||
|
||||
){
|
||||
assert(!ucycleAccess.canWrite)
|
||||
}
|
||||
|
@ -431,10 +433,51 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio
|
|||
|
||||
|
||||
|
||||
val interrupt = ((mip.MSIP && mie.MSIE) || (mip.MEIP && mie.MEIE) || (mip.MTIP && mie.MTIE)) && mstatus.MIE && allowInterrupts
|
||||
val interruptRequest = ((mip.MSIP && mie.MSIE) || (mip.MEIP && mie.MEIE) || (mip.MTIP && mie.MTIE)) && mstatus.MIE
|
||||
val interrupt = interruptRequest && allowInterrupts
|
||||
val exception = if(exceptionPortCtrl != null) exceptionPortCtrl.exceptionValids.last && allowException else False
|
||||
val writeBackWasWfi = if(wfiGen) RegNext(writeBack.arbitration.isFiring && writeBack.input(ENV_CTRL) === EnvCtrlEnum.WFI) init(False) else False
|
||||
|
||||
|
||||
|
||||
val deteriministicLogic = if(deterministicInteruptionEntry) new Area{
|
||||
val counter = Reg(UInt(4 bits)) init(0)
|
||||
|
||||
when(!interruptRequest || !mstatus.MIE){
|
||||
counter := 0
|
||||
} otherwise {
|
||||
when(counter < 6){
|
||||
when(writeBack.arbitration.isFiring){
|
||||
counter := counter + 1
|
||||
}
|
||||
}
|
||||
val counterPlusPending = counter + CountOne(stages.tail.map(_.arbitration.isValid))
|
||||
when(counterPlusPending < 6){
|
||||
inhibateInterrupts()
|
||||
}
|
||||
}
|
||||
}
|
||||
// val deteriministicLogic = if(deterministicInteruptionEntry) new Area{
|
||||
// val counter = Reg(UInt(4 bits)) init(0)
|
||||
// val limit = Reg(UInt(4 bits)) init(5)
|
||||
// when(interruptRequest.rise()){
|
||||
// limit := CountOne(stages.tail.map(_.arbitration.isValid)).resized
|
||||
// }
|
||||
// when(!interruptRequest || !mstatus.MIE){
|
||||
// counter := 0
|
||||
// } otherwise {
|
||||
// when(counter < limit){
|
||||
// when(writeBack.arbitration.isFiring){
|
||||
// counter := counter + 1
|
||||
// }
|
||||
// }
|
||||
// val counterPlusPending = counter + CountOne(stages.tail.map(_.arbitration.isValid)) + 1
|
||||
// when(counterPlusPending < limit){
|
||||
// inhibateInterrupts()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
//Interrupt/Exception entry logic
|
||||
pipelineLiberator.enable setWhen(interrupt)
|
||||
when(exception || (interrupt && pipelineLiberator.done)){
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package vexriscv.plugin
|
||||
|
||||
import spinal.lib.com.jtag.Jtag
|
||||
import spinal.lib.system.debugger.{SystemDebugger, JtagBridge, SystemDebuggerConfig}
|
||||
import vexriscv.plugin.IntAluPlugin.{AluCtrlEnum, ALU_CTRL}
|
||||
import spinal.lib.system.debugger.{JtagBridge, SystemDebugger, SystemDebuggerConfig}
|
||||
import vexriscv.plugin.IntAluPlugin.{ALU_CTRL, AluCtrlEnum}
|
||||
import vexriscv._
|
||||
import vexriscv.ip._
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
import spinal.lib.bus.amba3.apb.{Apb3Config, Apb3}
|
||||
import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
|
||||
import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config}
|
||||
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
|
||||
|
||||
case class DebugExtensionCmd() extends Bundle{
|
||||
|
@ -92,10 +94,18 @@ case class DebugExtensionIo() extends Bundle with IMasterSlave{
|
|||
}
|
||||
}
|
||||
|
||||
class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
||||
|
||||
//Allow to avoid instruction cache plugin to be confused by new instruction poping in the pipeline
|
||||
trait InstructionInjector{
|
||||
def isInjecting(stage : Stage) : Bool
|
||||
}
|
||||
|
||||
class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] with InstructionInjector {
|
||||
|
||||
var io : DebugExtensionIo = null
|
||||
|
||||
val injectionAsks = ArrayBuffer[(Stage, Bool)]()
|
||||
var isInjectingOnDecode : Bool = null
|
||||
override def isInjecting(stage: Stage) : Bool = if(stage == pipeline.decode) isInjectingOnDecode else False
|
||||
|
||||
object IS_EBREAK extends Stageable(Bool)
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
|
@ -114,13 +124,15 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
|||
SRC2_CTRL -> Src2CtrlEnum.PC,
|
||||
ALU_CTRL -> AluCtrlEnum.ADD_SUB //Used to get the PC value in busReadDataReg
|
||||
))
|
||||
|
||||
isInjectingOnDecode = Bool()
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
debugClockDomain {pipeline plug new Area{
|
||||
val logic = debugClockDomain {pipeline plug new Area{
|
||||
val insertDecodeInstruction = False
|
||||
val firstCycle = RegNext(False) setWhen (io.bus.cmd.ready)
|
||||
val secondCycle = RegNext(firstCycle)
|
||||
|
@ -168,12 +180,21 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
|||
}
|
||||
}
|
||||
|
||||
//Assign the bus write data into the register who drive the decode instruction, even if it need to cross some hierarchy (caches)
|
||||
Component.current.addPrePopTask(() => {
|
||||
val reg = decode.input(INSTRUCTION).getDrivingReg
|
||||
reg.component.rework {
|
||||
//Check if the decode instruction is driven by a register
|
||||
val instructionDriver = try {decode.input(INSTRUCTION).getDrivingReg} catch { case _ : Throwable => null}
|
||||
if(instructionDriver != null){ //If yes =>
|
||||
//Insert the instruction by writing the "fetch to decode instruction register",
|
||||
// Work even if it need to cross some hierarchy (caches)
|
||||
instructionDriver.component.rework {
|
||||
when(insertDecodeInstruction.pull()) {
|
||||
reg := io.bus.cmd.data.pull()
|
||||
instructionDriver := io.bus.cmd.data.pull()
|
||||
}
|
||||
}
|
||||
} else{
|
||||
//Insert the instruction via a mux in the decode stage
|
||||
when(RegNext(insertDecodeInstruction)){
|
||||
decode.input(INSTRUCTION) := RegNext(io.bus.cmd.data)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -193,7 +214,9 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
|||
when(stepIt && prefetch.arbitration.isFiring) {
|
||||
haltIt := True
|
||||
}
|
||||
|
||||
when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) {
|
||||
haltIt := False
|
||||
}
|
||||
io.resetOut := RegNext(resetIt)
|
||||
|
||||
if(serviceExist(classOf[InterruptionInhibitor])) {
|
||||
|
@ -207,5 +230,8 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
|||
}
|
||||
}
|
||||
}}
|
||||
|
||||
|
||||
isInjectingOnDecode := RegNext(logic.insertDecodeInstruction) init(False)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ case class RvfiPort() extends Bundle with IMasterSlave {
|
|||
//2) JALR => clear PC(0)
|
||||
//3) input(INSTRUCTION)(5) REGFILE_WRITE_VALID memory read with exception would not fire properly
|
||||
|
||||
class FomalPlugin extends Plugin[VexRiscv]{
|
||||
class FormalPlugin extends Plugin[VexRiscv]{
|
||||
|
||||
var rvfi : RvfiPort = null
|
||||
|
|
@ -28,11 +28,15 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService {
|
|||
stages.head.insert(FORMAL_HALT) := False
|
||||
stages.foreach(stage => {
|
||||
val stagePorts = exceptionPortsInfos.filter(_.stage == stage)
|
||||
if(stagePorts.nonEmpty)
|
||||
when(stagePorts.map(_.port.valid).orR){
|
||||
if(stagePorts.nonEmpty) {
|
||||
when(stagePorts.map(info => info.port.valid).orR) {
|
||||
stage.output(FORMAL_HALT) := True
|
||||
stage.arbitration.haltItself := True
|
||||
}
|
||||
for(stage <- stages){
|
||||
stage.output(FORMAL_HALT) clearWhen(stage.arbitration.isFlushed)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,17 @@ import spinal.lib._
|
|||
|
||||
class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : Boolean = false, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] {
|
||||
import config._
|
||||
assert(twoStageLogic || !askMemoryTranslation)
|
||||
|
||||
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._
|
||||
|
@ -29,6 +31,9 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
|||
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)
|
||||
|
@ -47,6 +52,9 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
|||
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
|
||||
|
@ -60,33 +68,26 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
|||
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.isFiring := prefetch.arbitration.isFiring
|
||||
cache.io.cpu.prefetch.address := prefetch.output(PC)
|
||||
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
|
||||
if(!twoStageLogic) cache.io.cpu.fetch.isStuckByOthers := fetch.arbitration.isStuckByOthers
|
||||
cache.io.cpu.fetch.address := fetch.output(PC)
|
||||
if(!twoStageLogic) {
|
||||
fetch.arbitration.haltItself setWhen (cache.io.cpu.fetch.haltIt)
|
||||
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
|
||||
}else {
|
||||
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
|
||||
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
|
||||
|
@ -94,33 +95,41 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
|||
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
|
||||
cache.io.cpu.fetch.mmuBus.rsp.miss := False
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(twoStageLogic){
|
||||
cache.io.cpu.decode.isValid := decode.arbitration.isValid && RegNextWhen(fetch.arbitration.isValid, !decode.arbitration.isStuck) //avoid inserted instruction from debug module
|
||||
decode.arbitration.haltItself.setWhen(cache.io.cpu.decode.haltIt)
|
||||
cache.io.cpu.decode.isStuck := decode.arbitration.isStuck
|
||||
cache.io.cpu.decode.isUser := (if(privilegeService != null) privilegeService.isUser(writeBack) else False)
|
||||
cache.io.cpu.decode.address := decode.input(PC)
|
||||
if(dataOnDecode){
|
||||
decode.insert(INSTRUCTION) := cache.io.cpu.decode.data
|
||||
decode.insert(INSTRUCTION_ANTICIPATED) := cache.io.cpu.decode.dataAnticipated
|
||||
decode.insert(INSTRUCTION_READY) := !cache.io.cpu.decode.haltIt
|
||||
}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 := cache.io.cpu.decode.redo
|
||||
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){
|
||||
if(catchAccessFault) {
|
||||
if (!twoStageLogic) fetch.insert(IBUS_ACCESS_ERROR) := cache.io.cpu.fetch.error
|
||||
if (twoStageLogic) decode.insert(IBUS_ACCESS_ERROR) := cache.io.cpu.decode.error
|
||||
}
|
||||
|
||||
val accessFault = if(catchAccessFault) decode.input(IBUS_ACCESS_ERROR) else False
|
||||
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 && (accessFault || mmuMiss || illegalAccess)
|
||||
decodeExceptionPort.valid := decode.arbitration.isValid && ownDecode && (accessFault || mmuMiss || illegalAccess)
|
||||
decodeExceptionPort.code := mmuMiss ? U(14) | 1
|
||||
decodeExceptionPort.badAddr := decode.input(PC)
|
||||
}
|
||||
|
@ -130,11 +139,10 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
|||
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
|
||||
} otherwise {
|
||||
decode.arbitration.flushAll := True
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import scala.collection.mutable.ArrayBuffer
|
|||
class PcManagerSimplePlugin(resetVector : BigInt,
|
||||
relaxedPcCalculation : Boolean = false) extends Plugin[VexRiscv] with JumpService{
|
||||
//FetchService interface
|
||||
case class JumpInfo(interface : Flow[UInt], stage: Stage)
|
||||
case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
|
||||
val jumpInfos = ArrayBuffer[JumpInfo]()
|
||||
override def createJumpInterface(stage: Stage): Flow[UInt] = {
|
||||
override def createJumpInterface(stage: Stage, priority : Int = 0): Flow[UInt] = {
|
||||
val interface = Flow(UInt(32 bits))
|
||||
jumpInfos += JumpInfo(interface,stage)
|
||||
jumpInfos += JumpInfo(interface,stage, priority)
|
||||
interface
|
||||
}
|
||||
var prefetchExceptionPort : Flow[ExceptionCause] = null
|
||||
|
@ -59,7 +59,10 @@ class PcManagerSimplePlugin(resetVector : BigInt,
|
|||
|
||||
//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 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)
|
||||
|
||||
|
|
|
@ -199,6 +199,8 @@ public:
|
|||
|
||||
|
||||
Workspace(string name){
|
||||
// setIStall(false);
|
||||
// setDStall(false);
|
||||
staticMutex.lock();
|
||||
testsCounter++;
|
||||
staticMutex.unlock();
|
||||
|
@ -358,6 +360,10 @@ public:
|
|||
|
||||
top->reset = 1;
|
||||
top->eval();
|
||||
top->clk = 1;
|
||||
top->eval();
|
||||
top->clk = 0;
|
||||
top->eval();
|
||||
#ifdef CSR
|
||||
top->timerInterrupt = 0;
|
||||
top->externalInterrupt = 1;
|
||||
|
@ -400,7 +406,11 @@ public:
|
|||
|
||||
|
||||
#ifndef REF_TIME
|
||||
#ifndef MTIME_INSTR_FACTOR
|
||||
mTime = i/2;
|
||||
#else
|
||||
mTime += top->VexRiscv->writeBack_arbitration_isFiring*MTIME_INSTR_FACTOR;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CSR
|
||||
top->timerInterrupt = mTime >= mTimeCmp ? 1 : 0;
|
||||
|
@ -435,7 +445,7 @@ public:
|
|||
for(SimElement* simElement : simElements) simElement->preCycle();
|
||||
|
||||
if(withInstructionReadCheck){
|
||||
if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself){
|
||||
if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself && !top->VexRiscv->decode_arbitration_flushAll){
|
||||
uint32_t expectedData;
|
||||
bool dummy;
|
||||
iBusAccess(top->VexRiscv->decode_PC, &expectedData, &dummy);
|
||||
|
@ -598,7 +608,7 @@ public:
|
|||
virtual void preCycle(){
|
||||
if (top->iBus_cmd_valid && top->iBus_cmd_ready && pendingCount == 0) {
|
||||
assertEq(top->iBus_cmd_payload_address & 3,0);
|
||||
pendingCount = 8;
|
||||
pendingCount = (1 << top->iBus_cmd_payload_size)/4;
|
||||
address = top->iBus_cmd_payload_address;
|
||||
}
|
||||
}
|
||||
|
@ -610,7 +620,7 @@ public:
|
|||
ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error);
|
||||
top->iBus_rsp_payload_error = error;
|
||||
pendingCount--;
|
||||
address = (address & ~0x1F) + ((address + 4) & 0x1F);
|
||||
address = address + 4;
|
||||
top->iBus_rsp_valid = 1;
|
||||
}
|
||||
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && pendingCount == 0;
|
||||
|
@ -1606,10 +1616,11 @@ string riscvTestDiv[] = {
|
|||
};
|
||||
|
||||
string freeRtosTests[] = {
|
||||
"AltBlock", "AltQTest", "AltBlckQ", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek",
|
||||
"AltBlock", "AltQTest", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek",
|
||||
"QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic",
|
||||
"GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1"
|
||||
//"flop", "sp_flop" // <- Simple test
|
||||
// "AltBlckQ" ???
|
||||
};
|
||||
|
||||
|
||||
|
@ -1714,7 +1725,7 @@ int main(int argc, char **argv, char **env) {
|
|||
#ifdef CSR
|
||||
uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u ,
|
||||
8,6,9,6,10,4,11,4, 12,13,0, 14,2, 15,5,16,17,1 };
|
||||
redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(4e4);)
|
||||
redo(REDO,TestX28("machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).noInstructionReadCheck()->run(10e4);)
|
||||
#endif
|
||||
#ifdef MMU
|
||||
uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5,
|
||||
|
|
|
@ -19,7 +19,9 @@ REDO?=10
|
|||
REF=no
|
||||
TRACE_WITH_TIME=no
|
||||
REF_TIME=no
|
||||
THREAD_COUNT=4
|
||||
THREAD_COUNT?=4
|
||||
MTIME_INSTR_FACTOR?=no
|
||||
|
||||
|
||||
ADDCFLAGS += -CFLAGS -DIBUS_${IBUS}
|
||||
ADDCFLAGS += -CFLAGS -DDBUS_${DBUS}
|
||||
|
@ -27,10 +29,15 @@ ADDCFLAGS += -CFLAGS -DREDO=${REDO}
|
|||
ADDCFLAGS += -CFLAGS -pthread
|
||||
|
||||
ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT}
|
||||
|
||||
ifeq ($(DHRYSTONE),yes)
|
||||
ADDCFLAGS += -CFLAGS -DDHRYSTONE
|
||||
endif
|
||||
|
||||
ifneq ($(MTIME_INSTR_FACTOR),no)
|
||||
ADDCFLAGS += -CFLAGS -DMTIME_INSTR_FACTOR=${MTIME_INSTR_FACTOR}
|
||||
endif
|
||||
|
||||
ifeq ($(TRACE),yes)
|
||||
VERILATOR_ARGS += --trace
|
||||
ADDCFLAGS += -CFLAGS -DTRACE
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
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
|
||||
),
|
||||
askMemoryTranslation = false
|
||||
),
|
||||
new FormalPlugin,
|
||||
new HaltOnExceptionPlugin,
|
||||
new PcManagerSimplePlugin(
|
||||
resetVector = 0x00000000l,
|
||||
relaxedPcCalculation = false
|
||||
),
|
||||
// new IBusSimplePlugin(
|
||||
// interfaceKeepData = false,
|
||||
// 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))))
|
||||
//
|
||||
// } 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
|
||||
}
|
||||
SpinalConfig(
|
||||
defaultConfigForClockDomains = ClockDomainConfig(
|
||||
resetKind = spinal.core.SYNC,
|
||||
resetActiveLevel = spinal.core.HIGH
|
||||
),
|
||||
inlineRom = true
|
||||
).generateVerilog(wrap(cpu()))
|
||||
}
|
Loading…
Reference in New Issue