TestIndividual is now fully random

This commit is contained in:
Dolu1990 2018-06-15 13:00:59 +02:00
parent b2cd8c5314
commit 1090111a6f
5 changed files with 120 additions and 87 deletions

View File

@ -332,17 +332,19 @@ You can find multiples software examples and demo there : https://github.com/Spi
There is some measurements of Murax SoC timings and area :
```
Murax interlocked stages (0.45 DMIPS/Mhz) ->
Artix 7 -> 305 Mhz 1004 LUT 1297 FF
Cyclone V -> 160 Mhz 744 ALMs
Cyclone IV -> 148 Mhz 1,522 LUT 1,255 FF
ICE40-HX -> 51 Mhz 2402 LC (icestorm)
Murax interlocked stages (0.45 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 299 Mhz 984 LUT 1186 FF
Cyclone V -> 175 Mhz 710 ALMs
Cyclone IV -> 137 Mhz 1,436 LUT 1,193 FF
iCE40 -> 48 Mhz 2337 LC (icestorm)
iCE40Ultra -> 20 Mhz 2337 LC (icestorm)
MuraxFast bypassed stages (0.65 DMIPS/Mhz) ->
Artix 7 -> 312 Mhz 1240 LUT 1330 FF
Cyclone V -> 159 Mhz 884 ALMs
Cyclone IV -> 142 Mhz 1,755 LUT 1,289 FF
ICE40-HX -> 50 Mhz, 2787 LC (icestorm)
MuraxFast bypassed stages (0.65 DMIPS/Mhz, 8 bits GPIO) ->
Artix 7 -> 294 Mhz 1128 LUT 1219 FF
Cyclone V -> 165 Mhz 840 ALMs
Cyclone IV -> 141 Mhz 1,680 LUT 1,227 FF
iCE40 -> 48 Mhz 2702 LC (icestorm)
iCE40Ultra -> 22 Mhz 2702 LC (icestorm)
```
There is some scripts to generate the SoC and call the icestorm toolchain there : scripts/Murax/
@ -414,14 +416,10 @@ val cpu = new VexRiscv(
config = VexRiscvConfig(
//Provide a list of plugins which will futher add their logic into the CPU
plugins = List(
new PcManagerSimplePlugin(
new IBusSimplePlugin(
resetVector = 0x00000000l,
relaxedPcCalculation = true
),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false
@ -447,8 +445,7 @@ val cpu = new VexRiscv(
),
new BranchPlugin(
earlyBranch = false,
catchAddressMisaligned = false,
prediction = NONE
catchAddressMisaligned = false
),
new YamlPlugin("cpu0.yaml")
)
@ -616,7 +613,6 @@ So again, if you generate the CPU without any plugin, it will only contain the 5
This chapter is describing plugins currently implemented.
- [PcManagerSimplePlugin](#pcmanagersimpleplugin)
- [IBusSimplePlugin](#ibussimpleplugin)
- [IBusCachedPlugin](#ibuscachedplugin)
- [DecoderSimplePlugin](#decodersimpleplugin)
@ -649,24 +645,24 @@ This plugin implement the programme counter and over an jump service to all plug
| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
The jump interface implemented by this plugin allow all other plugin to request jumps. The stage argument specify from which stage the jump is asked, which will allow the PcManagerSimplePlugin plugin to manage priorities between jump requests.
```scala
trait JumpService{
def createJumpInterface(stage : Stage) : Flow[UInt]
}
```
This plugin operate into the prefetch stage.
#### IBusSimplePlugin
This plugin fetch instruction via a very simple and neutral memory interface going outside the CPU.
This plugin implement the CPU frontend (instruction fetch) via a very simple and neutral memory interface going outside the CPU.
| Parameters | type | description |
| ------ | ----------- | ------ |
| interfaceKeepData | Boolean | Specify if the read response interface keep the data until the next one, or if it's only present a single cycle.|
| catchAccessFault | Boolean | If an the read response specify an read error and this parameter is true, it will generate an CPU exception trap |
| resetVector | BigInt | Address of the program counter after the reset |
| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
| relaxedBusCmdValid | Boolean | Same than relaxedPcCalculation, but for the iBus.cmd.valid pin. |
| compressedGen | Boolean | Enable RVC support |
| busLatencyMin | Int | Specify the minimal latency between the iBus.cmd and iBus.rsp, which will add the corresponding number of stages into the frontend to keep the IPC to 1.|
| injectorStage | Boolean | Add a stage between the frontend and the decode stage of the CPU to improve FMax. (busLatencyMin + injectorStage) should be at least two. |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
There is the SimpleBus interface definition
@ -700,7 +696,14 @@ There is at least one cycle latency between que cmd and the rsp. the rsp.ready f
Note that bridges are implemented to convert this interface into AXI4 and Avalon
This plugin fit in the fetch stage
The jump interface implemented by this plugin allow all other plugin to request jumps. The stage argument specify from which stage the jump is asked, which will allow the PcManagerSimplePlugin plugin to manage priorities between jump requests.
```scala
trait JumpService{
def createJumpInterface(stage : Stage) : Flow[UInt]
}
```
#### IBusCachedPlugin
@ -719,6 +722,11 @@ Simple and light multi way instruction cache.
| 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 |
| resetVector | BigInt | Address of the program counter after the reset |
| relaxedPcCalculation | Boolean | By default jump have an asynchronous immediate effect on the program counter, which allow to reduce the branch penalties by one cycle but could reduce the FMax as it will combinatorialy drive the instruction bus address signal. To avoid this you can set this parameter to true, which will make the jump affecting the programm counter in a sequancial way, which will cut the combinatorial path but add one additional cycle of penalty when a jump occur. |
| compressedGen | Boolean | Enable RVC support |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
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.
@ -813,18 +821,15 @@ Implement SLL/SRL/SRA instructions by using an full barriel shifter, so it execu
#### BranchPlugin
This plugin implement all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with some optional branch prediction. Each of those branch prediction could have been implemented into separated plugins.
This plugin implement all branch/jump instructions (JAL/JALR/BEQ/BNE/BLT/BGE/BLTU/BGEU) with primitives used by the cpu frontend plugins to implement branch prediction. The prediction implementation is set in the frontend plugins (IBusX)
| Parameters | type | description |
| ------ | ----------- | ------ |
| earlyBranch | Boolean | By default the branch is done in the Memory stage to relax timings, but if this option is set it's done in the Execute stage|
| catchAddressMisaligned | Boolean | If a jump/branch is done in an unaligned PC address, it will fire an trap exception |
| prediction | BranchPrediction | Can be set to NONE/STATIC/DYNAMIC/DYNAMIC_TARGET to specify the branch predictor implementation, see bellow for more descriptions |
| historyRamSizeLog2 | Int | Specify the number of entries in the direct mapped prediction cache of DYNAMIC/DYNAMIC_TARGET implementation. 2 pow historyRamSizeLog2 entries |
Each miss predicted jumps will produce between 2 and 4 cycles penalty depending the `earlyBranch` and the `PcManagerSimplePlugin.relaxedPcCalculation` configurations
##### Prediction NONE
No prediction, each PC changes due to a jump/branch will produce a penalty.

View File

@ -31,38 +31,39 @@ object TestsWorkspace {
SpinalConfig(mergeAsyncProcess = false).generateVerilog {
val configFull = VexRiscvConfig(
plugins = List(
new IBusSimplePlugin(
resetVector = 0x80000000l,
relaxedPcCalculation = true,
relaxedBusCmdValid = false,
prediction = DYNAMIC_TARGET,
historyRamSizeLog2 = 10,
catchAccessFault = true,
compressedGen = false,
busLatencyMin = 1
),
// new IBusCachedPlugin(
// new IBusSimplePlugin(
// resetVector = 0x80000000l,
// compressedGen = true,
// relaxedPcCalculation = true,
// relaxedBusCmdValid = false,
// prediction = DYNAMIC_TARGET,
// config = InstructionCacheConfig(
// cacheSize = 1024*16,
// bytePerLine = 32,
// wayCount = 1,
// addressWidth = 32,
// cpuDataWidth = 32,
// memDataWidth = 32,
// catchIllegalAccess = false,
// catchAccessFault = true,
// catchMemoryTranslationMiss = false,
// asyncTagMemory = false,
// twoCycleRam = false,
// twoCycleCache = true
// ),
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
// portTlbSize = 4
// )
// historyRamSizeLog2 = 10,
// catchAccessFault = true,
// compressedGen = false,
// busLatencyMin = 1
// ),
new IBusCachedPlugin(
resetVector = 0x80000000l,
compressedGen = true,
prediction = DYNAMIC_TARGET,
injectorStage = true,
config = InstructionCacheConfig(
cacheSize = 1024*16,
bytePerLine = 32,
wayCount = 1,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoCycleRam = false,
twoCycleCache = true
),
memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
portTlbSize = 4
)
),
// new DBusSimplePlugin(
// catchAddressMisaligned = true,
// catchAccessFault = true,

View File

@ -1,6 +1,6 @@
package vexriscv.plugin
import vexriscv._
import vexriscv.{plugin, _}
import vexriscv.ip._
import spinal.core._
import spinal.lib._
@ -16,7 +16,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
compressedGen : Boolean = false,
keepPcPlus4 : Boolean = false,
config : InstructionCacheConfig,
memoryTranslatorPortConfig : Any = null) extends IBusFetcherImpl(
memoryTranslatorPortConfig : Any = null,
injectorStage : Boolean = false) extends IBusFetcherImpl(
catchAccessFault = config.catchAccessFault,
resetVector = resetVector,
keepPcPlus4 = keepPcPlus4,
@ -27,7 +28,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
relaxedPcCalculation = relaxedPcCalculation,
prediction = prediction,
historyRamSizeLog2 = historyRamSizeLog2,
injectorStage = !config.twoCycleCache){
injectorStage = !config.twoCycleCache || injectorStage){
import config._
var iBus : InstructionCacheMemBus = null
@ -133,7 +134,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
cache.io.cpu.decode.pc := iBusRsp.inputPipeline(1).payload
cache.io.cpu.decode.isUser := (if (privilegeService != null) privilegeService.isUser(decode) else False)
if((!twoCycleRam || wayCount == 1) && !compressedGen){
if((!twoCycleRam || wayCount == 1) && !compressedGen && !injectorStage){
decode.insert(INSTRUCTION_ANTICIPATED) := Mux(decode.arbitration.isStuck, decode.input(INSTRUCTION), cache.io.cpu.fetch.data)
}
}

View File

@ -1 +1 @@
.word 0x7912a23
.word 0x3c12083

View File

@ -8,6 +8,7 @@ import vexriscv.demo._
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
import vexriscv.plugin._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.sys.process._
import scala.util.Random
@ -20,6 +21,16 @@ abstract class ConfigDimension[T](val name: String) {
abstract class VexRiscvDimension(name: String) extends ConfigDimension[VexRiscvPosition](name)
abstract class ConfigPosition[T](val name: String) {
def applyOn(config: T): Unit
var dimension : ConfigDimension[_] = null
def isCompatibleWith(positions : Seq[ConfigPosition[T]]) : Boolean = true
}
abstract class VexRiscvPosition(name: String) extends ConfigPosition[VexRiscvConfig](name){
def testParam : String = ""
}
class ShiftDimension extends VexRiscvDimension("Shift") {
override val positions = List(
new VexRiscvPosition("FullLate") {
@ -256,14 +267,16 @@ class IBusDimension extends VexRiscvDimension("IBus") {
wayCount <- List(1, 4);
cacheSize <- List(512, 4096);
compressed <- List(false, true);
injectorStage <- List(false, true);
relaxedPcCalculation <- List(false, true);
if !(!twoCycleCache && twoCycleRam ) && !(prediction != NONE && (wayCount == 1 || cacheSize == 4096 ))) yield new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")) with InstructionAnticipatedPosition{
if !(!twoCycleCache && twoCycleRam ) && !(prediction != NONE && (wayCount == 1 || cacheSize == 4096 ))) yield new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")) with InstructionAnticipatedPosition{
override def testParam = "IBUS=CACHED" + (if(compressed) " COMPRESSED=yes" else "")
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new IBusCachedPlugin(
resetVector = 0x80000000l,
compressedGen = compressed,
prediction = prediction,
relaxedPcCalculation = relaxedPcCalculation,
injectorStage = injectorStage,
config = InstructionCacheConfig(
cacheSize = cacheSize,
bytePerLine = 32,
@ -335,15 +348,24 @@ class DBusDimension extends VexRiscvDimension("DBus") {
abstract class ConfigPosition[T](val name: String) {
def applyOn(config: T): Unit
var dimension : ConfigDimension[_] = null
def isCompatibleWith(positions : Seq[ConfigPosition[T]]) : Boolean = true
trait CatchAllPosition
class CsrDimension extends VexRiscvDimension("Src") {
override val positions = List(
new VexRiscvPosition("None") {
override def applyOn(config: VexRiscvConfig): Unit = {}
override def testParam = "CSR=no"
},
new VexRiscvPosition("All") with CatchAllPosition{
override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all)
override def testParam = "CSR=no"
}
)
}
abstract class VexRiscvPosition(name: String) extends ConfigPosition[VexRiscvConfig](name){
def testParam : String = ""
}
class TestIndividualFeatures extends FunSuite {
def doCmd(cmd: String): String = {
@ -366,14 +388,15 @@ class TestIndividualFeatures extends FunSuite {
val dimensions = List(
new IBusDimension,
new DBusDimension,
new MulDivDimension,
new ShiftDimension,
new BranchDimension,
new HazardDimension,
new RegFileDimension,
new SrcDimension,
new IBusDimension,
new DBusDimension
new CsrDimension
)
@ -382,8 +405,11 @@ class TestIndividualFeatures extends FunSuite {
case Nil => List(stack)
}
val usedPositions = mutable.HashSet[VexRiscvPosition]();
val positionsCount = dimensions.map(d => d.positions.length).sum
def doTest(positionsToApply : List[VexRiscvPosition], prefix : String = ""): Unit ={
usedPositions ++= positionsToApply
def gen = {
SpinalVerilog{
val config = VexRiscvConfig(
@ -404,7 +430,7 @@ class TestIndividualFeatures extends FunSuite {
gen
}
test(prefix + name + "_test") {
val testCmd = "make clean run REDO=10 CSR=no MMU=no DEBUG_PLUGIN=no " + (positionsToApply).map(_.testParam).mkString(" ")
val testCmd = "make clean run REDO=5 MMU=no DEBUG_PLUGIN=no " + (positionsToApply).map(_.testParam).mkString(" ")
val str = doCmd(testCmd)
assert(!str.contains("FAIL"))
val intFind = "(\\d+\\.?)+".r
@ -414,7 +440,8 @@ class TestIndividualFeatures extends FunSuite {
dimensions.foreach(d => d.positions.foreach(_.dimension = d))
for(i <- 0 until 40){
for(i <- 0 until 200){
var positions : List[VexRiscvPosition] = null
do{
positions = dimensions.map(d => d.positions(Random.nextInt(d.positions.size)))
@ -422,14 +449,13 @@ class TestIndividualFeatures extends FunSuite {
doTest(positions," random_" + i + "_")
}
for (dimension <- dimensions) {
for (position <- dimension.positions/* if position.name.contains("Cached")*/) {
for(defaults <- genDefaultsPositions(dimensions.filter(_ != dimension))){
doTest(position :: defaults)
}
}
}
println(s"${usedPositions.size}/$positionsCount positions")
// for (dimension <- dimensions) {
// for (position <- dimension.positions/* if position.name.contains("Cached")*/) {
// for(defaults <- genDefaultsPositions(dimensions.filter(_ != dimension))){
// doTest(position :: defaults)
// }
// }
// }
}