Merge branch 'masterPrerelease'

This commit is contained in:
Charles Papon 2020-01-31 11:37:04 +01:00
commit ee36c36fdd
18 changed files with 584 additions and 58 deletions

View file

@ -7,8 +7,8 @@ lazy val root = (project in file(".")).
version := "2.0.0"
)),
libraryDependencies ++= Seq(
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.6",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.6",
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.3.8",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.3.8",
"org.scalatest" % "scalatest_2.11" % "2.2.1",
"org.yaml" % "snakeyaml" % "1.8"
),

View file

@ -13,7 +13,9 @@ import spinal.lib.com.uart.{Apb3UartCtrl, Uart, UartCtrlGenerics, UartCtrlMemory
import spinal.lib.graphic.RgbConfig
import spinal.lib.graphic.vga.{Axi4VgaCtrl, Axi4VgaCtrlGenerics, Vga}
import spinal.lib.io.TriStateArray
import spinal.lib.memory.sdram.SdramGeneration.SDR
import spinal.lib.memory.sdram._
import spinal.lib.memory.sdram.sdr.{Axi4SharedSdramCtrl, IS42x320D, SdramInterface, SdramTimings}
import spinal.lib.misc.HexTools
import spinal.lib.soc.pinsec.{PinsecTimerCtrl, PinsecTimerCtrlExternal}
import spinal.lib.system.debugger.{JtagAxi4SharedDebugger, JtagBridge, SystemDebugger, SystemDebuggerConfig}
@ -412,6 +414,7 @@ object BrieyDe0Nano{
def main(args: Array[String]) {
object IS42x160G {
def layout = SdramLayout(
generation = SDR,
bankWidth = 2,
columnWidth = 9,
rowWidth = 13,

View file

@ -0,0 +1,72 @@
package vexriscv.demo
import spinal.core._
import vexriscv.plugin._
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
/**
* Created by spinalvm on 15.06.17.
*/
object GenCustomInterrupt extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new UserInterruptPlugin(
interruptName = "miaou",
code = 20
),
new UserInterruptPlugin(
interruptName = "rawrrr",
code = 24
),
new CsrPlugin(
CsrPluginConfig.smallest.copy(
xtvecModeGen = true,
mtvecAccess = CsrAccess.WRITE_ONLY
)
),
new IBusSimplePlugin(
resetVector = 0x80000000l,
cmdForkOnSecondStage = false,
cmdForkPersistence = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = false
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false
),
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
),
new YamlPlugin("cpu0.yaml")
)
)
)
SpinalVerilog(cpu())
}

View file

@ -0,0 +1,77 @@
package vexriscv.demo
import spinal.core._
import vexriscv.plugin._
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
/**
* Created by spinalvm on 15.06.17.
*/
object GenSmallAndProductiveCfu extends App{
def cpu() = new VexRiscv(
config = VexRiscvConfig(
plugins = List(
new IBusSimplePlugin(
resetVector = 0x80000000l,
cmdForkOnSecondStage = false,
cmdForkPersistence = false,
prediction = NONE,
catchAccessFault = false,
compressedGen = 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
),
new CfuPlugin(
stageCount = 1,
allowZeroLatency = true,
encoding = M"000000-------------------0001011",
busParameter = CfuBusParameter(
CFU_VERSION = 0,
CFU_INTERFACE_ID_W = 0,
CFU_FUNCTION_ID_W = 2,
CFU_REORDER_ID_W = 0,
CFU_REQ_RESP_ID_W = 0,
CFU_INPUTS = 2,
CFU_INPUT_DATA_W = 32,
CFU_OUTPUTS = 1,
CFU_OUTPUT_DATA_W = 32,
CFU_FLOW_REQ_READY_ALWAYS = false,
CFU_FLOW_RESP_READY_ALWAYS = false
)
),
new YamlPlugin("cpu0.yaml")
)
)
)
SpinalVerilog(cpu())
}

View file

@ -119,7 +119,12 @@ make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRE
rm -rf cpio
mkdir cpio
cd cpio
cpio -idv < ../rootfs.cpio
sudo cpio -i < ../rootfs.cpio
cd ..
rm rootfs.cpio
cd cpio
sudo find | sudo cpio -H newc -o > ../rootfs.cpio
cd ..
make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes RUN_HEX=~/pro/riscv/zephyr/samples/synchronization/build/zephyr/zephyr.hex

View file

@ -65,7 +65,7 @@ object MuraxConfig{
SpiXdrMasterCtrl.Parameters(8, 12, SpiXdrParameter(2, 2, 1)).addFullDuplex(0,1,false),
cmdFifoDepth = 32,
rspFifoDepth = 32,
xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, dataWidth = 32)
xip = SpiXdrMasterCtrl.XipBusParameters(addressWidth = 24, lengthWidth = 2)
)),
hardwareBreakpointCount = if(withXip) 3 else 0,
cpuPlugins = ArrayBuffer( //DebugPlugin added by the toplevel
@ -298,13 +298,7 @@ case class Murax(config : MuraxConfig) extends Component{
val accessBus = new PipelinedMemoryBus(PipelinedMemoryBusConfig(24,32))
mainBusMapping += accessBus -> (0xE0000000l, 16 MB)
ctrl.io.xip.cmd.valid <> (accessBus.cmd.valid && !accessBus.cmd.write)
ctrl.io.xip.cmd.ready <> accessBus.cmd.ready
ctrl.io.xip.cmd.payload <> accessBus.cmd.address
ctrl.io.xip.rsp.valid <> accessBus.rsp.valid
ctrl.io.xip.rsp.payload <> accessBus.rsp.data
ctrl.io.xip.fromPipelinedMemoryBus() << accessBus
val bootloader = Apb3Rom("src/main/c/murax/xipBootloader/crt.bin")
apbMapping += bootloader.io.apb -> (0x1E000, 4 kB)
})

View file

@ -1,10 +1,11 @@
package vexriscv.demo
import spinal.core._
import spinal.lib._
import spinal.lib.eda.bench._
import spinal.lib.eda.icestorm.IcestormStdTargets
import vexriscv.VexRiscv
import vexriscv.plugin.{DecoderSimplePlugin, KeepAttribute}
import vexriscv.plugin.{DecoderSimplePlugin}
import scala.collection.mutable.ArrayBuffer
import scala.util.Random

View file

@ -22,7 +22,8 @@ case class InstructionCacheConfig( cacheSize : Int,
asyncTagMemory : Boolean,
twoCycleCache : Boolean = true,
twoCycleRam : Boolean = false,
preResetFlush : Boolean = false){
preResetFlush : Boolean = false,
bypassGen : Boolean = false ){
assert(!(twoCycleRam && !twoCycleCache))
@ -108,8 +109,8 @@ case class InstructionCacheCpuFetch(p : InstructionCacheConfig) extends Bundle w
val isRemoved = Bool()
val pc = UInt(p.addressWidth bits)
val data = Bits(p.cpuDataWidth bits)
val dataBypassValid = Bool()
val dataBypass = Bits(p.cpuDataWidth bits)
val dataBypassValid = p.bypassGen generate Bool()
val dataBypass = p.bypassGen generate Bits(p.cpuDataWidth bits)
val mmuBus = MemoryTranslatorBus()
val physicalAddress = UInt(p.addressWidth bits)
val cacheMiss, error, mmuRefilling, mmuException, isUser = ifGen(!p.twoCycleCache)(Bool)
@ -325,7 +326,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
val lineLoader = new Area{
val fire = False
val valid = RegInit(False) clearWhen(fire)
val address = Reg(UInt(addressWidth bits))
val address = KeepAttribute(Reg(UInt(addressWidth bits)))
val hadError = RegInit(False) clearWhen(fire)
val flushPending = RegInit(True)
@ -363,7 +364,7 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
io.mem.cmd.size := log2Up(p.bytePerLine)
val wayToAllocate = Counter(wayCount, !valid)
val wordIndex = Reg(UInt(log2Up(memWordPerLine) bits)) init(0)
val wordIndex = KeepAttribute(Reg(UInt(log2Up(memWordPerLine) bits)) init(0))
val write = new Area{
@ -415,15 +416,16 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
val id = OHToUInt(hits)
val error = read.waysValues.map(_.tag.error).read(id)
val data = read.waysValues.map(_.data).read(id)
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
io.cpu.fetch.data := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word)
val word = if(cpuDataWidth == memDataWidth) CombInit(data) else data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | word) else word)
if(twoCycleCache){
io.cpu.decode.data := RegNextWhen(io.cpu.fetch.data,!io.cpu.decode.isStuck)
}
}
if(twoCycleRam && wayCount == 1){
io.cpu.fetch.data := (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange)))
val cacheData = if(cpuDataWidth == memDataWidth) CombInit(read.waysValues.head.data) else read.waysValues.head.data.subdivideIn(cpuDataWidth bits).read(io.cpu.fetch.pc(memWordToCpuWordRange))
io.cpu.fetch.data := (if(p.bypassGen) (io.cpu.fetch.dataBypassValid ? io.cpu.fetch.dataBypass | cacheData) else cacheData)
}
io.cpu.fetch.mmuBus.cmd.isValid := io.cpu.fetch.isValid
@ -458,8 +460,8 @@ class InstructionCache(p : InstructionCacheConfig) extends Component{
val id = OHToUInt(hits)
val error = tags(id).error
val data = fetchStage.read.waysValues.map(way => stage(way.data)).read(id)
val word = data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange))
when(stage(io.cpu.fetch.dataBypassValid)){
val word = if(cpuDataWidth == memDataWidth) data else data.subdivideIn(cpuDataWidth bits).read(io.cpu.decode.pc(memWordToCpuWordRange))
if(p.bypassGen) when(stage(io.cpu.fetch.dataBypassValid)){
word := stage(io.cpu.fetch.dataBypass)
}
io.cpu.decode.data := word

View file

@ -53,7 +53,8 @@ trait PredictionInterface{
class BranchPlugin(earlyBranch : Boolean,
catchAddressMisaligned : Boolean = false,
fenceiGenAsAJump : Boolean = false,
fenceiGenAsANop : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{
fenceiGenAsANop : Boolean = false,
decodeBranchSrc2 : Boolean = false) extends Plugin[VexRiscv] with PredictionInterface{
def catchAddressMisalignedForReal = catchAddressMisaligned && !pipeline(RVC_GEN)
@ -310,6 +311,8 @@ class BranchPlugin(earlyBranch : Boolean,
//Do branch calculations (conditions + target PC)
object NEXT_PC extends Stageable(UInt(32 bits))
object TARGET_MISSMATCH extends Stageable(Bool)
object BRANCH_SRC2 extends Stageable(UInt(32 bits))
val branchSrc2Stage = if(decodeBranchSrc2) decode else execute
execute plug new Area {
import execute._
@ -328,15 +331,16 @@ class BranchPlugin(earlyBranch : Boolean,
)
)
val imm = IMM(input(INSTRUCTION))
val branch_src1 = (input(BRANCH_CTRL) === BranchCtrlEnum.JALR) ? input(RS1).asUInt | input(PC)
val branch_src2 = input(BRANCH_CTRL).mux(
val imm = IMM(branchSrc2Stage.input(INSTRUCTION))
branchSrc2Stage.insert(BRANCH_SRC2) := branchSrc2Stage.input(BRANCH_CTRL).mux(
BranchCtrlEnum.JAL -> imm.j_sext,
BranchCtrlEnum.JALR -> imm.i_sext,
default -> imm.b_sext
).asUInt
val branchAdder = branch_src1 + branch_src2
val branchAdder = branch_src1 + input(BRANCH_SRC2)
insert(BRANCH_CALC) := branchAdder(31 downto 1) @@ "0"
insert(NEXT_PC) := input(PC) + (if(pipeline(RVC_GEN)) ((input(IS_RVC)) ? U(2) | U(4)) else 4)
insert(TARGET_MISSMATCH) := decode.input(PC) =/= input(BRANCH_CALC)

View file

@ -0,0 +1,289 @@
package vexriscv.plugin
import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv}
import spinal.core._
import spinal.lib._
import spinal.lib.bus.bmb.WeakConnector
import spinal.lib.bus.misc.{AddressMapping, DefaultMapping}
case class CfuPluginParameter(
CFU_VERSION : Int,
CFU_INTERFACE_ID_W : Int,
CFU_FUNCTION_ID_W : Int,
CFU_REORDER_ID_W : Int,
CFU_REQ_RESP_ID_W : Int,
CFU_INPUTS : Int,
CFU_INPUT_DATA_W : Int,
CFU_OUTPUTS : Int,
CFU_OUTPUT_DATA_W : Int,
CFU_FLOW_REQ_READY_ALWAYS : Boolean,
CFU_FLOW_RESP_READY_ALWAYS : Boolean)
case class CfuBusParameter(CFU_VERSION : Int,
CFU_INTERFACE_ID_W : Int,
CFU_FUNCTION_ID_W : Int,
CFU_REORDER_ID_W : Int,
CFU_REQ_RESP_ID_W : Int,
CFU_INPUTS : Int,
CFU_INPUT_DATA_W : Int,
CFU_OUTPUTS : Int,
CFU_OUTPUT_DATA_W : Int,
CFU_FLOW_REQ_READY_ALWAYS : Boolean,
CFU_FLOW_RESP_READY_ALWAYS : Boolean)
case class CfuCmd( p : CfuBusParameter ) extends Bundle{
val function_id = UInt(p.CFU_FUNCTION_ID_W bits)
val reorder_id = UInt(p.CFU_REORDER_ID_W bits)
val request_id = UInt(p.CFU_REQ_RESP_ID_W bits)
val inputs = Vec(Bits(p.CFU_INPUT_DATA_W bits), p.CFU_INPUTS)
def weakAssignFrom(m : CfuCmd): Unit ={
def s = this
WeakConnector(m, s, m.function_id, s.function_id, defaultValue = null, allowUpSize = false, allowDownSize = true , allowDrop = true)
WeakConnector(m, s, m.reorder_id, s.reorder_id, defaultValue = null, allowUpSize = false , allowDownSize = false, allowDrop = false)
WeakConnector(m, s, m.request_id, s.request_id, defaultValue = null, allowUpSize = false, allowDownSize = false, allowDrop = false)
s.inputs := m.inputs
}
}
case class CfuRsp(p : CfuBusParameter) extends Bundle{
val response_ok = Bool()
val response_id = UInt(p.CFU_REQ_RESP_ID_W bits)
val outputs = Vec(Bits(p.CFU_OUTPUT_DATA_W bits), p.CFU_OUTPUTS)
def weakAssignFrom(m : CfuRsp): Unit ={
def s = this
s.response_ok := m.response_ok
s.response_id := m.response_id
s.outputs := m.outputs
}
}
case class CfuBus(p : CfuBusParameter) extends Bundle with IMasterSlave{
val cmd = Stream(CfuCmd(p))
val rsp = Stream(CfuRsp(p))
def <<(m : CfuBus) : Unit = {
val s = this
s.cmd.arbitrationFrom(m.cmd)
m.rsp.arbitrationFrom(s.rsp)
s.cmd.weakAssignFrom(m.cmd)
m.rsp.weakAssignFrom(s.rsp)
}
override def asMaster(): Unit = {
master(cmd)
slave(rsp)
}
}
class CfuPlugin( val stageCount : Int,
val allowZeroLatency : Boolean,
val encoding : MaskedLiteral,
val busParameter : CfuBusParameter) extends Plugin[VexRiscv]{
def p = busParameter
assert(p.CFU_INPUTS <= 2)
assert(p.CFU_OUTPUTS == 1)
assert(p.CFU_FUNCTION_ID_W == 3)
var bus : CfuBus = null
var joinException : Flow[ExceptionCause] = null
lazy val forkStage = pipeline.execute
lazy val joinStage = pipeline.stages(Math.min(pipeline.stages.length - 1, pipeline.indexOf(forkStage) + stageCount))
val CFU_ENABLE = new Stageable(Bool()).setCompositeName(this, "CFU_ENABLE")
val CFU_IN_FLIGHT = new Stageable(Bool()).setCompositeName(this, "CFU_IN_FLIGHT")
override def setup(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
bus = master(CfuBus(p))
joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(CFU_ENABLE, False)
//custom-0
decoderService.add(List(
encoding -> List(
CFU_ENABLE -> True,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> Bool(stageCount == 0),
BYPASSABLE_MEMORY_STAGE -> Bool(stageCount <= 1),
RS1_USE -> True,
RS2_USE -> True
)
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
forkStage plug new Area{
import forkStage._
val schedule = arbitration.isValid && input(CFU_ENABLE)
val hold = RegInit(False) setWhen(schedule) clearWhen(bus.cmd.ready)
val fired = RegInit(False) setWhen(bus.cmd.fire) clearWhen(!arbitration.isStuckByOthers)
insert(CFU_IN_FLIGHT) := schedule || hold || fired
bus.cmd.valid := (schedule || hold) && !fired
arbitration.haltItself setWhen(bus.cmd.valid && !bus.cmd.ready)
bus.cmd.function_id := U(input(INSTRUCTION)(14 downto 12)).resized
bus.cmd.reorder_id := 0
bus.cmd.request_id := 0
if(p.CFU_INPUTS >= 1) bus.cmd.inputs(0) := input(RS1)
if(p.CFU_INPUTS >= 2) bus.cmd.inputs(1) := input(RS2)
}
joinStage plug new Area{
import joinStage._
//If the CFU interface can produce a result combinatorialy and the fork stage isn't the same than the join stage
//Then it is required to add a buffer on rsp to not propagate the fork stage ready := False in the CPU pipeline.
val rsp = if(p.CFU_FLOW_RESP_READY_ALWAYS){
bus.rsp.toFlow.toStream.queueLowLatency(
size = stageCount + 1,
latency = 0
)
} else if(forkStage != joinStage && allowZeroLatency) {
bus.rsp.m2sPipe()
} else {
bus.rsp.combStage()
}
joinException.valid := False
joinException.code := 15
joinException.badAddr := 0
rsp.ready := False
when(input(CFU_IN_FLIGHT)){
arbitration.haltItself setWhen(!rsp.valid)
rsp.ready := !arbitration.isStuckByOthers
output(REGFILE_WRITE_DATA) := rsp.outputs(0)
when(arbitration.isValid){
joinException.valid := !rsp.response_ok
}
}
}
addPrePopTask(() => stages.dropWhile(_ != memory).reverse.dropWhile(_ != joinStage).foreach(s => s.input(CFU_IN_FLIGHT).init(False)))
}
}
object CfuTest{
// stageCount = 0,
// allowZeroLatency = true,
def getCfuParameter() = CfuBusParameter(
CFU_VERSION = 0,
CFU_INTERFACE_ID_W = 0,
CFU_FUNCTION_ID_W = 3,
CFU_REORDER_ID_W = 0,
CFU_REQ_RESP_ID_W = 0,
CFU_INPUTS = 2,
CFU_INPUT_DATA_W = 32,
CFU_OUTPUTS = 1,
CFU_OUTPUT_DATA_W = 32,
CFU_FLOW_REQ_READY_ALWAYS = false,
CFU_FLOW_RESP_READY_ALWAYS = false
)
}
case class CfuTest() extends Component{
val io = new Bundle {
val bus = slave(CfuBus(CfuTest.getCfuParameter()))
}
io.bus.rsp.arbitrationFrom(io.bus.cmd)
io.bus.rsp.response_ok := True
io.bus.rsp.response_id := io.bus.cmd.request_id
io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1))
}
case class CfuBb(p : CfuBusParameter) extends BlackBox{
val io = new Bundle {
val clk, reset = in Bool()
val bus = slave(CfuBus(p))
}
mapCurrentClockDomain(io.clk, io.reset)
}
//case class CfuGray(p : CfuBusParameter) extends BlackBox{
// val req_function_id = in Bits(p.CFU_FUNCTION_ID_W)
// val req_data = in Bits(p.CFU_REQ_INPUTS)
// val resp_data = in Bits(p.CFU_FUNCTION_ID_W)
// input `CFU_FUNCTION_ID req_function_id,
// input [CFU_REQ_INPUTS-1:0]`CFU_REQ_DATA req_data,
// output [CFU_RESP_OUTPUTS-1:0]`CFU_RESP_DATA resp_data
// io.bus.rsp.arbitrationFrom(io.bus.cmd)
// io.bus.rsp.response_ok := True
// io.bus.rsp.response_id := io.bus.cmd.request_id
// io.bus.rsp.outputs(0) := ~(io.bus.cmd.inputs(0) & io.bus.cmd.inputs(1))
//}
case class CfuDecoder(p : CfuBusParameter,
mappings : Seq[AddressMapping],
pendingMax : Int = 3) extends Component{
val io = new Bundle {
val input = slave(CfuBus(p))
val outputs = Vec(master(CfuBus(p)), mappings.size)
}
val hasDefault = mappings.contains(DefaultMapping)
val logic = if(hasDefault && mappings.size == 1){
io.outputs(0) << io.input
} else new Area {
val hits = Vec(Bool, mappings.size)
for (portId <- 0 until mappings.length) yield {
val slaveBus = io.outputs(portId)
val memorySpace = mappings(portId)
val hit = hits(portId)
hit := (memorySpace match {
case DefaultMapping => !hits.filterNot(_ == hit).orR
case _ => memorySpace.hit(io.input.cmd.function_id)
})
slaveBus.cmd.valid := io.input.cmd.valid && hit
slaveBus.cmd.payload := io.input.cmd.payload.resized
}
val noHit = if (!hasDefault) !hits.orR else False
io.input.cmd.ready := (hits, io.outputs).zipped.map(_ && _.cmd.ready).orR || noHit
val rspPendingCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init(0)
rspPendingCounter := rspPendingCounter + U(io.input.cmd.fire) - U(io.input.rsp.fire)
val rspHits = RegNextWhen(hits, io.input.cmd.fire)
val rspPending = rspPendingCounter =/= 0
val rspNoHitValid = if (!hasDefault) !rspHits.orR else False
val rspNoHit = !hasDefault generate new Area{
val doIt = RegInit(False) clearWhen(io.input.rsp.fire) setWhen(io.input.cmd.fire && noHit)
val response_id = RegNextWhen(io.input.cmd.request_id, io.input.cmd.fire)
}
io.input.rsp.valid := io.outputs.map(_.rsp.valid).orR || (rspPending && rspNoHitValid)
io.input.rsp.payload := io.outputs.map(_.rsp.payload).read(OHToUInt(rspHits))
if(!hasDefault) when(rspNoHit.doIt) {
io.input.rsp.valid := True
io.input.rsp.response_ok := False
io.input.rsp.response_id := rspNoHit.response_id
}
for(output <- io.outputs) output.rsp.ready := io.input.rsp.ready
val cmdWait = (rspPending && (hits =/= rspHits || rspNoHitValid)) || rspPendingCounter === pendingMax
when(cmdWait) {
io.input.cmd.ready := False
io.outputs.foreach(_.cmd.valid := False)
}
}
}

View file

@ -69,7 +69,8 @@ case class CsrPluginConfig(
midelegAccess : CsrAccess = CsrAccess.NONE,
pipelineCsrRead : Boolean = false,
pipelinedInterrupt : Boolean = true,
deterministicInteruptionEntry : Boolean = false //Only used for simulatation purposes
deterministicInteruptionEntry : Boolean = false, //Only used for simulatation purposes
wfiOutput : Boolean = false
){
assert(!ucycleAccess.canWrite)
def privilegeGen = userGen || supervisorGen
@ -311,8 +312,11 @@ trait CsrInterface{
trait IContextSwitching{
def isContextSwitching : Bool
}
trait IWake{
def askWake() : Unit
}
class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface{
class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with ExceptionService with PrivilegeService with InterruptionInhibitor with ExceptionInhibitor with IContextSwitching with CsrInterface with IWake{
import config._
import CsrAccess._
@ -322,7 +326,6 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
//Mannage ExceptionService calls
val exceptionPortsInfos = ArrayBuffer[ExceptionPortInfo]()
def exceptionCodeWidth = 4
override def newExceptionPort(stage : Stage, priority : Int = 0) = {
val interface = Flow(ExceptionCause())
exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority)
@ -332,6 +335,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
var exceptionPendings : Vec[Bool] = null
override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage))
var redoInterface : Flow[UInt] = null
var jumpInterface : Flow[UInt] = null
var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null
var externalInterruptS : Bool = null
@ -339,6 +343,11 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
var privilege : UInt = null
var selfException : Flow[ExceptionCause] = null
var contextSwitching : Bool = null
var thirdPartyWake : Bool = null
var inWfi : Bool = null
override def askWake(): Unit = thirdPartyWake := True
override def isContextSwitching = contextSwitching
object EnvCtrlEnum extends SpinalEnum(binarySequential){
@ -359,6 +368,16 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
val csrMapping = new CsrMapping()
//Print CSR mapping
def printCsr() {
for ((address, things) <- csrMapping.mapping) {
println("0x" + address.toHexString + " => ")
for (thing <- things) {
println(" - " + thing)
}
}
}
//Interruption and exception data model
case class Delegator(var enable : Bool, privilege : Int)
case class InterruptSpec(var cond : Bool, id : Int, privilege : Int, delegators : List[Delegator])
@ -379,6 +398,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
inWfi = False.addTag(Verilator.public)
thirdPartyWake = False
val defaultEnv = List[(Stageable[_ <: BaseType],Any)](
)
@ -422,6 +445,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
jumpInterface.valid := False
jumpInterface.payload.assignDontCare()
if(supervisorGen) {
redoInterface = pcManagerService.createJumpInterface(pipeline.execute)
redoInterface.valid := False
redoInterface.payload.assignDontCare()
}
exceptionPendings = Vec(Bool, pipeline.stages.length)
timerInterrupt = in Bool() setName("timerInterrupt")
externalInterrupt = in Bool() setName("externalInterrupt")
@ -459,6 +489,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
import pipeline._
import pipeline.config._
val fetcher = service(classOf[IBusFetcher])
val trapCodeWidth = log2Up((List(16) ++ interruptSpecs.map(_.id + 1) ++ exceptionPortsInfos.map(p => 1 << widthOf(p.port.code))).max)
//Define CSR mapping utilities
implicit class CsrAccessPimper(csrAccess : CsrAccess){
@ -511,7 +542,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
val mscratch = if(mscratchGen) Reg(Bits(xlen bits)) else null
val mcause = new Area{
val interrupt = Reg(Bool)
val exceptionCode = Reg(UInt(exceptionCodeWidth bits))
val exceptionCode = Reg(UInt(trapCodeWidth bits))
}
val mtval = Reg(UInt(xlen bits))
val mcycle = Reg(UInt(64 bits)) randBoot()
@ -582,7 +613,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
val scause = new Area {
val interrupt = Reg(Bool)
val exceptionCode = Reg(UInt(exceptionCodeWidth bits))
val exceptionCode = Reg(UInt(trapCodeWidth bits))
}
val stval = Reg(UInt(xlen bits))
val sepc = Reg(UInt(xlen bits))
@ -610,6 +641,13 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
scauseAccess(CSR.SCAUSE, xlen-1 -> scause.interrupt, 0 -> scause.exceptionCode)
sbadaddrAccess(CSR.SBADADDR, stval)
satpAccess(CSR.SATP, 31 -> satp.MODE, 22 -> satp.ASID, 0 -> satp.PPN)
if(supervisorGen) onWrite(CSR.SATP){
execute.arbitration.flushNext := True
redoInterface.valid := True
redoInterface.payload := execute.input(PC) + 4
}
}
}
@ -733,7 +771,7 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
//Process interrupt request, code and privilege
val interrupt = new Area {
val valid = if(pipelinedInterrupt) RegNext(False) init(False) else False
val code = if(pipelinedInterrupt) Reg(UInt(4 bits)) else UInt(4 bits).assignDontCare()
val code = if(pipelinedInterrupt) Reg(UInt(trapCodeWidth bits)) else UInt(trapCodeWidth bits).assignDontCare()
var privilegs = if (supervisorGen) List(1, 3) else List(3)
val targetPrivilege = if(pipelinedInterrupt) Reg(UInt(2 bits)) else UInt(2 bits).assignDontCare()
val privilegeAllowInterrupts = mutable.HashMap[Int, Bool]()
@ -838,6 +876,10 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
}
}
if(exceptionPortCtrl == null){
if(mbadaddrAccess == CsrAccess.READ_ONLY) mtval := 0
if(sbadaddrAccess == CsrAccess.READ_ONLY) stval := 0
}
lastStage plug new Area{
import lastStage._
@ -885,8 +927,8 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
execute plug new Area{
import execute._
//Manage WFI instructions
val inWfi = False.addTag(Verilator.public)
val wfiWake = RegNext(interruptSpecs.map(_.cond).orR) init(False)
if(wfiOutput) out(inWfi)
val wfiWake = RegNext(interruptSpecs.map(_.cond).orR || thirdPartyWake) init(False)
if(wfiGenAsWait) when(arbitration.isValid && input(ENV_CTRL) === EnvCtrlEnum.WFI){
inWfi := True
when(!wfiWake){
@ -1044,3 +1086,18 @@ class CsrPlugin(val config: CsrPluginConfig) extends Plugin[VexRiscv] with Excep
}
}
}
class UserInterruptPlugin(interruptName : String, code : Int, privilege : Int = 3) extends Plugin[VexRiscv]{
var interrupt, interruptEnable : Bool = null
override def setup(pipeline: VexRiscv): Unit = {
val csr = pipeline.service(classOf[CsrPlugin])
interrupt = in.Bool().setName(interruptName)
val interruptPending = RegNext(interrupt) init(False)
val interruptEnable = RegInit(False).setName(interruptName + "_enable")
csr.addInterrupt(interruptPending , code, privilege, Nil)
csr.r(csrAddress = CSR.MIP, bitOffset = code,interruptPending)
csr.rw(csrAddress = CSR.MIE, bitOffset = code, interruptEnable)
}
override def build(pipeline: VexRiscv): Unit = {}
}

View file

@ -225,7 +225,13 @@ class DBusCachedPlugin(val config : DataCacheConfig,
arbitration.haltItself := True
}
if(relaxedMemoryTranslationRegister) insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address
if(relaxedMemoryTranslationRegister) {
insert(MEMORY_VIRTUAL_ADDRESS) := cache.io.cpu.execute.address
memory.input(MEMORY_VIRTUAL_ADDRESS)
if(writeBack != null) addPrePopTask( () =>
KeepAttribute(memory.input(MEMORY_VIRTUAL_ADDRESS).getDrivingReg)
)
}
}
val mmuAndBufferStage = if(writeBack != null) memory else execute

View file

@ -246,6 +246,11 @@ class DebugPlugin(val debugClockDomain : ClockDomain, hardwareBreakpointCount :
}
if(pipeline.things.contains(DEBUG_BYPASS_CACHE)) pipeline(DEBUG_BYPASS_CACHE) := True
}
val wakeService = serviceElse(classOf[IWake], null)
if(wakeService != null) when(haltIt){
wakeService.askWake()
}
}}
}
}

View file

@ -61,7 +61,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
var redoBranch : Flow[UInt] = null
var decodeExceptionPort : Flow[ExceptionCause] = null
val tightlyCoupledPorts = ArrayBuffer[TightlyCoupledPort]()
def tightlyGen = tightlyCoupledPorts.nonEmpty
def newTightlyCoupledPort(p : TightlyCoupledPortParameter) = {
val port = TightlyCoupledPort(p, null)
@ -125,7 +125,7 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
import pipeline.config._
pipeline plug new FetchArea(pipeline) {
val cache = new InstructionCache(IBusCachedPlugin.this.config)
val cache = new InstructionCache(IBusCachedPlugin.this.config.copy(bypassGen = tightlyGen))
iBus = master(new InstructionCacheMemBus(IBusCachedPlugin.this.config)).setName("iBus")
iBus <> cache.io.mem
iBus.cmd.address.allowOverride := cache.io.mem.cmd.address
@ -165,8 +165,8 @@ class IBusCachedPlugin(resetVector : BigInt = 0x80000000l,
val tightlyCoupledHits = RegNextWhen(s0.tightlyCoupledHits, stages(1).input.ready)
val tightlyCoupledHit = RegNextWhen(s0.tightlyCoupledHit, stages(1).input.ready)
cache.io.cpu.fetch.dataBypassValid := tightlyCoupledHit
cache.io.cpu.fetch.dataBypass := (if(tightlyCoupledPorts.isEmpty) B(0) else MuxOH(tightlyCoupledHits, tightlyCoupledPorts.map(e => CombInit(e.bus.data))))
if(tightlyGen) cache.io.cpu.fetch.dataBypassValid := tightlyCoupledHit
if(tightlyGen) cache.io.cpu.fetch.dataBypass := MuxOH(tightlyCoupledHits, tightlyCoupledPorts.map(e => CombInit(e.bus.data)))
//Connect fetch cache side
cache.io.cpu.fetch.isValid := stages(1).input.valid && !tightlyCoupledHit

View file

@ -3,7 +3,8 @@ import vexriscv._
import vexriscv.VexRiscv
import spinal.core._
class MulPlugin extends Plugin[VexRiscv]{
//Input buffer generaly avoid the FPGA synthesis to duplicate reg inside the DSP cell, which could stress timings quite much.
class MulPlugin(inputBuffer : Boolean = false) extends Plugin[VexRiscv]{
object MUL_LL extends Stageable(UInt(32 bits))
object MUL_LH extends Stageable(SInt(34 bits))
object MUL_HL extends Stageable(SInt(34 bits))
@ -19,8 +20,8 @@ class MulPlugin extends Plugin[VexRiscv]{
val actions = List[(Stageable[_ <: BaseType],Any)](
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
// SRC1_CTRL -> Src1CtrlEnum.RS,
// SRC2_CTRL -> Src2CtrlEnum.RS,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False,
@ -48,8 +49,26 @@ class MulPlugin extends Plugin[VexRiscv]{
val aSigned,bSigned = Bool
val a,b = Bits(32 bit)
a := input(SRC1)
b := input(SRC2)
// a := input(SRC1)
// b := input(SRC2)
val withInputBuffer = inputBuffer generate new Area{
val rs1 = RegNext(input(RS1))
val rs2 = RegNext(input(RS2))
a := rs1
b := rs2
val delay = RegNext(arbitration.isStuck)
when(arbitration.isValid && input(IS_MUL) && !delay){
arbitration.haltItself := True
}
}
val noInputBuffer = (!inputBuffer) generate new Area{
a := input(RS1)
b := input(RS2)
}
switch(input(INSTRUCTION)(13 downto 12)) {
is(B"01") {
aSigned := True

View file

@ -8,19 +8,6 @@ import scala.collection.mutable.ArrayBuffer
object KeepAttribute{
object syn_keep_verilog extends AttributeFlag("synthesis syn_keep = 1", COMMENT_ATTRIBUTE){
override def isLanguageReady(language: Language) : Boolean = language == Language.VERILOG || language == Language.SYSTEM_VERILOG
}
object syn_keep_vhdl extends AttributeFlag("syn_keep"){
override def isLanguageReady(language: Language) : Boolean = language == Language.VHDL
}
object keep extends AttributeFlag("keep")
def apply[T <: Data](that : T) = that.addAttribute(keep).addAttribute(syn_keep_verilog).addAttribute(syn_keep_vhdl)
}
class PcManagerSimplePlugin(resetVector : BigInt,
relaxedPcCalculation : Boolean = false,

View file

@ -96,6 +96,11 @@ class RegFilePlugin(regFileReadyKind : RegFileReadKind,
regFileWrite.address := U(shadowPrefix(output(INSTRUCTION)(rdRange)))
regFileWrite.data := output(REGFILE_WRITE_DATA)
//Ensure no boot glitches modify X0
if(!x0Init && zeroBoot) when(regFileWrite.address === 0){
regFileWrite.valid := False
}
//CPU will initialise constant register zero in the first cycle
if(x0Init) {
val boot = RegNext(False) init (True)

View file

@ -1548,7 +1548,7 @@ public:
riscvRef.ipInput |= top->externalInterruptS << 9;
#endif
riscvRef.liveness(top->VexRiscv->execute_CsrPlugin_inWfi);
riscvRef.liveness(top->VexRiscv->CsrPlugin_inWfi);
if(top->VexRiscv->CsrPlugin_interruptJump){
if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interrupt_code);
}