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
|
Cyclone II -> 149 Mhz 780 LUT 578 FF
|
||||||
|
|
||||||
VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) ->
|
VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) ->
|
||||||
Artix 7 -> 309 Mhz 703 LUT 557 FF
|
Artix 7 -> 327 Mhz 698 LUT 558 FF
|
||||||
Cyclone V -> 152 Mhz 502 ALMs
|
Cyclone V -> 158 Mhz 524 ALMs
|
||||||
Cyclone IV -> 147 Mhz 1,062 LUT 552 FF
|
Cyclone IV -> 146 Mhz 1,061 LUT 552 FF
|
||||||
Cyclone II -> 120 Mhz 1,072 LUT 551 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) ->
|
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
|
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
|
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) ->
|
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
|
Artix 7 -> 249 Mhz 1822 LUT 1362 FF
|
||||||
Cyclone V -> 132 Mhz 1,266 ALMs
|
Cyclone V -> 128 Mhz 1,187 ALMs
|
||||||
Cyclone IV -> 127 Mhz 2,733 LUT 1,762 FF
|
Cyclone IV -> 107 Mhz 2,560 LUT 1,671 FF
|
||||||
Cyclone II -> 103 Mhz 2,791 LUT 1,760 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) ->
|
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
|
Artix 7 -> 192 Mhz 1858 LUT 1392 FF
|
||||||
Cyclone V -> 90 Mhz 1,261 ALMs
|
Cyclone V -> 89 Mhz 1,246 ALMs
|
||||||
Cyclone IV -> 88 Mhz 2,780 LUT 1,788 FF
|
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) ->
|
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
|
Artix 7 -> 208 Mhz 2092 LUT 1881 FF
|
||||||
Cyclone V -> 110 Mhz 1,503 ALMs
|
Cyclone V - > 112 Mhz 1,435 ALMs
|
||||||
Cyclone IV -> 108 Mhz 3,153 LUT 2,281 FF
|
Cyclone IV -> 94 Mhz 2,980 LUT 2,169 FF
|
||||||
Cyclone II -> 94 Mhz 3,187 LUT 2,281 FF
|
|
||||||
```
|
```
|
||||||
|
|
||||||
There is a summary of the configuration which produce 1.44 DMIPS :
|
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 :
|
There is some measurements of Briey SoC timings and area :
|
||||||
|
|
||||||
```
|
```
|
||||||
Artix 7 -> 231 Mhz 3339 LUT 3533 FF
|
Artix 7 -> 239 Mhz 3227 LUT 3410 FF
|
||||||
Cyclone V -> 124 Mhz 2,264 ALMs
|
Cyclone V -> 125 Mhz 2,207 ALMs
|
||||||
Cyclone IV -> 124 Mhz 4,709 LUT 3,716 FF
|
Cyclone IV -> 112 Mhz 4,594 LUT 3,620
|
||||||
```
|
```
|
||||||
|
|
||||||
## Murax SoC
|
## Murax SoC
|
||||||
|
@ -695,7 +697,23 @@ This plugin fit in the fetch stage
|
||||||
|
|
||||||
#### IBusCachedPlugin
|
#### 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
|
#### DecoderSimplePlugin
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ trait Pipeline {
|
||||||
for(stageIndex <- 0 until stages.length; stage = stages(stageIndex)){
|
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.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.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
|
stage.arbitration.isFiring := stage.arbitration.isValid && !stage.arbitration.isStuck && !stage.arbitration.removeIt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import spinal.lib._
|
||||||
import scala.beans.BeanProperty
|
import scala.beans.BeanProperty
|
||||||
|
|
||||||
trait JumpService{
|
trait JumpService{
|
||||||
def createJumpInterface(stage : Stage) : Flow[UInt]
|
def createJumpInterface(stage : Stage, priority : Int = 0) : Flow[UInt]
|
||||||
}
|
}
|
||||||
|
|
||||||
trait DecoderService{
|
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 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 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 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 isValid = RegInit(False) //Inform if a instruction is in the current stage
|
||||||
val isStuck = Bool //Inform if the instruction is stuck (haltItself || haltByOther)
|
val isStuck = Bool //Inform if the instruction is stuck (haltItself || haltByOther)
|
||||||
val isStuckByOthers = Bool //Inform if the instruction is stuck by sombody else
|
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
|
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 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)
|
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(
|
new IBusCachedPlugin(
|
||||||
config = InstructionCacheConfig(
|
config = InstructionCacheConfig(
|
||||||
cacheSize = 4096*4,
|
cacheSize = 2048,
|
||||||
bytePerLine =32,
|
bytePerLine = 32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -52,10 +51,10 @@ object TestsWorkspace {
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = true,
|
catchMemoryTranslationMiss = true,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = false
|
||||||
),
|
),
|
||||||
askMemoryTranslation = true,
|
askMemoryTranslation = true,
|
||||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
portTlbSize = 4
|
portTlbSize = 4
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -95,7 +94,7 @@ object TestsWorkspace {
|
||||||
catchIllegalInstruction = true
|
catchIllegalInstruction = true
|
||||||
),
|
),
|
||||||
new RegFilePlugin(
|
new RegFilePlugin(
|
||||||
regFileReadyKind = plugin.SYNC,
|
regFileReadyKind = plugin.ASYNC,
|
||||||
zeroBoot = false
|
zeroBoot = false
|
||||||
),
|
),
|
||||||
new IntAluPlugin,
|
new IntAluPlugin,
|
||||||
|
@ -117,7 +116,7 @@ object TestsWorkspace {
|
||||||
// new HazardSimplePlugin(false, false, false, false),
|
// new HazardSimplePlugin(false, false, false, false),
|
||||||
new MulPlugin,
|
new MulPlugin,
|
||||||
new DivPlugin,
|
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 DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||||
new BranchPlugin(
|
new BranchPlugin(
|
||||||
earlyBranch = true,
|
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.INSTRUCTION).addAttribute(Verilator.public)
|
||||||
decode.input(config.PC).addAttribute(Verilator.public)
|
decode.input(config.PC).addAttribute(Verilator.public)
|
||||||
decode.arbitration.isValid.addAttribute(Verilator.public)
|
decode.arbitration.isValid.addAttribute(Verilator.public)
|
||||||
|
decode.arbitration.flushAll.addAttribute(Verilator.public)
|
||||||
decode.arbitration.haltItself.addAttribute(Verilator.public)
|
decode.arbitration.haltItself.addAttribute(Verilator.public)
|
||||||
writeBack.input(config.INSTRUCTION) keep() addAttribute(Verilator.public)
|
writeBack.input(config.INSTRUCTION) keep() addAttribute(Verilator.public)
|
||||||
writeBack.input(config.PC) keep() addAttribute(Verilator.public)
|
writeBack.input(config.PC) keep() addAttribute(Verilator.public)
|
||||||
|
|
|
@ -57,7 +57,6 @@ object BrieyConfig{
|
||||||
cacheSize = 4096,
|
cacheSize = 4096,
|
||||||
bytePerLine =32,
|
bytePerLine =32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -65,7 +64,7 @@ object BrieyConfig{
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = true,
|
catchMemoryTranslationMiss = true,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = true
|
||||||
)
|
)
|
||||||
// askMemoryTranslation = true,
|
// askMemoryTranslation = true,
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// 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"
|
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(
|
getDmips(
|
||||||
name = "GenFullNoMmuNoCache",
|
name = "GenFullNoMmuNoCache",
|
||||||
|
|
|
@ -11,7 +11,7 @@ object FormalSimple extends App{
|
||||||
def cpu() = new VexRiscv(
|
def cpu() = new VexRiscv(
|
||||||
config = VexRiscvConfig(
|
config = VexRiscvConfig(
|
||||||
plugins = List(
|
plugins = List(
|
||||||
new FomalPlugin,
|
new FormalPlugin,
|
||||||
new HaltOnExceptionPlugin,
|
new HaltOnExceptionPlugin,
|
||||||
new PcManagerSimplePlugin(
|
new PcManagerSimplePlugin(
|
||||||
resetVector = 0x00000000l,
|
resetVector = 0x00000000l,
|
||||||
|
|
|
@ -21,7 +21,6 @@ object GenFull extends App{
|
||||||
cacheSize = 4096,
|
cacheSize = 4096,
|
||||||
bytePerLine =32,
|
bytePerLine =32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -29,7 +28,7 @@ object GenFull extends App{
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = true,
|
catchMemoryTranslationMiss = true,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = true
|
||||||
),
|
),
|
||||||
askMemoryTranslation = true,
|
askMemoryTranslation = true,
|
||||||
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -21,7 +21,6 @@ object GenFullNoMmu extends App{
|
||||||
cacheSize = 4096,
|
cacheSize = 4096,
|
||||||
bytePerLine =32,
|
bytePerLine =32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -29,7 +28,7 @@ object GenFullNoMmu extends App{
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = true,
|
catchMemoryTranslationMiss = true,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = true
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new DBusCachedPlugin(
|
new DBusCachedPlugin(
|
||||||
|
|
|
@ -21,7 +21,6 @@ object GenFullNoMmuMaxPerf extends App{
|
||||||
cacheSize = 4096*4,
|
cacheSize = 4096*4,
|
||||||
bytePerLine =32,
|
bytePerLine =32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -29,7 +28,7 @@ object GenFullNoMmuMaxPerf extends App{
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = false,
|
catchMemoryTranslationMiss = false,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = true
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
new DBusCachedPlugin(
|
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())
|
||||||
|
}
|
|
@ -12,24 +12,24 @@ object VexRiscvSynthesisBench {
|
||||||
def main(args: Array[String]) {
|
def main(args: Array[String]) {
|
||||||
|
|
||||||
def wrap(that : => Component) : Component = that
|
def wrap(that : => Component) : Component = that
|
||||||
//Wrap with input/output registers
|
// Wrap with input/output registers
|
||||||
// def wrap(that : => Component) : Component = {
|
// def wrap(that : => Component) : Component = {
|
||||||
// //new WrapWithReg.Wrapper(that)
|
// //new WrapWithReg.Wrapper(that)
|
||||||
// val c = that
|
// val c = that
|
||||||
// c.rework {
|
// c.rework {
|
||||||
// for (e <- c.getOrdredNodeIo) {
|
// for (e <- c.getOrdredNodeIo) {
|
||||||
// if (e.isInput) {
|
// if (e.isInput) {
|
||||||
// e.asDirectionLess()
|
// e.asDirectionLess()
|
||||||
// e := RegNext(RegNext(in(cloneOf(e))))
|
// e := RegNext(RegNext(in(cloneOf(e))))
|
||||||
//
|
//
|
||||||
// } else {
|
// } else {
|
||||||
// e.asDirectionLess()
|
// e.asDirectionLess()
|
||||||
// out(cloneOf(e)) := RegNext(RegNext(e))
|
// out(cloneOf(e)) := RegNext(RegNext(e))
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// c
|
// c
|
||||||
// }
|
// }
|
||||||
|
|
||||||
val smallestNoCsr = new Rtl {
|
val smallestNoCsr = new Rtl {
|
||||||
override def getName(): String = "VexRiscv smallest no CSR"
|
override def getName(): String = "VexRiscv smallest no CSR"
|
||||||
|
@ -49,6 +49,12 @@ object VexRiscvSynthesisBench {
|
||||||
SpinalVerilog(wrap(GenSmallAndProductive.cpu()).setDefinitionName(getRtlPath().split("\\.").head))
|
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 {
|
val fullNoMmuNoCache = new Rtl {
|
||||||
override def getName(): String = "VexRiscv full no MMU no cache"
|
override def getName(): String = "VexRiscv full no MMU no cache"
|
||||||
override def getRtlPath(): String = "VexRiscvFullNoMmuNoCache.v"
|
override def getRtlPath(): String = "VexRiscvFullNoMmuNoCache.v"
|
||||||
|
@ -78,8 +84,9 @@ object VexRiscvSynthesisBench {
|
||||||
SpinalVerilog(wrap(GenFull.cpu()).setDefinitionName(getRtlPath().split("\\.").head))
|
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(noCacheNoMmuMaxPerf, fullNoMmuMaxPerf)
|
||||||
|
val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full)
|
||||||
|
|
||||||
val targets = XilinxStdTargets(
|
val targets = XilinxStdTargets(
|
||||||
vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
|
vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin"
|
||||||
|
|
|
@ -39,7 +39,6 @@ object VexRiscvAvalonForSim{
|
||||||
cacheSize = 4096,
|
cacheSize = 4096,
|
||||||
bytePerLine =32,
|
bytePerLine =32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -47,7 +46,7 @@ object VexRiscvAvalonForSim{
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = true,
|
catchMemoryTranslationMiss = true,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = true
|
||||||
)
|
)
|
||||||
// askMemoryTranslation = true,
|
// askMemoryTranslation = true,
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -38,7 +38,6 @@ object VexRiscvAvalonWithIntegratedJtag{
|
||||||
cacheSize = 4096,
|
cacheSize = 4096,
|
||||||
bytePerLine =32,
|
bytePerLine =32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -46,7 +45,7 @@ object VexRiscvAvalonWithIntegratedJtag{
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = true,
|
catchMemoryTranslationMiss = true,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = true
|
||||||
)
|
)
|
||||||
// askMemoryTranslation = true,
|
// askMemoryTranslation = true,
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -39,7 +39,6 @@ object VexRiscvAxi4WithIntegratedJtag{
|
||||||
cacheSize = 4096,
|
cacheSize = 4096,
|
||||||
bytePerLine =32,
|
bytePerLine =32,
|
||||||
wayCount = 1,
|
wayCount = 1,
|
||||||
wrappedMemAccess = true,
|
|
||||||
addressWidth = 32,
|
addressWidth = 32,
|
||||||
cpuDataWidth = 32,
|
cpuDataWidth = 32,
|
||||||
memDataWidth = 32,
|
memDataWidth = 32,
|
||||||
|
@ -47,7 +46,7 @@ object VexRiscvAxi4WithIntegratedJtag{
|
||||||
catchAccessFault = true,
|
catchAccessFault = true,
|
||||||
catchMemoryTranslationMiss = true,
|
catchMemoryTranslationMiss = true,
|
||||||
asyncTagMemory = false,
|
asyncTagMemory = false,
|
||||||
twoStageLogic = true
|
twoCycleRam = true
|
||||||
)
|
)
|
||||||
// askMemoryTranslation = true,
|
// askMemoryTranslation = true,
|
||||||
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
|
|
@ -10,7 +10,6 @@ import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
|
||||||
case class InstructionCacheConfig( cacheSize : Int,
|
case class InstructionCacheConfig( cacheSize : Int,
|
||||||
bytePerLine : Int,
|
bytePerLine : Int,
|
||||||
wayCount : Int,
|
wayCount : Int,
|
||||||
wrappedMemAccess : Boolean,
|
|
||||||
addressWidth : Int,
|
addressWidth : Int,
|
||||||
cpuDataWidth : Int,
|
cpuDataWidth : Int,
|
||||||
memDataWidth : Int,
|
memDataWidth : Int,
|
||||||
|
@ -18,7 +17,10 @@ case class InstructionCacheConfig( cacheSize : Int,
|
||||||
catchAccessFault : Boolean,
|
catchAccessFault : Boolean,
|
||||||
catchMemoryTranslationMiss : Boolean,
|
catchMemoryTranslationMiss : Boolean,
|
||||||
asyncTagMemory : Boolean,
|
asyncTagMemory : Boolean,
|
||||||
twoStageLogic : Boolean){
|
twoCycleRam : Boolean = false,
|
||||||
|
preResetFlush : Boolean = false){
|
||||||
|
|
||||||
|
def dataOnDecode = twoCycleRam && wayCount > 1
|
||||||
def burstSize = bytePerLine*8/memDataWidth
|
def burstSize = bytePerLine*8/memDataWidth
|
||||||
def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess
|
def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess
|
||||||
|
|
||||||
|
@ -36,7 +38,6 @@ case class InstructionCacheConfig( cacheSize : Int,
|
||||||
addressWidth = addressWidth,
|
addressWidth = addressWidth,
|
||||||
dataWidth = memDataWidth,
|
dataWidth = memDataWidth,
|
||||||
burstCountWidth = log2Up(burstSize + 1)).getReadOnlyConfig.copy(
|
burstCountWidth = log2Up(burstSize + 1)).getReadOnlyConfig.copy(
|
||||||
linewrapBursts = wrappedMemAccess,
|
|
||||||
useResponse = true,
|
useResponse = true,
|
||||||
constantBurstBehavior = true
|
constantBurstBehavior = true
|
||||||
)
|
)
|
||||||
|
@ -47,72 +48,65 @@ case class InstructionCacheConfig( cacheSize : Int,
|
||||||
|
|
||||||
case class InstructionCacheCpuPrefetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
case class InstructionCacheCpuPrefetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||||
val isValid = Bool
|
val isValid = Bool
|
||||||
val isFiring = Bool
|
|
||||||
val haltIt = Bool
|
val haltIt = Bool
|
||||||
val address = UInt(p.addressWidth bit)
|
val pc = UInt(p.addressWidth bit)
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid, isFiring, address)
|
out(isValid, pc)
|
||||||
in(haltIt)
|
in(haltIt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
|
case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
|
||||||
val isValid = Bool
|
val isValid = Bool
|
||||||
val haltIt = if(!p.twoStageLogic) Bool else null
|
|
||||||
val isStuck = Bool
|
val isStuck = Bool
|
||||||
val isStuckByOthers = if(!p.twoStageLogic) Bool else null
|
val pc = UInt(p.addressWidth bits)
|
||||||
val address = UInt(p.addressWidth bit)
|
val data = Bits(p.cpuDataWidth bits)
|
||||||
val data = if(!p.twoStageLogic) Bits(32 bit) else null
|
val mmuBus = MemoryTranslatorBus()
|
||||||
val error = if(!p.twoStageLogic && p.catchAccessFault) Bool else null
|
|
||||||
val mmuBus = if(p.twoStageLogic) MemoryTranslatorBus() else null
|
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid, isStuck, address)
|
out(isValid, isStuck, pc)
|
||||||
outWithNull(isStuckByOthers)
|
inWithNull(data)
|
||||||
inWithNull(error,data,haltIt)
|
|
||||||
slaveWithNull(mmuBus)
|
slaveWithNull(mmuBus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
|
case class InstructionCacheCpuDecode(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
|
||||||
require(p.twoStageLogic)
|
|
||||||
val isValid = Bool
|
val isValid = Bool
|
||||||
val haltIt = Bool
|
|
||||||
val isStuck = Bool
|
|
||||||
val isUser = Bool
|
val isUser = Bool
|
||||||
val address = UInt(p.addressWidth bit)
|
val isStuck = Bool
|
||||||
val data = Bits(32 bit)
|
val pc = UInt(p.addressWidth bits)
|
||||||
val dataAnticipated = Bits(32 bits)
|
val redo = Bool
|
||||||
|
val data = ifGen(p.dataOnDecode) (Bits(p.cpuDataWidth bits))
|
||||||
val error = if(p.catchAccessFault) Bool else null
|
val error = if(p.catchAccessFault) Bool else null
|
||||||
val mmuMiss = if(p.catchMemoryTranslationMiss) Bool else null
|
val mmuMiss = if(p.catchMemoryTranslationMiss) Bool else null
|
||||||
val illegalAccess = if(p.catchIllegalAccess) Bool else null
|
val illegalAccess = if(p.catchIllegalAccess) Bool else null
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
out(isValid, isStuck, address, isUser)
|
out(isValid, isUser, isStuck, pc)
|
||||||
in(haltIt, data, dataAnticipated)
|
in(redo)
|
||||||
inWithNull(error,mmuMiss,illegalAccess)
|
inWithNull(error,mmuMiss,illegalAccess,data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||||
val prefetch = InstructionCacheCpuPrefetch(p)
|
val prefetch = InstructionCacheCpuPrefetch(p)
|
||||||
val fetch = InstructionCacheCpuFetch(p)
|
val fetch = InstructionCacheCpuFetch(p)
|
||||||
val decode = if(p.twoStageLogic) InstructionCacheCpuDecode(p) else null
|
val decode = InstructionCacheCpuDecode(p)
|
||||||
|
|
||||||
override def asMaster(): Unit = {
|
override def asMaster(): Unit = {
|
||||||
master(prefetch)
|
master(prefetch, fetch, decode)
|
||||||
master(fetch)
|
|
||||||
if(p.twoStageLogic) master(decode)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{
|
case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{
|
||||||
val address = UInt(p.addressWidth bit)
|
val address = UInt(p.addressWidth bit)
|
||||||
|
val size = UInt(log2Up(log2Up(p.bytePerLine) + 1) bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{
|
case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{
|
||||||
val data = Bits(32 bit)
|
val data = Bits(p.memDataWidth bit)
|
||||||
val error = Bool
|
val error = Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,10 +128,7 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit
|
||||||
mm.readCmd.addr := cmd.address
|
mm.readCmd.addr := cmd.address
|
||||||
mm.readCmd.prot := "110"
|
mm.readCmd.prot := "110"
|
||||||
mm.readCmd.cache := "1111"
|
mm.readCmd.cache := "1111"
|
||||||
if(p.wrappedMemAccess)
|
mm.readCmd.setBurstINCR()
|
||||||
mm.readCmd.setBurstWRAP()
|
|
||||||
else
|
|
||||||
mm.readCmd.setBurstINCR()
|
|
||||||
cmd.ready := mm.readCmd.ready
|
cmd.ready := mm.readCmd.ready
|
||||||
rsp.valid := mm.readRsp.valid
|
rsp.valid := mm.readRsp.valid
|
||||||
rsp.data := mm.readRsp.data
|
rsp.data := mm.readRsp.data
|
||||||
|
@ -173,21 +164,21 @@ case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{
|
||||||
|
|
||||||
class InstructionCache(p : InstructionCacheConfig) extends Component{
|
class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||||
import p._
|
import p._
|
||||||
assert(wayCount == 1)
|
assert(cpuDataWidth == memDataWidth, "Need testing")
|
||||||
assert(cpuDataWidth == memDataWidth)
|
|
||||||
val io = new Bundle{
|
val io = new Bundle{
|
||||||
val flush = slave(InstructionCacheFlushBus())
|
val flush = slave(InstructionCacheFlushBus())
|
||||||
// val translator = master(InstructionCacheTranslationBus(p))
|
|
||||||
val cpu = slave(InstructionCacheCpuBus(p))
|
val cpu = slave(InstructionCacheCpuBus(p))
|
||||||
val mem = master(InstructionCacheMemBus(p))
|
val mem = master(InstructionCacheMemBus(p))
|
||||||
}
|
}
|
||||||
// val haltCpu = False
|
|
||||||
val lineWidth = bytePerLine*8
|
val lineWidth = bytePerLine*8
|
||||||
val lineCount = cacheSize/bytePerLine
|
val lineCount = cacheSize/bytePerLine
|
||||||
val wordWidth = Math.max(memDataWidth,32)
|
val wordWidth = Math.max(memDataWidth,32)
|
||||||
val wordWidthLog2 = log2Up(wordWidth)
|
val wordWidthLog2 = log2Up(wordWidth)
|
||||||
val wordPerLine = lineWidth/wordWidth
|
val wordPerLine = lineWidth/wordWidth
|
||||||
|
val memWordPerLine = lineWidth/memDataWidth
|
||||||
val bytePerWord = wordWidth/8
|
val bytePerWord = wordWidth/8
|
||||||
|
val bytePerMemWord = memDataWidth/8
|
||||||
val wayLineCount = lineCount/wayCount
|
val wayLineCount = lineCount/wayCount
|
||||||
val wayLineLog2 = log2Up(wayLineCount)
|
val wayLineLog2 = log2Up(wayLineCount)
|
||||||
val wayWordCount = wayLineCount * wordPerLine
|
val wayWordCount = wayLineCount * wordPerLine
|
||||||
|
@ -195,44 +186,41 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||||
val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine)
|
val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine)
|
||||||
val lineRange = tagRange.low-1 downto log2Up(bytePerLine)
|
val lineRange = tagRange.low-1 downto log2Up(bytePerLine)
|
||||||
val wordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord)
|
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 tagLineRange = tagRange.high downto lineRange.low
|
||||||
val lineWordRange = lineRange.high downto wordRange.low
|
val lineWordRange = lineRange.high downto wordRange.low
|
||||||
|
|
||||||
class LineInfo extends Bundle{
|
case class LineTag() extends Bundle{
|
||||||
val valid = Bool
|
val valid = Bool
|
||||||
val loading = Bool
|
val error = Bool
|
||||||
val error = if(catchAccessFault) Bool else null
|
|
||||||
val address = UInt(tagRange.length bit)
|
val address = UInt(tagRange.length bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
class LineInfoWithHit extends LineInfo{
|
|
||||||
val hit = Bool
|
|
||||||
}
|
|
||||||
|
|
||||||
def LineInfoWithHit(lineInfo : LineInfo, testTag : UInt) = {
|
val ways = Seq.fill(wayCount)(new Area{
|
||||||
val ret = new LineInfoWithHit()
|
val tags = Mem(LineTag(),wayLineCount)
|
||||||
ret.assignSomeByName(lineInfo)
|
val datas = Mem(Bits(memDataWidth bits),wayWordCount)
|
||||||
ret.hit := lineInfo.valid && lineInfo.address === testTag
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if(preResetFlush){
|
||||||
val ways = Array.fill(wayCount)(new Area{
|
tags.initBigInt(List.fill(wayLineCount)(BigInt(0)))
|
||||||
val tags = Mem(new LineInfo(),wayLineCount)
|
}
|
||||||
val datas = Mem(Bits(wordWidth bits),wayWordCount)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
io.cpu.prefetch.haltIt := False
|
io.cpu.prefetch.haltIt := False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val lineLoader = new Area{
|
val lineLoader = new Area{
|
||||||
val requestIn = Stream(wrap(new Bundle{
|
val fire = False
|
||||||
val addr = UInt(addressWidth bits)
|
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(if(preResetFlush) wayLineCount else 0)
|
||||||
val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(0)
|
|
||||||
when(!flushCounter.msb){
|
when(!flushCounter.msb){
|
||||||
io.cpu.prefetch.haltIt := True
|
io.cpu.prefetch.haltIt := True
|
||||||
flushCounter := flushCounter + 1
|
flushCounter := flushCounter + 1
|
||||||
|
@ -241,6 +229,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||||
io.cpu.prefetch.haltIt := True
|
io.cpu.prefetch.haltIt := True
|
||||||
}
|
}
|
||||||
val flushFromInterface = RegInit(False)
|
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){
|
when(io.flush.cmd.valid){
|
||||||
io.cpu.prefetch.haltIt := True
|
io.cpu.prefetch.haltIt := True
|
||||||
when(io.flush.cmd.ready){
|
when(io.flush.cmd.ready){
|
||||||
|
@ -251,204 +240,110 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||||
|
|
||||||
io.flush.rsp := flushCounter.msb.rise && flushFromInterface
|
io.flush.rsp := flushCounter.msb.rise && flushFromInterface
|
||||||
|
|
||||||
val loadingWithErrorReg = if(catchAccessFault) RegInit(False) else null
|
|
||||||
val loadingWithError = if(catchAccessFault) Bool else null
|
|
||||||
if(catchAccessFault) {
|
val cmdSent = RegInit(False) setWhen(io.mem.cmd.fire) clearWhen(fire)
|
||||||
loadingWithError := loadingWithErrorReg
|
io.mem.cmd.valid := valid && !cmdSent
|
||||||
loadingWithErrorReg := loadingWithError
|
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)
|
||||||
val request = requestIn.stage()
|
data.valid := io.mem.rsp.valid && wayHit
|
||||||
|
data.address := address(lineRange) @@ wordIndex
|
||||||
|
data.data := io.mem.rsp.data
|
||||||
//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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val memRspLast = loadedWordsNext === B(loadedWordsNext.range -> true)
|
when(io.mem.rsp.valid) {
|
||||||
|
wordIndex := (wordIndex + 1).resized
|
||||||
val readyDelay = Reg(UInt(1 bit))
|
hadError.setWhen(io.mem.rsp.error)
|
||||||
when(memRspLast){
|
when(wordIndex === wordIndex.maxValue) {
|
||||||
readyDelay := readyDelay + 1
|
fire := True
|
||||||
}
|
}
|
||||||
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 fetchStage = new Area{
|
||||||
val readAddress = Mux(io.cpu.fetch.isStuck,io.cpu.fetch.address,io.cpu.prefetch.address) //TODO FMAX
|
val read = new Area{
|
||||||
val tag = if(asyncTagMemory)
|
val waysValues = for(way <- ways) yield new Area{
|
||||||
way.tags.readAsync(io.cpu.fetch.address(lineRange),writeFirst)
|
val tag = if(asyncTagMemory) {
|
||||||
else
|
way.tags.readAsync(io.cpu.fetch.pc(lineRange))
|
||||||
way.tags.readSync(readAddress(lineRange),readUnderWrite = readFirst)
|
}else {
|
||||||
|
way.tags.readSync(io.cpu.prefetch.pc(lineRange), !io.cpu.fetch.isStuck)
|
||||||
val data = way.datas.readSync(readAddress(lineRange.high downto wordRange.low))
|
}
|
||||||
waysHitWord := data //Not applicable to multi way
|
val data = way.datas.readSync(io.cpu.prefetch.pc(lineRange.high downto memWordRange.low), !io.cpu.fetch.isStuck)
|
||||||
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)))
|
val hit = if(!twoCycleRam) new Area{
|
||||||
io.cpu.fetch.haltIt := io.cpu.fetch.isValid && !hit
|
val hits = read.waysValues.map(way => way.tag.valid && way.tag.address === io.cpu.fetch.mmuBus.rsp.physicalAddress(tagRange))
|
||||||
io.cpu.fetch.data := waysHitWord
|
val valid = Cat(hits).orR
|
||||||
if(catchAccessFault) io.cpu.fetch.error := waysRead(0).tag.error
|
val id = OHToUInt(hits)
|
||||||
lineLoader.requestIn.valid := io.cpu.fetch.isValid && !hit //TODO avoid duplicated request
|
val error = read.waysValues.map(_.tag.error).read(id)
|
||||||
lineLoader.requestIn.addr := io.cpu.fetch.address
|
val data = read.waysValues.map(_.data).read(id)
|
||||||
} else new Area{
|
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
|
||||||
//Long readValidPath
|
io.cpu.fetch.data := word
|
||||||
// def writeFirstMemWrap[T <: Data](readValid : Bool, readAddress : UInt, lastAddress : UInt, readData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = {
|
} else null
|
||||||
// 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
|
if(twoCycleRam && wayCount == 1){
|
||||||
def writeFirstMemWrap[T <: Data](readValid : Bool, readLastAddress : UInt, readData : T,writeValid : Bool, writeAddress : UInt, writeData : T) : T = {
|
io.cpu.fetch.data := read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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)
|
|
||||||
}
|
|
||||||
// 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 (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
|
|
||||||
)
|
|
||||||
|
|
||||||
io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid
|
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
|
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
|
|
||||||
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))
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,9 @@ case class CsrPluginConfig(
|
||||||
minstretAccess : CsrAccess,
|
minstretAccess : CsrAccess,
|
||||||
ucycleAccess : CsrAccess,
|
ucycleAccess : CsrAccess,
|
||||||
wfiGen : Boolean,
|
wfiGen : Boolean,
|
||||||
ecallGen : Boolean
|
ecallGen : Boolean,
|
||||||
|
deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes
|
||||||
|
|
||||||
){
|
){
|
||||||
assert(!ucycleAccess.canWrite)
|
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 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 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
|
//Interrupt/Exception entry logic
|
||||||
pipelineLiberator.enable setWhen(interrupt)
|
pipelineLiberator.enable setWhen(interrupt)
|
||||||
when(exception || (interrupt && pipelineLiberator.done)){
|
when(exception || (interrupt && pipelineLiberator.done)){
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
package vexriscv.plugin
|
package vexriscv.plugin
|
||||||
|
|
||||||
import spinal.lib.com.jtag.Jtag
|
import spinal.lib.com.jtag.Jtag
|
||||||
import spinal.lib.system.debugger.{SystemDebugger, JtagBridge, SystemDebuggerConfig}
|
import spinal.lib.system.debugger.{JtagBridge, SystemDebugger, SystemDebuggerConfig}
|
||||||
import vexriscv.plugin.IntAluPlugin.{AluCtrlEnum, ALU_CTRL}
|
import vexriscv.plugin.IntAluPlugin.{ALU_CTRL, AluCtrlEnum}
|
||||||
import vexriscv._
|
import vexriscv._
|
||||||
import vexriscv.ip._
|
import vexriscv.ip._
|
||||||
import spinal.core._
|
import spinal.core._
|
||||||
import spinal.lib._
|
import spinal.lib._
|
||||||
import spinal.lib.bus.amba3.apb.{Apb3Config, Apb3}
|
import spinal.lib.bus.amba3.apb.{Apb3, Apb3Config}
|
||||||
import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
|
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||||
|
|
||||||
|
import scala.collection.mutable.ArrayBuffer
|
||||||
|
|
||||||
|
|
||||||
case class DebugExtensionCmd() extends Bundle{
|
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
|
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)
|
object IS_EBREAK extends Stageable(Bool)
|
||||||
override def setup(pipeline: VexRiscv): Unit = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
|
@ -114,13 +124,15 @@ class DebugPlugin(val debugClockDomain : ClockDomain) extends Plugin[VexRiscv] {
|
||||||
SRC2_CTRL -> Src2CtrlEnum.PC,
|
SRC2_CTRL -> Src2CtrlEnum.PC,
|
||||||
ALU_CTRL -> AluCtrlEnum.ADD_SUB //Used to get the PC value in busReadDataReg
|
ALU_CTRL -> AluCtrlEnum.ADD_SUB //Used to get the PC value in busReadDataReg
|
||||||
))
|
))
|
||||||
|
|
||||||
|
isInjectingOnDecode = Bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def build(pipeline: VexRiscv): Unit = {
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
import pipeline._
|
import pipeline._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
|
||||||
debugClockDomain {pipeline plug new Area{
|
val logic = debugClockDomain {pipeline plug new Area{
|
||||||
val insertDecodeInstruction = False
|
val insertDecodeInstruction = False
|
||||||
val firstCycle = RegNext(False) setWhen (io.bus.cmd.ready)
|
val firstCycle = RegNext(False) setWhen (io.bus.cmd.ready)
|
||||||
val secondCycle = RegNext(firstCycle)
|
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(() => {
|
Component.current.addPrePopTask(() => {
|
||||||
val reg = decode.input(INSTRUCTION).getDrivingReg
|
//Check if the decode instruction is driven by a register
|
||||||
reg.component.rework {
|
val instructionDriver = try {decode.input(INSTRUCTION).getDrivingReg} catch { case _ : Throwable => null}
|
||||||
when(insertDecodeInstruction.pull()) {
|
if(instructionDriver != null){ //If yes =>
|
||||||
reg := io.bus.cmd.data.pull()
|
//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()) {
|
||||||
|
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) {
|
when(stepIt && prefetch.arbitration.isFiring) {
|
||||||
haltIt := True
|
haltIt := True
|
||||||
}
|
}
|
||||||
|
when(stepIt && Cat(pipeline.stages.map(_.arbitration.redoIt)).asBits.orR) {
|
||||||
|
haltIt := False
|
||||||
|
}
|
||||||
io.resetOut := RegNext(resetIt)
|
io.resetOut := RegNext(resetIt)
|
||||||
|
|
||||||
if(serviceExist(classOf[InterruptionInhibitor])) {
|
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)
|
//2) JALR => clear PC(0)
|
||||||
//3) input(INSTRUCTION)(5) REGFILE_WRITE_VALID memory read with exception would not fire properly
|
//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
|
var rvfi : RvfiPort = null
|
||||||
|
|
|
@ -28,11 +28,15 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService {
|
||||||
stages.head.insert(FORMAL_HALT) := False
|
stages.head.insert(FORMAL_HALT) := False
|
||||||
stages.foreach(stage => {
|
stages.foreach(stage => {
|
||||||
val stagePorts = exceptionPortsInfos.filter(_.stage == stage)
|
val stagePorts = exceptionPortsInfos.filter(_.stage == stage)
|
||||||
if(stagePorts.nonEmpty)
|
if(stagePorts.nonEmpty) {
|
||||||
when(stagePorts.map(_.port.valid).orR){
|
when(stagePorts.map(info => info.port.valid).orR) {
|
||||||
stage.output(FORMAL_HALT) := True
|
stage.output(FORMAL_HALT) := True
|
||||||
stage.arbitration.haltItself := 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] {
|
class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : Boolean = false, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv] {
|
||||||
import config._
|
import config._
|
||||||
assert(twoStageLogic || !askMemoryTranslation)
|
|
||||||
|
|
||||||
var iBus : InstructionCacheMemBus = null
|
var iBus : InstructionCacheMemBus = null
|
||||||
var mmuBus : MemoryTranslatorBus = null
|
var mmuBus : MemoryTranslatorBus = null
|
||||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||||
var privilegeService : PrivilegeService = null
|
var privilegeService : PrivilegeService = null
|
||||||
|
var redoBranch : Flow[UInt] = null
|
||||||
|
|
||||||
object FLUSH_ALL extends Stageable(Bool)
|
object FLUSH_ALL extends Stageable(Bool)
|
||||||
object IBUS_ACCESS_ERROR 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 = {
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
import Riscv._
|
import Riscv._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
@ -29,6 +31,9 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
||||||
FLUSH_ALL -> True
|
FLUSH_ALL -> True
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
redoBranch = pipeline.service(classOf[JumpService]).createJumpInterface(pipeline.decode, priority = 1) //Priority 1 will win against branch predictor
|
||||||
|
|
||||||
if(catchSomething) {
|
if(catchSomething) {
|
||||||
val exceptionService = pipeline.service(classOf[ExceptionService])
|
val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||||
|
@ -47,6 +52,9 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
||||||
val c = new CacheReport()
|
val c = new CacheReport()
|
||||||
e.kind = "cached"
|
e.kind = "cached"
|
||||||
e.flushInstructions.add(0x400F) //invalid instruction cache
|
e.flushInstructions.add(0x400F) //invalid instruction cache
|
||||||
|
e.flushInstructions.add(0x13)
|
||||||
|
e.flushInstructions.add(0x13)
|
||||||
|
e.flushInstructions.add(0x13)
|
||||||
|
|
||||||
e.info = c
|
e.info = c
|
||||||
c.size = cacheSize
|
c.size = cacheSize
|
||||||
|
@ -60,67 +68,68 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
||||||
override def build(pipeline: VexRiscv): Unit = {
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
import pipeline._
|
import pipeline._
|
||||||
import pipeline.config._
|
import pipeline.config._
|
||||||
|
// val debugAddressOffset = 28
|
||||||
val cache = new InstructionCache(this.config)
|
val cache = new InstructionCache(this.config)
|
||||||
iBus = master(new InstructionCacheMemBus(this.config)).setName("iBus")
|
iBus = master(new InstructionCacheMemBus(this.config)).setName("iBus")
|
||||||
iBus <> cache.io.mem
|
iBus <> cache.io.mem
|
||||||
|
iBus.cmd.address.allowOverride := cache.io.mem.cmd.address // - debugAddressOffset
|
||||||
|
|
||||||
//Connect prefetch cache side
|
//Connect prefetch cache side
|
||||||
cache.io.cpu.prefetch.isValid := prefetch.arbitration.isValid
|
cache.io.cpu.prefetch.isValid := prefetch.arbitration.isValid
|
||||||
cache.io.cpu.prefetch.isFiring := prefetch.arbitration.isFiring
|
cache.io.cpu.prefetch.pc := prefetch.output(PC)// + debugAddressOffset
|
||||||
cache.io.cpu.prefetch.address := prefetch.output(PC)
|
|
||||||
prefetch.arbitration.haltItself setWhen(cache.io.cpu.prefetch.haltIt)
|
prefetch.arbitration.haltItself setWhen(cache.io.cpu.prefetch.haltIt)
|
||||||
|
|
||||||
//Connect fetch cache side
|
//Connect fetch cache side
|
||||||
cache.io.cpu.fetch.isValid := fetch.arbitration.isValid
|
cache.io.cpu.fetch.isValid := fetch.arbitration.isValid
|
||||||
cache.io.cpu.fetch.isStuck := fetch.arbitration.isStuck
|
cache.io.cpu.fetch.isStuck := fetch.arbitration.isStuck
|
||||||
if(!twoStageLogic) cache.io.cpu.fetch.isStuckByOthers := fetch.arbitration.isStuckByOthers
|
cache.io.cpu.fetch.pc := fetch.output(PC) // + debugAddressOffset
|
||||||
cache.io.cpu.fetch.address := fetch.output(PC)
|
|
||||||
if(!twoStageLogic) {
|
if (mmuBus != null) {
|
||||||
fetch.arbitration.haltItself setWhen (cache.io.cpu.fetch.haltIt)
|
cache.io.cpu.fetch.mmuBus <> mmuBus
|
||||||
|
} else {
|
||||||
|
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress //- debugAddressOffset
|
||||||
|
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
|
||||||
|
cache.io.cpu.fetch.mmuBus.rsp.allowRead := True
|
||||||
|
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
|
||||||
|
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
|
||||||
|
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
|
||||||
|
cache.io.cpu.fetch.mmuBus.rsp.miss := False
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dataOnDecode){
|
||||||
|
decode.insert(INSTRUCTION) := cache.io.cpu.decode.data
|
||||||
|
}else{
|
||||||
fetch.insert(INSTRUCTION) := cache.io.cpu.fetch.data
|
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_ANTICIPATED) := Mux(decode.arbitration.isStuck,decode.input(INSTRUCTION),fetch.output(INSTRUCTION))
|
||||||
decode.insert(INSTRUCTION_READY) := True
|
}
|
||||||
}else {
|
decode.insert(INSTRUCTION_READY) := True
|
||||||
if (mmuBus != null) {
|
|
||||||
cache.io.cpu.fetch.mmuBus <> mmuBus
|
cache.io.cpu.decode.pc := decode.output(PC)
|
||||||
} else {
|
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.physicalAddress := cache.io.cpu.fetch.mmuBus.cmd.virtualAddress
|
val ownDecode = pipeline.plugins.filter(_.isInstanceOf[InstructionInjector]).foldLeft(True)(_ && !_.asInstanceOf[InstructionInjector].isInjecting(decode))
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.allowExecute := True
|
cache.io.cpu.decode.isValid := decode.arbitration.isValid && ownDecode
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.allowRead := True
|
cache.io.cpu.decode.isStuck := decode.arbitration.isStuck
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.allowWrite := True
|
cache.io.cpu.decode.isUser := (if(privilegeService != null) privilegeService.isUser(decode) else False)
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.allowUser := True
|
// cache.io.cpu.decode.pc := decode.input(PC)
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.isIoAccess := False
|
|
||||||
cache.io.cpu.fetch.mmuBus.rsp.miss := False
|
redoBranch.valid := cache.io.cpu.decode.redo
|
||||||
}
|
redoBranch.payload := decode.input(PC)
|
||||||
}
|
when(redoBranch.valid){
|
||||||
|
decode.arbitration.redoIt := True
|
||||||
|
decode.arbitration.flushAll := True
|
||||||
|
|
||||||
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)
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// val redo = RegInit(False) clearWhen(decode.arbitration.isValid) setWhen(redoBranch.valid)
|
||||||
|
// when(redoBranch.valid || redo){
|
||||||
|
// service(classOf[InterruptionInhibitor]).inhibateInterrupts()
|
||||||
|
// }
|
||||||
|
|
||||||
if(catchSomething){
|
if(catchSomething){
|
||||||
if(catchAccessFault) {
|
val accessFault = if(catchAccessFault) cache.io.cpu.decode.error else False
|
||||||
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 mmuMiss = if(catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False
|
val mmuMiss = if(catchMemoryTranslationMiss) cache.io.cpu.decode.mmuMiss else False
|
||||||
val illegalAccess = if(catchIllegalAccess) cache.io.cpu.decode.illegalAccess 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.code := mmuMiss ? U(14) | 1
|
||||||
decodeExceptionPort.badAddr := decode.input(PC)
|
decodeExceptionPort.badAddr := decode.input(PC)
|
||||||
}
|
}
|
||||||
|
@ -130,11 +139,10 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
|
||||||
cache.io.flush.cmd.valid := False
|
cache.io.flush.cmd.valid := False
|
||||||
when(arbitration.isValid && input(FLUSH_ALL)){
|
when(arbitration.isValid && input(FLUSH_ALL)){
|
||||||
cache.io.flush.cmd.valid := True
|
cache.io.flush.cmd.valid := True
|
||||||
|
decode.arbitration.flushAll := True
|
||||||
|
|
||||||
when(!cache.io.flush.cmd.ready){
|
when(!cache.io.flush.cmd.ready){
|
||||||
arbitration.haltItself := True
|
arbitration.haltItself := True
|
||||||
} otherwise {
|
|
||||||
decode.arbitration.flushAll := True
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@ import scala.collection.mutable.ArrayBuffer
|
||||||
class PcManagerSimplePlugin(resetVector : BigInt,
|
class PcManagerSimplePlugin(resetVector : BigInt,
|
||||||
relaxedPcCalculation : Boolean = false) extends Plugin[VexRiscv] with JumpService{
|
relaxedPcCalculation : Boolean = false) extends Plugin[VexRiscv] with JumpService{
|
||||||
//FetchService interface
|
//FetchService interface
|
||||||
case class JumpInfo(interface : Flow[UInt], stage: Stage)
|
case class JumpInfo(interface : Flow[UInt], stage: Stage, priority : Int)
|
||||||
val jumpInfos = ArrayBuffer[JumpInfo]()
|
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))
|
val interface = Flow(UInt(32 bits))
|
||||||
jumpInfos += JumpInfo(interface,stage)
|
jumpInfos += JumpInfo(interface,stage, priority)
|
||||||
interface
|
interface
|
||||||
}
|
}
|
||||||
var prefetchExceptionPort : Flow[ExceptionCause] = null
|
var prefetchExceptionPort : Flow[ExceptionCause] = null
|
||||||
|
@ -59,7 +59,10 @@ class PcManagerSimplePlugin(resetVector : BigInt,
|
||||||
|
|
||||||
//JumpService hardware implementation
|
//JumpService hardware implementation
|
||||||
val jump = if(jumpInfos.length != 0) new Area {
|
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 valids = sortedByStage.map(_.interface.valid)
|
||||||
val pcs = sortedByStage.map(_.interface.payload)
|
val pcs = sortedByStage.map(_.interface.payload)
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,8 @@ public:
|
||||||
|
|
||||||
|
|
||||||
Workspace(string name){
|
Workspace(string name){
|
||||||
|
// setIStall(false);
|
||||||
|
// setDStall(false);
|
||||||
staticMutex.lock();
|
staticMutex.lock();
|
||||||
testsCounter++;
|
testsCounter++;
|
||||||
staticMutex.unlock();
|
staticMutex.unlock();
|
||||||
|
@ -358,6 +360,10 @@ public:
|
||||||
|
|
||||||
top->reset = 1;
|
top->reset = 1;
|
||||||
top->eval();
|
top->eval();
|
||||||
|
top->clk = 1;
|
||||||
|
top->eval();
|
||||||
|
top->clk = 0;
|
||||||
|
top->eval();
|
||||||
#ifdef CSR
|
#ifdef CSR
|
||||||
top->timerInterrupt = 0;
|
top->timerInterrupt = 0;
|
||||||
top->externalInterrupt = 1;
|
top->externalInterrupt = 1;
|
||||||
|
@ -400,7 +406,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
#ifndef REF_TIME
|
#ifndef REF_TIME
|
||||||
mTime = i/2;
|
#ifndef MTIME_INSTR_FACTOR
|
||||||
|
mTime = i/2;
|
||||||
|
#else
|
||||||
|
mTime += top->VexRiscv->writeBack_arbitration_isFiring*MTIME_INSTR_FACTOR;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef CSR
|
#ifdef CSR
|
||||||
top->timerInterrupt = mTime >= mTimeCmp ? 1 : 0;
|
top->timerInterrupt = mTime >= mTimeCmp ? 1 : 0;
|
||||||
|
@ -435,7 +445,7 @@ public:
|
||||||
for(SimElement* simElement : simElements) simElement->preCycle();
|
for(SimElement* simElement : simElements) simElement->preCycle();
|
||||||
|
|
||||||
if(withInstructionReadCheck){
|
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;
|
uint32_t expectedData;
|
||||||
bool dummy;
|
bool dummy;
|
||||||
iBusAccess(top->VexRiscv->decode_PC, &expectedData, &dummy);
|
iBusAccess(top->VexRiscv->decode_PC, &expectedData, &dummy);
|
||||||
|
@ -598,7 +608,7 @@ public:
|
||||||
virtual void preCycle(){
|
virtual void preCycle(){
|
||||||
if (top->iBus_cmd_valid && top->iBus_cmd_ready && pendingCount == 0) {
|
if (top->iBus_cmd_valid && top->iBus_cmd_ready && pendingCount == 0) {
|
||||||
assertEq(top->iBus_cmd_payload_address & 3,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;
|
address = top->iBus_cmd_payload_address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -610,7 +620,7 @@ public:
|
||||||
ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error);
|
ws->iBusAccess(address,&top->iBus_rsp_payload_data,&error);
|
||||||
top->iBus_rsp_payload_error = error;
|
top->iBus_rsp_payload_error = error;
|
||||||
pendingCount--;
|
pendingCount--;
|
||||||
address = (address & ~0x1F) + ((address + 4) & 0x1F);
|
address = address + 4;
|
||||||
top->iBus_rsp_valid = 1;
|
top->iBus_rsp_valid = 1;
|
||||||
}
|
}
|
||||||
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && pendingCount == 0;
|
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(7) < 100 && pendingCount == 0;
|
||||||
|
@ -1606,10 +1616,11 @@ string riscvTestDiv[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
string freeRtosTests[] = {
|
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",
|
"QueueSet", "recmutex", "semtest", "TaskNotify", "BlockQ", "crhook", "dynamic",
|
||||||
"GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1"
|
"GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1"
|
||||||
//"flop", "sp_flop" // <- Simple test
|
//"flop", "sp_flop" // <- Simple test
|
||||||
|
// "AltBlckQ" ???
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1714,7 +1725,7 @@ int main(int argc, char **argv, char **env) {
|
||||||
#ifdef CSR
|
#ifdef CSR
|
||||||
uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u ,
|
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 };
|
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
|
#endif
|
||||||
#ifdef MMU
|
#ifdef MMU
|
||||||
uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5,
|
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
|
REF=no
|
||||||
TRACE_WITH_TIME=no
|
TRACE_WITH_TIME=no
|
||||||
REF_TIME=no
|
REF_TIME=no
|
||||||
THREAD_COUNT=4
|
THREAD_COUNT?=4
|
||||||
|
MTIME_INSTR_FACTOR?=no
|
||||||
|
|
||||||
|
|
||||||
ADDCFLAGS += -CFLAGS -DIBUS_${IBUS}
|
ADDCFLAGS += -CFLAGS -DIBUS_${IBUS}
|
||||||
ADDCFLAGS += -CFLAGS -DDBUS_${DBUS}
|
ADDCFLAGS += -CFLAGS -DDBUS_${DBUS}
|
||||||
|
@ -27,10 +29,15 @@ ADDCFLAGS += -CFLAGS -DREDO=${REDO}
|
||||||
ADDCFLAGS += -CFLAGS -pthread
|
ADDCFLAGS += -CFLAGS -pthread
|
||||||
|
|
||||||
ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT}
|
ADDCFLAGS += -CFLAGS -DTHREAD_COUNT=${THREAD_COUNT}
|
||||||
|
|
||||||
ifeq ($(DHRYSTONE),yes)
|
ifeq ($(DHRYSTONE),yes)
|
||||||
ADDCFLAGS += -CFLAGS -DDHRYSTONE
|
ADDCFLAGS += -CFLAGS -DDHRYSTONE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(MTIME_INSTR_FACTOR),no)
|
||||||
|
ADDCFLAGS += -CFLAGS -DMTIME_INSTR_FACTOR=${MTIME_INSTR_FACTOR}
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(TRACE),yes)
|
ifeq ($(TRACE),yes)
|
||||||
VERILATOR_ARGS += --trace
|
VERILATOR_ARGS += --trace
|
||||||
ADDCFLAGS += -CFLAGS -DTRACE
|
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