Reorganize project

This commit is contained in:
Charles Papon 2017-03-16 13:14:25 +01:00
parent bf5bebda08
commit 401be6ca83
16 changed files with 999 additions and 934 deletions

View File

@ -1,5 +1,6 @@
package SpinalRiscv
import SpinalRiscv.Plugin.Plugin
import spinal.core._
import scala.collection.mutable

View File

@ -0,0 +1,131 @@
package SpinalRiscv.Plugin
import SpinalRiscv._
import spinal.core._
import spinal.lib._
case class DBusSimpleCmd() extends Bundle{
val wr = Bool
val address = UInt(32 bits)
val data = Bits(32 bit)
val size = UInt(2 bit)
}
case class DBusSimpleRsp() extends Bundle{
val data = Bits(32 bit)
}
class DBusSimplePlugin extends Plugin[VexRiscv]{
var dCmd : Stream[DBusSimpleCmd] = null
var dRsp : DBusSimpleRsp = null
object MemoryCtrlEnum extends SpinalEnum{
val WR, RD = newElement()
}
object MEMORY_ENABLE extends Stageable(Bool)
object MEMORY_CTRL extends Stageable(MemoryCtrlEnum())
object MEMORY_READ_DATA extends Stageable(Bits(32 bits))
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
val stdActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC_USE_SUB_LESS -> False,
MEMORY_ENABLE -> True,
REG1_USE -> True
)
val loadActions = stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False
)
val storeActions = stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.IMS,
REG2_USE -> True
)
decoderService.addDefault(MEMORY_ENABLE, False)
decoderService.add(List(
LB -> (loadActions),
LH -> (loadActions),
LW -> (loadActions),
LBU -> (loadActions),
LHU -> (loadActions),
LWU -> (loadActions),
SB -> (storeActions),
SH -> (storeActions),
SW -> (storeActions)
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area{
import execute._
dCmd = master(Stream(DBusSimpleCmd())).setName("dCmd")
dCmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers
dCmd.wr := input(INSTRUCTION)(5)
dCmd.address := input(SRC_ADD_SUB).asUInt
dCmd.size := input(INSTRUCTION)(13 downto 12).asUInt
dCmd.payload.data := dCmd.size.mux (
U(0) -> input(REG2)(7 downto 0) ## input(REG2)(7 downto 0) ## input(REG2)(7 downto 0) ## input(REG2)(7 downto 0),
U(1) -> input(REG2)(15 downto 0) ## input(REG2)(15 downto 0),
default -> input(REG2)(31 downto 0)
)
when(arbitration.isValid && input(MEMORY_ENABLE) && !dCmd.ready){
arbitration.haltIt := True
}
insert(MEMORY_ADDRESS_LOW) := dCmd.address(1 downto 0)
}
memory plug new Area {
import memory._
dRsp = in(DBusSimpleRsp()).setName("dRsp")
insert(MEMORY_READ_DATA) := dRsp.data
assert(!(input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend")
}
writeBack plug new Area {
import writeBack._
val rspShifted = MEMORY_READ_DATA()
rspShifted := input(MEMORY_READ_DATA)
switch(input(MEMORY_ADDRESS_LOW)){
is(1){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(15 downto 8)}
is(2){rspShifted(15 downto 0) := input(MEMORY_READ_DATA)(31 downto 16)}
is(3){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(31 downto 24)}
}
val rspFormated = input(INSTRUCTION)(13 downto 12).mux(
0 -> B((31 downto 8) -> (rspShifted(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(7 downto 0)),
1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)),
default -> rspShifted //W
)
when(input(MEMORY_ENABLE)) {
input(REGFILE_WRITE_DATA) := rspFormated
}
assert(!(input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend")
}
}
}

View File

@ -0,0 +1,126 @@
package SpinalRiscv.Plugin
import SpinalRiscv._
import spinal.core._
import spinal.lib._
import scala.Predef.assert
import scala.collection.mutable
case class Masked(value : BigInt,care : BigInt){
}
class DecoderSimplePlugin extends Plugin[VexRiscv] with DecoderService {
override def add(encoding: Seq[(MaskedLiteral, Seq[(Stageable[_ <: BaseType], Any)])]): Unit = encoding.foreach(e => this.add(e._1,e._2))
override def add(key: MaskedLiteral, values: Seq[(Stageable[_ <: BaseType], Any)]): Unit = {
assert(!encodings.contains(key))
encodings(key) = values.map{case (a,b) => (a,b match{
case e : SpinalEnumElement[_] => e()
case e : BaseType => e
})}
}
override def addDefault(key: Stageable[_ <: BaseType], value: Any): Unit = {
assert(!defaults.contains(key))
defaults(key) = value match{
case e : SpinalEnumElement[_] => e()
case e : BaseType => e
}
}
val defaults = mutable.HashMap[Stageable[_ <: BaseType], BaseType]()
val encodings = mutable.HashMap[MaskedLiteral,Seq[(Stageable[_ <: BaseType], BaseType)]]()
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
addDefault(LEGAL_INSTRUCTION, False)
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline.config._
import pipeline.decode._
val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toSet.toList
var offset = 0
var defaultValue, defaultCare = BigInt(0)
val offsetOf = mutable.HashMap[Stageable[_ <: BaseType],Int]()
//Build defaults value and field offset map
stageables.foreach(e => {
defaults.get(e) match {
case Some(value) => {
value.input match {
case literal: EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding)
case _ =>
}
defaultValue += value.input.asInstanceOf[Literal].getValue << offset
defaultCare += ((BigInt(1) << e.dataType.getBitsWidth) - 1) << offset
}
case _ =>
}
offsetOf(e) = offset
offset += e.dataType.getBitsWidth
})
//Build spec
val spec = encodings.map { case (key, values) =>
var decodedValue, decodedCare = BigInt(0)
for((e, literal) <- values){
literal.input match{
case literal : EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding)
case _ =>
}
val offset = offsetOf(e)
decodedValue += literal.input.asInstanceOf[Literal].getValue << offset
decodedCare += ((BigInt(1) << e.dataType.getBitsWidth)-1) << offset
}
(Masked(key.value,key.careAbout),Masked(decodedValue,decodedCare))
}
// logic implementation
val decodedBits = Bits(stageables.foldLeft(0)(_ + _.dataType.getBitsWidth) bits)
val defaultBits = cloneOf(decodedBits)
assert(defaultValue == 0)
defaultBits := defaultValue
val logicOr = for((key, mapping) <- spec) yield Mux[Bits](((input(INSTRUCTION) & key.care) === (key.value & key.care)), B(mapping.value & mapping.care, decodedBits.getWidth bits) , B(0, decodedBits.getWidth bits))
decodedBits := logicOr.foldLeft(defaultBits)(_ | _)
// for(i <- decodedBits.range)
// if(defaultCare.testBit(i))
// defaultBits(i) := Bool(defaultValue.testBit(i))
// else
// defaultBits(i).assignDontCare()
// val logicOr = for((key, mapping) <- spec) yield Mux[Bits](((input(INSTRUCTION) & key.care) === (key.value & key.care)), B(mapping.value & mapping.care, decodedBits.getWidth bits) , B(0, decodedBits.getWidth bits))
// val logicAnd = for((key, mapping) <- spec) yield Mux[Bits](((input(INSTRUCTION) & key.care) === (key.value & key.care)), B(~mapping.value & mapping.care, decodedBits.getWidth bits) , B(0, decodedBits.getWidth bits))
// decodedBits := (defaultBits | logicOr.foldLeft(B(0, decodedBits.getWidth bits))(_ | _)) & ~logicAnd.foldLeft(B(0, decodedBits.getWidth bits))(_ | _)
//Unpack decodedBits and insert fields in the pipeline
offset = 0
stageables.foreach(e => {
insert(e).assignFromBits(decodedBits(offset, e.dataType.getBitsWidth bits))
// insert(e).assignFromBits(RegNext(decodedBits(offset, e.dataType.getBitsWidth bits)))
offset += e.dataType.getBitsWidth
})
}
def bench(toplevel : VexRiscv): Unit ={
toplevel.rework{
import toplevel.config._
toplevel.getAllIo.toList.foreach(_.asDirectionLess())
toplevel.decode.input(INSTRUCTION) := Delay((in Bits(32 bits)).setName("instruction"),2)
val stageables = encodings.flatMap(_._2.map(_._1)).toSet
stageables.foreach(e => out(Delay(toplevel.decode.insert(e),2)).setName(e.getName))
toplevel.getAdditionalNodesRoot.clear()
}
}
}

View File

@ -0,0 +1,83 @@
package SpinalRiscv.Plugin
import SpinalRiscv._
import spinal.core._
import spinal.lib.Reverse
class FullBarrielShifterPlugin extends Plugin[VexRiscv]{
object ShiftCtrlEnum extends SpinalEnum(binarySequential){
val DISABLE, SLL, SRL, SRA = newElement()
}
object SHIFT_CTRL extends Stageable(ShiftCtrlEnum())
object SHIFT_RIGHT extends Stageable(Bits(32 bits))
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True
)
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True,
REG2_USE -> True
)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(SHIFT_CTRL, ShiftCtrlEnum.DISABLE)
decoderService.add(List(
SLL -> (nonImmediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SLL)),
SRL -> (nonImmediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRL)),
SRA -> (nonImmediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRA))
))
decoderService.add(List(
SLLI -> (immediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SLL)),
SRLI -> (immediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRL)),
SRAI -> (immediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRA))
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area{
import execute._
val amplitude = input(SRC2)(4 downto 0).asUInt
val reversed = Mux(input(SHIFT_CTRL) === ShiftCtrlEnum.SLL, Reverse(input(SRC1)), input(SRC1))
insert(SHIFT_RIGHT) := (Cat(input(SHIFT_CTRL) === ShiftCtrlEnum.SRA & reversed.msb, reversed).asSInt >> amplitude)(31 downto 0).asBits
}
memory plug new Area{
import memory._
switch(input(SHIFT_CTRL)){
is(ShiftCtrlEnum.SLL){
output(REGFILE_WRITE_DATA) := Reverse(input(SHIFT_RIGHT))
}
is(ShiftCtrlEnum.SRL,ShiftCtrlEnum.SRA){
output(REGFILE_WRITE_DATA) := input(SHIFT_RIGHT)
}
}
}
}
}

View File

@ -0,0 +1,93 @@
package SpinalRiscv.Plugin
import SpinalRiscv._
import spinal.core._
import spinal.lib._
class HazardSimplePlugin(bypassExecute : Boolean,bypassMemory: Boolean,bypassWriteBack: Boolean, bypassWriteBackBuffer : Boolean) extends Plugin[VexRiscv] {
import Riscv._
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
val src0Hazard = False
val src1Hazard = False
//Disable rd0 write in decoding stage
when(decode.input(INSTRUCTION)(rdRange) === 0) {
decode.input(REGFILE_WRITE_VALID) := False
}
def trackHazardWithStage(stage : Stage,bypassable : Boolean, runtimeBypassable : Stageable[Bool]): Unit ={
val runtimeBypassableValue = if(runtimeBypassable != null) stage.input(runtimeBypassable) else True
val addr0Match = stage.input(INSTRUCTION)(rdRange) === decode.input(INSTRUCTION)(rs1Range)
val addr1Match = stage.input(INSTRUCTION)(rdRange) === decode.input(INSTRUCTION)(rs2Range)
when(stage.arbitration.isValid && stage.input(REGFILE_WRITE_VALID)) {
if (bypassable) {
when(runtimeBypassableValue) {
when(addr0Match) {
decode.input(REG1) := stage.output(REGFILE_WRITE_DATA)
}
when(addr1Match) {
decode.input(REG2) := stage.output(REGFILE_WRITE_DATA)
}
}
}
when((Bool(!bypassable) || !runtimeBypassableValue)) {
when(addr0Match) {
src0Hazard := True
}
when(addr1Match) {
src1Hazard := True
}
}
}
}
val writeBackWrites = Flow(cloneable(new Bundle{
val address = Bits(5 bits)
val data = Bits(32 bits)
}))
writeBackWrites.valid := writeBack.output(REGFILE_WRITE_VALID) && writeBack.arbitration.isFiring
writeBackWrites.address := writeBack.output(INSTRUCTION)(rdRange)
writeBackWrites.data := writeBack.output(REGFILE_WRITE_DATA)
val writeBackBuffer = writeBackWrites.stage()
val addr0Match = writeBackBuffer.address === decode.input(INSTRUCTION)(rs1Range)
val addr1Match = writeBackBuffer.address === decode.input(INSTRUCTION)(rs2Range)
when(writeBackBuffer.valid) {
if (bypassWriteBackBuffer) {
when(addr0Match) {
decode.input(REG1) := writeBackBuffer.data
}
when(addr1Match) {
decode.input(REG2) := writeBackBuffer.data
}
} else {
when(addr0Match) {
src0Hazard := True
}
when(addr1Match) {
src1Hazard := True
}
}
}
trackHazardWithStage(writeBack,bypassWriteBack,null)
trackHazardWithStage(memory ,bypassMemory ,BYPASSABLE_MEMORY_STAGE)
trackHazardWithStage(execute ,bypassExecute ,BYPASSABLE_EXECUTE_STAGE)
when(decode.input(INSTRUCTION)(rs1Range) === 0 || !decode.input(REG1_USE)){
src0Hazard := False
}
when(decode.input(INSTRUCTION)(rs2Range) === 0 || !decode.input(REG2_USE)){
src1Hazard := False
}
when(decode.arbitration.isValid && (src0Hazard || src1Hazard)){
decode.arbitration.haltIt := True
}
}
}

View File

@ -0,0 +1,33 @@
package SpinalRiscv.Plugin
import SpinalRiscv.VexRiscv
import spinal.core._
import spinal.lib._
case class IBusSimpleCmd() extends Bundle{
val pc = UInt(32 bits)
}
case class IBusSimpleRsp() extends Bundle{
val inst = Bits(32 bits)
}
class IBusSimplePlugin(interfaceKeepData : Boolean) extends Plugin[VexRiscv]{
var iCmd : Stream[IBusSimpleCmd] = null
var iRsp : IBusSimpleRsp = null
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
require(interfaceKeepData)
iCmd = master(Stream(IBusSimpleCmd())).setName("iCmd")
iCmd.valid := prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
iCmd.pc := prefetch.output(PC)
prefetch.arbitration.haltIt setWhen(!iCmd.ready)
iRsp = in(IBusSimpleRsp()).setName("iRsp")
fetch.insert(INSTRUCTION) := iRsp.inst
}
}

View File

@ -0,0 +1,95 @@
package SpinalRiscv.Plugin
import SpinalRiscv._
import spinal.core._
class IntAluPlugin extends Plugin[VexRiscv]{
object AluCtrlEnum extends SpinalEnum(binarySequential){
val ADD_SUB, SLT_SLTU, XOR, OR, AND, SRC1 = newElement()
}
object ALU_CTRL extends Stageable(AluCtrlEnum())
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True
)
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True,
REG2_USE -> True
)
val otherAction = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True
)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(REGFILE_WRITE_VALID,False)
decoderService.add(List(
ADD -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False)),
SUB -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> True)),
SLT -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> False)),
SLTU -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> True)),
XOR -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.XOR)),
OR -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.OR)),
AND -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.AND))
))
decoderService.add(List(
ADDI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False)),
SLTI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> False)),
SLTIU -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> True)),
XORI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.XOR)),
ORI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.OR)),
ANDI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.AND))
))
decoderService.add(List(
LUI -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.SRC1, SRC1_CTRL -> Src1CtrlEnum.IMU)),
AUIPC -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False, SRC1_CTRL -> Src1CtrlEnum.IMU, SRC2_CTRL -> Src2CtrlEnum.PC))
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area{
import execute._
// mux results
insert(REGFILE_WRITE_DATA) := input(ALU_CTRL).mux(
AluCtrlEnum.AND -> (input(SRC1) & input(SRC2)),
AluCtrlEnum.OR -> (input(SRC1) | input(SRC2)),
AluCtrlEnum.XOR -> (input(SRC1) ^ input(SRC2)),
AluCtrlEnum.SRC1 -> input(SRC1),
AluCtrlEnum.SLT_SLTU -> input(SRC_LESS).asBits(32 bit),
AluCtrlEnum.ADD_SUB -> input(SRC_ADD_SUB)
)
}
}
}

View File

@ -0,0 +1,103 @@
package SpinalRiscv.Plugin
import SpinalRiscv.Riscv._
import SpinalRiscv._
import spinal.core._
import spinal.lib._
class NoPredictionBranchPlugin(earlyBranch : Boolean) extends Plugin[VexRiscv]{
object BranchCtrlEnum extends SpinalEnum(binarySequential){
val INC,B,JAL,JALR = newElement()
}
object BRANCH_CTRL extends Stageable(BranchCtrlEnum())
object BRANCH_SOLVED extends Stageable(BranchCtrlEnum())
object BRANCH_CALC extends Stageable(UInt(32 bits))
var jumpInterface : Flow[UInt] = null
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
val bActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
SRC_USE_SUB_LESS -> True,
REG1_USE -> True,
REG2_USE -> True
)
val jActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.FOUR,
SRC2_CTRL -> Src2CtrlEnum.PC,
SRC_USE_SUB_LESS -> False,
REGFILE_WRITE_VALID -> True
)
decoderService.addDefault(BRANCH_CTRL, BranchCtrlEnum.INC)
decoderService.add(List(
JAL -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JAL)),
JALR -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JALR, REG1_USE -> True)),
BEQ -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BNE -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BLT -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BGE -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BLTU -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True)),
BGEU -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True))
))
jumpInterface = pipeline.service(classOf[PcManagerService]).createJumpInterface(pipeline.execute)
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area {
import execute._
val less = input(SRC_LESS)
val eq = input(SRC1) === input(SRC2)
insert(BRANCH_SOLVED) := input(BRANCH_CTRL).mux[BranchCtrlEnum.C](
BranchCtrlEnum.INC -> BranchCtrlEnum.INC,
BranchCtrlEnum.JAL -> BranchCtrlEnum.JAL,
BranchCtrlEnum.JALR -> BranchCtrlEnum.JALR,
BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux(
B"000" -> Mux( eq , BranchCtrlEnum.B, BranchCtrlEnum.INC),
B"001" -> Mux(!eq , BranchCtrlEnum.B, BranchCtrlEnum.INC),
M"1-1" -> Mux(!less, BranchCtrlEnum.B, BranchCtrlEnum.INC),
default -> Mux( less, BranchCtrlEnum.B, BranchCtrlEnum.INC)
)
)
val imm = IMM(input(INSTRUCTION))
insert(BRANCH_CALC) := input(BRANCH_SOLVED).mux(
BranchCtrlEnum.JAL -> (input(PC) + imm.j_sext.asUInt),
BranchCtrlEnum.JALR -> (input(REG1).asUInt + imm.i_sext.asUInt),
default -> (input(PC) + imm.b_sext.asUInt) //B
)
}
val branchStage = if(earlyBranch) execute else memory
branchStage plug new Area {
import branchStage._
jumpInterface.valid := arbitration.isFiring && input(BRANCH_SOLVED) =/= BranchCtrlEnum.INC
jumpInterface.payload := input(BRANCH_CALC)
when(jumpInterface.valid) {
//prefetch.arbitration.removeIt := True
fetch.arbitration.removeIt := True
decode.arbitration.removeIt := True
if(!earlyBranch) execute.arbitration.removeIt := True
}
}
}
}

View File

@ -0,0 +1,73 @@
package SpinalRiscv.Plugin
import SpinalRiscv.{PcManagerService, Stage, VexRiscv}
import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
class PcManagerSimplePlugin(resetVector : BigInt,fastPcCalculation : Boolean) extends Plugin[VexRiscv] with PcManagerService{
//FetchService interface
case class JumpInfo(interface : Flow[UInt], stage: Stage)
val jumpInfos = ArrayBuffer[JumpInfo]()
override def createJumpInterface(stage: Stage): Flow[UInt] = {
val interface = Flow(UInt(32 bits))
jumpInfos += JumpInfo(interface,stage)
interface
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline.config._
import pipeline.prefetch
prefetch plug new Area {
import prefetch._
//Stage always valid
arbitration.isValid := True
//PC calculation without Jump
val pc = Reg(UInt(pcWidth bits)) init(resetVector) addAttribute("verilator public")
val inc = RegInit(False)
val pcNext = if(fastPcCalculation){
val pcPlus4 = pc + U(4)
pcPlus4.addAttribute("keep")
Mux(inc,pcPlus4,pc)
}else{
pc + Mux(inc,U(4),U(0))
}
val samplePcNext = False
//FetchService hardware implementation
val jump = if(jumpInfos.length != 0) new Area {
val sortedByStage = jumpInfos.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage))
val valids = sortedByStage.map(_.interface.valid)
val pcs = sortedByStage.map(_.interface.payload)
val pcLoad = Flow(UInt(pcWidth bits))
pcLoad.valid := jumpInfos.foldLeft(False)(_ || _.interface.valid)
pcLoad.payload := MuxOH(valids, pcs)
//Register managments
when(pcLoad.valid) {
inc := False
samplePcNext := True
pcNext := pcLoad.payload
}
}
when(arbitration.isFiring){
inc := True
samplePcNext := True
}
when(samplePcNext) { pc := pcNext }
//Pipeline insertions
insert(PC) := pcNext
}
}
}

View File

@ -1,5 +1,6 @@
package SpinalRiscv
package SpinalRiscv.Plugin
import SpinalRiscv.{Pipeline, Stage}
import spinal.core.Area
/**

View File

@ -0,0 +1,63 @@
package SpinalRiscv.Plugin
import SpinalRiscv.{DecoderService, Riscv, VexRiscv}
import spinal.core._
import spinal.lib._
trait RegFileReadKind
object ASYNC extends RegFileReadKind
object SYNC extends RegFileReadKind
class RegFilePlugin(regFileReadyKind : RegFileReadKind) extends Plugin[VexRiscv]{
import Riscv._
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(REG1_USE,False)
decoderService.addDefault(REG2_USE,False)
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
val global = pipeline plug new Area{
val regFile = Mem(Bits(32 bits),32) addAttribute("verilator public")
}
decode plug new Area{
import decode._
val rs1 = input(INSTRUCTION)(Riscv.rs1Range).asUInt
val rs2 = input(INSTRUCTION)(Riscv.rs2Range).asUInt
//read register file
val srcInstruction = regFileReadyKind match{
case `ASYNC` => input(INSTRUCTION)
case `SYNC` => Mux(arbitration.isStuck,input(INSTRUCTION),fetch.output(INSTRUCTION))
}
val regFileReadAddress1 = srcInstruction(Riscv.rs1Range).asUInt
val regFileReadAddress2 = srcInstruction(Riscv.rs2Range).asUInt
val (rs1Data,rs2Data) = regFileReadyKind match{
case `ASYNC` => (global.regFile.readAsync(regFileReadAddress1),global.regFile.readAsync(regFileReadAddress2))
case `SYNC` => (global.regFile.readSync(regFileReadAddress1),global.regFile.readSync(regFileReadAddress2))
}
insert(REG1) := Mux(rs1 =/= 0, rs1Data, B(0, 32 bit))
insert(REG2) := Mux(rs2 =/= 0, rs2Data, B(0, 32 bit))
}
writeBack plug new Area {
import writeBack._
val regFileWrite = global.regFile.writePort.addAttribute("verilator public")
regFileWrite.valid := input(REGFILE_WRITE_VALID) && arbitration.isFiring
regFileWrite.address := input(INSTRUCTION)(rdRange).asUInt
regFileWrite.data := input(REGFILE_WRITE_DATA)
}
}
}

View File

@ -0,0 +1,45 @@
package SpinalRiscv.Plugin
import SpinalRiscv.{Riscv, VexRiscv}
import spinal.core._
class SrcPlugin extends Plugin[VexRiscv]{
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
decode plug new Area{
import decode._
val imm = Riscv.IMM(input(INSTRUCTION))
insert(SRC1) := input(SRC1_CTRL).mux(
Src1CtrlEnum.RS -> output(REG1),
Src1CtrlEnum.FOUR -> B(4),
Src1CtrlEnum.IMU -> imm.u.resized
// Src1CtrlEnum.IMZ -> imm.z.resized,
// Src1CtrlEnum.IMJB -> B(0)
)
insert(SRC2) := input(SRC2_CTRL).mux(
Src2CtrlEnum.RS -> output(REG2),
Src2CtrlEnum.IMI -> imm.i_sext.resized,
Src2CtrlEnum.IMS -> imm.s_sext.resized,
Src2CtrlEnum.PC -> output(PC).asBits
)
}
execute plug new Area{
import execute._
// ADD, SUB
val addSub = (input(SRC1).asSInt + Mux(input(SRC_USE_SUB_LESS), ~input(SRC2), input(SRC2)).asSInt + Mux(input(SRC_USE_SUB_LESS),S(1),S(0))).asBits
// SLT, SLTU
val less = Mux(input(SRC1).msb === input(SRC2).msb, addSub.msb,
Mux(input(SRC_LESS_UNSIGNED), input(SRC2).msb, input(SRC1).msb))
insert(SRC_ADD_SUB) := addSub.resized
insert(SRC_LESS) := less
}
}
}

View File

@ -0,0 +1,71 @@
package SpinalRiscv
import spinal.core._
object Riscv{
def funct7Range = 31 downto 25
def rdRange = 11 downto 7
def funct3Range = 14 downto 12
def rs1Range = 19 downto 15
def rs2Range = 24 downto 20
case class IMM(instruction : Bits) extends Area{
// immediates
def i = instruction(31 downto 20)
def s = instruction(31, 25) ## instruction(11, 7)
def b = instruction(31) ## instruction(7) ## instruction(30 downto 25) ## instruction(11 downto 8)
def u = instruction(31 downto 12) ## U"x000"
def j = instruction(31) ## instruction(19 downto 12) ## instruction(20) ## instruction(30 downto 21)
def z = instruction(19 downto 15)
// sign-extend immediates
def i_sext = B((19 downto 0) -> i(11)) ## i
def s_sext = B((19 downto 0) -> s(11)) ## s
def b_sext = B((18 downto 0) -> b(11)) ## b ## False
def j_sext = B((10 downto 0) -> j(19)) ## j ## False
}
def ADD = M"0000000----------000-----0110011"
def SUB = M"0100000----------000-----0110011"
def SLL = M"0000000----------001-----0110011"
def SLT = M"0000000----------010-----0110011"
def SLTU = M"0000000----------011-----0110011"
def XOR = M"0000000----------100-----0110011"
def SRL = M"0000000----------101-----0110011"
def SRA = M"0100000----------101-----0110011"
def OR = M"0000000----------110-----0110011"
def AND = M"0000000----------111-----0110011"
def ADDI = M"-----------------000-----0010011"
def SLLI = M"000000-----------001-----0010011"
def SLTI = M"-----------------010-----0010011"
def SLTIU = M"-----------------011-----0010011"
def XORI = M"-----------------100-----0010011"
def SRLI = M"000000-----------101-----0010011"
def SRAI = M"010000-----------101-----0010011"
def ORI = M"-----------------110-----0010011"
def ANDI = M"-----------------111-----0010011"
def LB = M"-----------------000-----0000011"
def LH = M"-----------------001-----0000011"
def LW = M"-----------------010-----0000011"
def LBU = M"-----------------100-----0000011"
def LHU = M"-----------------101-----0000011"
def LWU = M"-----------------110-----0000011"
def SB = M"-----------------000-----0100011"
def SH = M"-----------------001-----0100011"
def SW = M"-----------------010-----0100011"
def BEQ = M"-----------------000-----1100011"
def BNE = M"-----------------001-----1100011"
def BLT = M"-----------------100-----1100011"
def BGE = M"-----------------101-----1100011"
def BLTU = M"-----------------110-----1100011"
def BGEU = M"-----------------111-----1100011"
def JALR = M"-----------------000-----1100111"
def JAL = M"-------------------------1101111"
def LUI = M"-------------------------0110111"
def AUIPC = M"-------------------------0010111"
}

View File

@ -0,0 +1,14 @@
package SpinalRiscv
import spinal.core._
import spinal.lib._
trait PcManagerService{
def createJumpInterface(stage : Stage) : Flow[UInt]
}
trait DecoderService{
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: BaseType],Any)])
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: BaseType],Any)])])
def addDefault(key : Stageable[_ <: BaseType], value : Any)
}

View File

@ -18,937 +18,10 @@
package SpinalRiscv
import java.io.File
import SpinalRiscv.Riscv.IMM
import SpinalRiscv.Plugin._
import spinal.core._
import spinal.lib._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
object Riscv{
def funct7Range = 31 downto 25
def rdRange = 11 downto 7
def funct3Range = 14 downto 12
def rs1Range = 19 downto 15
def rs2Range = 24 downto 20
case class IMM(instruction : Bits) extends Area{
// immediates
def i = instruction(31 downto 20)
def s = instruction(31, 25) ## instruction(11, 7)
def b = instruction(31) ## instruction(7) ## instruction(30 downto 25) ## instruction(11 downto 8)
def u = instruction(31 downto 12) ## U"x000"
def j = instruction(31) ## instruction(19 downto 12) ## instruction(20) ## instruction(30 downto 21)
def z = instruction(19 downto 15)
// sign-extend immediates
def i_sext = B((19 downto 0) -> i(11)) ## i
def s_sext = B((19 downto 0) -> s(11)) ## s
def b_sext = B((18 downto 0) -> b(11)) ## b ## False
def j_sext = B((10 downto 0) -> j(19)) ## j ## False
}
def ADD = M"0000000----------000-----0110011"
def SUB = M"0100000----------000-----0110011"
def SLL = M"0000000----------001-----0110011"
def SLT = M"0000000----------010-----0110011"
def SLTU = M"0000000----------011-----0110011"
def XOR = M"0000000----------100-----0110011"
def SRL = M"0000000----------101-----0110011"
def SRA = M"0100000----------101-----0110011"
def OR = M"0000000----------110-----0110011"
def AND = M"0000000----------111-----0110011"
def ADDI = M"-----------------000-----0010011"
def SLLI = M"000000-----------001-----0010011"
def SLTI = M"-----------------010-----0010011"
def SLTIU = M"-----------------011-----0010011"
def XORI = M"-----------------100-----0010011"
def SRLI = M"000000-----------101-----0010011"
def SRAI = M"010000-----------101-----0010011"
def ORI = M"-----------------110-----0010011"
def ANDI = M"-----------------111-----0010011"
def LB = M"-----------------000-----0000011"
def LH = M"-----------------001-----0000011"
def LW = M"-----------------010-----0000011"
def LBU = M"-----------------100-----0000011"
def LHU = M"-----------------101-----0000011"
def LWU = M"-----------------110-----0000011"
def SB = M"-----------------000-----0100011"
def SH = M"-----------------001-----0100011"
def SW = M"-----------------010-----0100011"
def BEQ = M"-----------------000-----1100011"
def BNE = M"-----------------001-----1100011"
def BLT = M"-----------------100-----1100011"
def BGE = M"-----------------101-----1100011"
def BLTU = M"-----------------110-----1100011"
def BGEU = M"-----------------111-----1100011"
def JALR = M"-----------------000-----1100111"
def JAL = M"-------------------------1101111"
def LUI = M"-------------------------0110111"
def AUIPC = M"-------------------------0010111"
}
case class VexRiscvConfig(pcWidth : Int){
val plugins = ArrayBuffer[Plugin[VexRiscv]]()
//TODO apply defaults to decoder
//Default Stageables
object BYPASSABLE_EXECUTE_STAGE extends Stageable(Bool)
object BYPASSABLE_MEMORY_STAGE extends Stageable(Bool)
object REG1 extends Stageable(Bits(32 bits))
object REG2 extends Stageable(Bits(32 bits))
object REG1_USE extends Stageable(Bool)
object REG2_USE extends Stageable(Bool)
object RESULT extends Stageable(UInt(32 bits))
object PC extends Stageable(UInt(pcWidth bits))
object INSTRUCTION extends Stageable(Bits(32 bits))
object LEGAL_INSTRUCTION extends Stageable(Bool)
object REGFILE_WRITE_VALID extends Stageable(Bool)
object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits))
object SRC1 extends Stageable(Bits(32 bits))
object SRC2 extends Stageable(Bits(32 bits))
object SRC_ADD_SUB extends Stageable(Bits(32 bits))
object SRC_LESS extends Stageable(Bool)
object SRC_USE_SUB_LESS extends Stageable(Bool)
object SRC_LESS_UNSIGNED extends Stageable(Bool)
object Src1CtrlEnum extends SpinalEnum(binarySequential){
val RS, IMU, FOUR = newElement() //IMU, IMZ IMJB
}
object Src2CtrlEnum extends SpinalEnum(binarySequential){
val RS, IMI, IMS, PC = newElement()
}
object SRC1_CTRL extends Stageable(Src1CtrlEnum())
object SRC2_CTRL extends Stageable(Src2CtrlEnum())
}
class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
type T = VexRiscv
import config._
stages ++= List.fill(6)(new Stage())
val prefetch :: fetch :: decode :: execute :: memory :: writeBack :: Nil = stages.toList
plugins ++= config.plugins
//regression usage
writeBack.input(config.INSTRUCTION) keep() addAttribute("verilator public")
writeBack.input(config.PC) keep() addAttribute("verilator public")
writeBack.arbitration.isValid keep() addAttribute("verilator public")
}
trait DecoderService{
def add(key : MaskedLiteral,values : Seq[(Stageable[_ <: BaseType],Any)])
def add(encoding :Seq[(MaskedLiteral,Seq[(Stageable[_ <: BaseType],Any)])])
def addDefault(key : Stageable[_ <: BaseType], value : Any)
}
case class Masked(value : BigInt,care : BigInt){
}
class DecoderSimplePlugin extends Plugin[VexRiscv] with DecoderService {
override def add(encoding: Seq[(MaskedLiteral, Seq[(Stageable[_ <: BaseType], Any)])]): Unit = encoding.foreach(e => this.add(e._1,e._2))
override def add(key: MaskedLiteral, values: Seq[(Stageable[_ <: BaseType], Any)]): Unit = {
require(!encodings.contains(key))
encodings(key) = values.map{case (a,b) => (a,b match{
case e : SpinalEnumElement[_] => e()
case e : BaseType => e
})}
}
override def addDefault(key: Stageable[_ <: BaseType], value: Any): Unit = {
require(!defaults.contains(key))
defaults(key) = value match{
case e : SpinalEnumElement[_] => e()
case e : BaseType => e
}
}
val defaults = mutable.HashMap[Stageable[_ <: BaseType], BaseType]()
val encodings = mutable.HashMap[MaskedLiteral,Seq[(Stageable[_ <: BaseType], BaseType)]]()
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
addDefault(LEGAL_INSTRUCTION, False)
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline.decode._
import pipeline.config._
val stageables = (encodings.flatMap(_._2.map(_._1)) ++ defaults.map(_._1)).toSet.toList
var offset = 0
var defaultValue, defaultCare = BigInt(0)
val offsetOf = mutable.HashMap[Stageable[_ <: BaseType],Int]()
//Build defaults value and field offset map
stageables.foreach(e => {
defaults.get(e) match {
case Some(value) => {
value.input match {
case literal: EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding)
case _ =>
}
defaultValue += value.input.asInstanceOf[Literal].getValue << offset
defaultCare += ((BigInt(1) << e.dataType.getBitsWidth) - 1) << offset
}
case _ =>
}
offsetOf(e) = offset
offset += e.dataType.getBitsWidth
})
//Build spec
val spec = encodings.map { case (key, values) =>
var decodedValue, decodedCare = BigInt(0)
for((e, literal) <- values){
literal.input match{
case literal : EnumLiteral[_] => literal.fixEncoding(e.dataType.asInstanceOf[SpinalEnumCraft[_]].getEncoding)
case _ =>
}
val offset = offsetOf(e)
decodedValue += literal.input.asInstanceOf[Literal].getValue << offset
decodedCare += ((BigInt(1) << e.dataType.getBitsWidth)-1) << offset
}
(Masked(key.value,key.careAbout),Masked(decodedValue,decodedCare))
}
// logic implementation
val decodedBits = Bits(stageables.foldLeft(0)(_ + _.dataType.getBitsWidth) bits)
val defaultBits = cloneOf(decodedBits)
assert(defaultValue == 0)
defaultBits := defaultValue
val logicOr = for((key, mapping) <- spec) yield Mux[Bits](((input(INSTRUCTION) & key.care) === (key.value & key.care)), B(mapping.value & mapping.care, decodedBits.getWidth bits) , B(0, decodedBits.getWidth bits))
decodedBits := logicOr.foldLeft(defaultBits)(_ | _)
// for(i <- decodedBits.range)
// if(defaultCare.testBit(i))
// defaultBits(i) := Bool(defaultValue.testBit(i))
// else
// defaultBits(i).assignDontCare()
// val logicOr = for((key, mapping) <- spec) yield Mux[Bits](((input(INSTRUCTION) & key.care) === (key.value & key.care)), B(mapping.value & mapping.care, decodedBits.getWidth bits) , B(0, decodedBits.getWidth bits))
// val logicAnd = for((key, mapping) <- spec) yield Mux[Bits](((input(INSTRUCTION) & key.care) === (key.value & key.care)), B(~mapping.value & mapping.care, decodedBits.getWidth bits) , B(0, decodedBits.getWidth bits))
// decodedBits := (defaultBits | logicOr.foldLeft(B(0, decodedBits.getWidth bits))(_ | _)) & ~logicAnd.foldLeft(B(0, decodedBits.getWidth bits))(_ | _)
//Unpack decodedBits and insert fields in the pipeline
offset = 0
stageables.foreach(e => {
insert(e).assignFromBits(decodedBits(offset, e.dataType.getBitsWidth bits))
// insert(e).assignFromBits(RegNext(decodedBits(offset, e.dataType.getBitsWidth bits)))
offset += e.dataType.getBitsWidth
})
}
def bench(toplevel : VexRiscv): Unit ={
toplevel.rework{
import toplevel.config._
toplevel.getAllIo.toList.foreach(_.asDirectionLess())
toplevel.decode.input(INSTRUCTION) := Delay((in Bits(32 bits)).setName("instruction"),2)
val stageables = encodings.flatMap(_._2.map(_._1)).toSet
stageables.foreach(e => out(Delay(toplevel.decode.insert(e),2)).setName(e.getName))
toplevel.getAdditionalNodesRoot.clear()
}
}
}
class NoPredictionBranchPlugin(earlyBranch : Boolean) extends Plugin[VexRiscv]{
object BranchCtrlEnum extends SpinalEnum(binarySequential){
val INC,B,JAL,JALR = newElement()
}
object BRANCH_CTRL extends Stageable(BranchCtrlEnum())
object BRANCH_SOLVED extends Stageable(BranchCtrlEnum())
object BRANCH_CALC extends Stageable(UInt(32 bits))
var jumpInterface : Flow[UInt] = null
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
import Riscv._
val decoderService = pipeline.service(classOf[DecoderService])
val bActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
SRC_USE_SUB_LESS -> True,
REG1_USE -> True,
REG2_USE -> True
)
val jActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.FOUR,
SRC2_CTRL -> Src2CtrlEnum.PC,
SRC_USE_SUB_LESS -> False,
REGFILE_WRITE_VALID -> True
)
decoderService.addDefault(BRANCH_CTRL, BranchCtrlEnum.INC)
decoderService.add(List(
JAL -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JAL)),
JALR -> (jActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.JALR, REG1_USE -> True)),
BEQ -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BNE -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B)),
BLT -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BGE -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> False)),
BLTU -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True)),
BGEU -> (bActions ++ List(BRANCH_CTRL -> BranchCtrlEnum.B, SRC_LESS_UNSIGNED -> True))
))
jumpInterface = pipeline.service(classOf[PcManagerService]).createJumpInterface(pipeline.execute)
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area {
import execute._
val less = input(SRC_LESS)
val eq = input(SRC1) === input(SRC2)
insert(BRANCH_SOLVED) := input(BRANCH_CTRL).mux[BranchCtrlEnum.C](
BranchCtrlEnum.INC -> BranchCtrlEnum.INC,
BranchCtrlEnum.JAL -> BranchCtrlEnum.JAL,
BranchCtrlEnum.JALR -> BranchCtrlEnum.JALR,
BranchCtrlEnum.B -> input(INSTRUCTION)(14 downto 12).mux(
B"000" -> Mux( eq , BranchCtrlEnum.B, BranchCtrlEnum.INC),
B"001" -> Mux(!eq , BranchCtrlEnum.B, BranchCtrlEnum.INC),
M"1-1" -> Mux(!less, BranchCtrlEnum.B, BranchCtrlEnum.INC),
default -> Mux( less, BranchCtrlEnum.B, BranchCtrlEnum.INC)
)
)
val imm = IMM(input(INSTRUCTION))
insert(BRANCH_CALC) := input(BRANCH_SOLVED).mux(
BranchCtrlEnum.JAL -> (input(PC) + imm.j_sext.asUInt),
BranchCtrlEnum.JALR -> (input(REG1).asUInt + imm.i_sext.asUInt),
default -> (input(PC) + imm.b_sext.asUInt) //B
)
}
val branchStage = if(earlyBranch) execute else memory
branchStage plug new Area {
import branchStage._
jumpInterface.valid := arbitration.isFiring && input(BRANCH_SOLVED) =/= BranchCtrlEnum.INC
jumpInterface.payload := input(BRANCH_CALC)
when(jumpInterface.valid) {
//prefetch.arbitration.removeIt := True
fetch.arbitration.removeIt := True
decode.arbitration.removeIt := True
if(!earlyBranch) execute.arbitration.removeIt := True
}
}
}
}
trait PcManagerService{
def createJumpInterface(stage : Stage) : Flow[UInt]
}
class PcManagerSimplePlugin(resetVector : BigInt,fastPcCalculation : Boolean) extends Plugin[VexRiscv] with PcManagerService{
//FetchService interface
case class JumpInfo(interface : Flow[UInt], stage: Stage)
val jumpInfos = ArrayBuffer[JumpInfo]()
override def createJumpInterface(stage: Stage): Flow[UInt] = {
val interface = Flow(UInt(32 bits))
jumpInfos += JumpInfo(interface,stage)
interface
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline.prefetch
import pipeline.config._
prefetch plug new Area {
import prefetch._
//Stage always valid
arbitration.isValid := True
//PC calculation without Jump
val pc = Reg(UInt(pcWidth bits)) init(resetVector) addAttribute("verilator public")
val inc = RegInit(False)
val pcNext = if(fastPcCalculation){
val pcPlus4 = pc + U(4)
pcPlus4.addAttribute("keep")
Mux(inc,pcPlus4,pc)
}else{
pc + Mux(inc,U(4),U(0))
}
val samplePcNext = False
//FetchService hardware implementation
val jump = if(jumpInfos.length != 0) new Area {
val sortedByStage = jumpInfos.sortWith((a, b) => pipeline.indexOf(a.stage) > pipeline.indexOf(b.stage))
val valids = sortedByStage.map(_.interface.valid)
val pcs = sortedByStage.map(_.interface.payload)
val pcLoad = Flow(UInt(pcWidth bits))
pcLoad.valid := jumpInfos.foldLeft(False)(_ || _.interface.valid)
pcLoad.payload := MuxOH(valids, pcs)
//Register managments
when(pcLoad.valid) {
inc := False
samplePcNext := True
pcNext := pcLoad.payload
}
}
when(arbitration.isFiring){
inc := True
samplePcNext := True
}
when(samplePcNext) { pc := pcNext }
//Pipeline insertions
insert(PC) := pcNext
}
}
}
case class IBusSimpleCmd() extends Bundle{
val pc = UInt(32 bits)
}
case class IBusSimpleRsp() extends Bundle{
val inst = Bits(32 bits)
}
class IBusSimplePlugin(interfaceKeepData : Boolean) extends Plugin[VexRiscv]{
var iCmd : Stream[IBusSimpleCmd] = null
var iRsp : IBusSimpleRsp = null
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
require(interfaceKeepData)
iCmd = master(Stream(IBusSimpleCmd())).setName("iCmd")
iCmd.valid := prefetch.arbitration.isValid && !prefetch.arbitration.isStuckByOthers
iCmd.pc := prefetch.output(PC)
prefetch.arbitration.haltIt setWhen(!iCmd.ready)
iRsp = in(IBusSimpleRsp()).setName("iRsp")
fetch.insert(INSTRUCTION) := iRsp.inst
}
}
case class DBusSimpleCmd() extends Bundle{
val wr = Bool
val address = UInt(32 bits)
val data = Bits(32 bit)
val size = UInt(2 bit)
}
case class DBusSimpleRsp() extends Bundle{
val data = Bits(32 bit)
}
class DBusSimplePlugin extends Plugin[VexRiscv]{
var dCmd : Stream[DBusSimpleCmd] = null
var dRsp : DBusSimpleRsp = null
object MemoryCtrlEnum extends SpinalEnum{
val WR, RD = newElement()
}
object MEMORY_ENABLE extends Stageable(Bool)
object MEMORY_CTRL extends Stageable(MemoryCtrlEnum())
object MEMORY_READ_DATA extends Stageable(Bits(32 bits))
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
import Riscv._
val decoderService = pipeline.service(classOf[DecoderService])
val stdActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC_USE_SUB_LESS -> False,
MEMORY_ENABLE -> True,
REG1_USE -> True
)
val loadActions = stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> False
)
val storeActions = stdActions ++ List(
SRC2_CTRL -> Src2CtrlEnum.IMS,
REG2_USE -> True
)
decoderService.addDefault(MEMORY_ENABLE, False)
decoderService.add(List(
LB -> (loadActions),
LH -> (loadActions),
LW -> (loadActions),
LBU -> (loadActions),
LHU -> (loadActions),
LWU -> (loadActions),
SB -> (storeActions),
SH -> (storeActions),
SW -> (storeActions)
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area{
import execute._
dCmd = master(Stream(DBusSimpleCmd())).setName("dCmd")
dCmd.valid := arbitration.isValid && input(MEMORY_ENABLE) && !arbitration.isStuckByOthers
dCmd.wr := input(INSTRUCTION)(5)
dCmd.address := input(SRC_ADD_SUB).asUInt
dCmd.size := input(INSTRUCTION)(13 downto 12).asUInt
dCmd.payload.data := dCmd.size.mux (
U(0) -> input(REG2)(7 downto 0) ## input(REG2)(7 downto 0) ## input(REG2)(7 downto 0) ## input(REG2)(7 downto 0),
U(1) -> input(REG2)(15 downto 0) ## input(REG2)(15 downto 0),
default -> input(REG2)(31 downto 0)
)
when(arbitration.isValid && input(MEMORY_ENABLE) && !dCmd.ready){
arbitration.haltIt := True
}
insert(MEMORY_ADDRESS_LOW) := dCmd.address(1 downto 0)
}
memory plug new Area {
import memory._
dRsp = in(DBusSimpleRsp()).setName("dRsp")
insert(MEMORY_READ_DATA) := dRsp.data
assert(!(input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend")
}
writeBack plug new Area {
import writeBack._
val rspShifted = MEMORY_READ_DATA()
rspShifted := input(MEMORY_READ_DATA)
switch(input(MEMORY_ADDRESS_LOW)){
is(1){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(15 downto 8)}
is(2){rspShifted(15 downto 0) := input(MEMORY_READ_DATA)(31 downto 16)}
is(3){rspShifted(7 downto 0) := input(MEMORY_READ_DATA)(31 downto 24)}
}
val rspFormated = input(INSTRUCTION)(13 downto 12).mux(
0 -> B((31 downto 8) -> (rspShifted(7) && !input(INSTRUCTION)(14)),(7 downto 0) -> rspShifted(7 downto 0)),
1 -> B((31 downto 16) -> (rspShifted(15) && ! input(INSTRUCTION)(14)),(15 downto 0) -> rspShifted(15 downto 0)),
default -> rspShifted //W
)
when(input(MEMORY_ENABLE)) {
input(REGFILE_WRITE_DATA) := rspFormated
}
assert(!(input(MEMORY_ENABLE) && !input(INSTRUCTION)(5) && arbitration.isStuck),"DBusSimplePlugin doesn't allow memory stage stall when read happend")
}
}
}
class HazardSimplePlugin(bypassExecute : Boolean,bypassMemory: Boolean,bypassWriteBack: Boolean, bypassWriteBackBuffer : Boolean) extends Plugin[VexRiscv] {
import Riscv._
override def build(pipeline: VexRiscv): Unit = {
import pipeline.config._
import pipeline._
val src0Hazard = False
val src1Hazard = False
//Disable rd0 write in decoding stage
when(decode.input(INSTRUCTION)(rdRange) === 0) {
decode.input(REGFILE_WRITE_VALID) := False
}
def trackHazardWithStage(stage : Stage,bypassable : Boolean, runtimeBypassable : Stageable[Bool]): Unit ={
val runtimeBypassableValue = if(runtimeBypassable != null) stage.input(runtimeBypassable) else True
val addr0Match = stage.input(INSTRUCTION)(rdRange) === decode.input(INSTRUCTION)(rs1Range)
val addr1Match = stage.input(INSTRUCTION)(rdRange) === decode.input(INSTRUCTION)(rs2Range)
when(stage.arbitration.isValid && stage.input(REGFILE_WRITE_VALID)) {
if (bypassable) {
when(runtimeBypassableValue) {
when(addr0Match) {
decode.input(REG1) := stage.output(REGFILE_WRITE_DATA)
}
when(addr1Match) {
decode.input(REG2) := stage.output(REGFILE_WRITE_DATA)
}
}
}
when((Bool(!bypassable) || !runtimeBypassableValue)) {
when(addr0Match) {
src0Hazard := True
}
when(addr1Match) {
src1Hazard := True
}
}
}
}
val writeBackWrites = Flow(cloneable(new Bundle{
val address = Bits(5 bits)
val data = Bits(32 bits)
}))
writeBackWrites.valid := writeBack.output(REGFILE_WRITE_VALID) && writeBack.arbitration.isFiring
writeBackWrites.address := writeBack.output(INSTRUCTION)(rdRange)
writeBackWrites.data := writeBack.output(REGFILE_WRITE_DATA)
val writeBackBuffer = writeBackWrites.stage()
val addr0Match = writeBackBuffer.address === decode.input(INSTRUCTION)(rs1Range)
val addr1Match = writeBackBuffer.address === decode.input(INSTRUCTION)(rs2Range)
when(writeBackBuffer.valid) {
if (bypassWriteBackBuffer) {
when(addr0Match) {
decode.input(REG1) := writeBackBuffer.data
}
when(addr1Match) {
decode.input(REG2) := writeBackBuffer.data
}
} else {
when(addr0Match) {
src0Hazard := True
}
when(addr1Match) {
src1Hazard := True
}
}
}
trackHazardWithStage(writeBack,bypassWriteBack,null)
trackHazardWithStage(memory ,bypassMemory ,BYPASSABLE_MEMORY_STAGE)
trackHazardWithStage(execute ,bypassExecute ,BYPASSABLE_EXECUTE_STAGE)
when(decode.input(INSTRUCTION)(rs1Range) === 0 || !decode.input(REG1_USE)){
src0Hazard := False
}
when(decode.input(INSTRUCTION)(rs2Range) === 0 || !decode.input(REG2_USE)){
src1Hazard := False
}
when(decode.arbitration.isValid && (src0Hazard || src1Hazard)){
decode.arbitration.haltIt := True
}
}
}
trait RegFileReadKind
object ASYNC extends RegFileReadKind
object SYNC extends RegFileReadKind
class RegFilePlugin(regFileReadyKind : RegFileReadKind) extends Plugin[VexRiscv]{
import Riscv._
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(REG1_USE,False)
decoderService.addDefault(REG2_USE,False)
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
val global = pipeline plug new Area{
val regFile = Mem(Bits(32 bits),32) addAttribute("verilator public")
}
decode plug new Area{
import decode._
val rs1 = input(INSTRUCTION)(Riscv.rs1Range).asUInt
val rs2 = input(INSTRUCTION)(Riscv.rs2Range).asUInt
//read register file
val srcInstruction = regFileReadyKind match{
case `ASYNC` => input(INSTRUCTION)
case `SYNC` => Mux(arbitration.isStuck,input(INSTRUCTION),fetch.output(INSTRUCTION))
}
val regFileReadAddress1 = srcInstruction(Riscv.rs1Range).asUInt
val regFileReadAddress2 = srcInstruction(Riscv.rs2Range).asUInt
val (rs1Data,rs2Data) = regFileReadyKind match{
case `ASYNC` => (global.regFile.readAsync(regFileReadAddress1),global.regFile.readAsync(regFileReadAddress2))
case `SYNC` => (global.regFile.readSync(regFileReadAddress1),global.regFile.readSync(regFileReadAddress2))
}
insert(REG1) := Mux(rs1 =/= 0, rs1Data, B(0, 32 bit))
insert(REG2) := Mux(rs2 =/= 0, rs2Data, B(0, 32 bit))
}
writeBack plug new Area {
import writeBack._
val regFileWrite = global.regFile.writePort.addAttribute("verilator public")
regFileWrite.valid := input(REGFILE_WRITE_VALID) && arbitration.isFiring
regFileWrite.address := input(INSTRUCTION)(rdRange).asUInt
regFileWrite.data := input(REGFILE_WRITE_DATA)
}
}
}
class SrcPlugin extends Plugin[VexRiscv]{
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
decode plug new Area{
import decode._
val imm = Riscv.IMM(input(INSTRUCTION))
insert(SRC1) := input(SRC1_CTRL).mux(
Src1CtrlEnum.RS -> output(REG1),
Src1CtrlEnum.FOUR -> B(4),
Src1CtrlEnum.IMU -> imm.u.resized
// Src1CtrlEnum.IMZ -> imm.z.resized,
// Src1CtrlEnum.IMJB -> B(0)
)
insert(SRC2) := input(SRC2_CTRL).mux(
Src2CtrlEnum.RS -> output(REG2),
Src2CtrlEnum.IMI -> imm.i_sext.resized,
Src2CtrlEnum.IMS -> imm.s_sext.resized,
Src2CtrlEnum.PC -> output(PC).asBits
)
}
execute plug new Area{
import execute._
// ADD, SUB
val addSub = (input(SRC1).asSInt + Mux(input(SRC_USE_SUB_LESS), ~input(SRC2), input(SRC2)).asSInt + Mux(input(SRC_USE_SUB_LESS),S(1),S(0))).asBits
// SLT, SLTU
val less = Mux(input(SRC1).msb === input(SRC2).msb, addSub.msb,
Mux(input(SRC_LESS_UNSIGNED), input(SRC2).msb, input(SRC1).msb))
insert(SRC_ADD_SUB) := addSub.resized
insert(SRC_LESS) := less
}
}
}
class IntAluPlugin extends Plugin[VexRiscv]{
object AluCtrlEnum extends SpinalEnum(binarySequential){
val ADD_SUB, SLT_SLTU, XOR, OR, AND, SRC1 = newElement()
}
object ALU_CTRL extends Stageable(AluCtrlEnum())
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
import Riscv._
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True
)
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True,
REG2_USE -> True
)
val otherAction = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> True,
BYPASSABLE_MEMORY_STAGE -> True
)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(REGFILE_WRITE_VALID,False)
decoderService.add(List(
ADD -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False)),
SUB -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> True)),
SLT -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> False)),
SLTU -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> True)),
XOR -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.XOR)),
OR -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.OR)),
AND -> (nonImmediateActions ++ List(ALU_CTRL -> AluCtrlEnum.AND))
))
decoderService.add(List(
ADDI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False)),
SLTI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> False)),
SLTIU -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.SLT_SLTU, SRC_USE_SUB_LESS -> True, SRC_LESS_UNSIGNED -> True)),
XORI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.XOR)),
ORI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.OR)),
ANDI -> (immediateActions ++ List(ALU_CTRL -> AluCtrlEnum.AND))
))
decoderService.add(List(
LUI -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.SRC1, SRC1_CTRL -> Src1CtrlEnum.IMU)),
AUIPC -> (otherAction ++ List(ALU_CTRL -> AluCtrlEnum.ADD_SUB, SRC_USE_SUB_LESS -> False, SRC1_CTRL -> Src1CtrlEnum.IMU, SRC2_CTRL -> Src2CtrlEnum.PC))
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area{
import execute._
// mux results
insert(REGFILE_WRITE_DATA) := input(ALU_CTRL).mux(
AluCtrlEnum.AND -> (input(SRC1) & input(SRC2)),
AluCtrlEnum.OR -> (input(SRC1) | input(SRC2)),
AluCtrlEnum.XOR -> (input(SRC1) ^ input(SRC2)),
AluCtrlEnum.SRC1 -> input(SRC1),
AluCtrlEnum.SLT_SLTU -> input(SRC_LESS).asBits(32 bit),
AluCtrlEnum.ADD_SUB -> input(SRC_ADD_SUB)
)
}
}
}
class FullBarrielShifterPlugin extends Plugin[VexRiscv]{
object ShiftCtrlEnum extends SpinalEnum(binarySequential){
val DISABLE, SLL, SRL, SRA = newElement() //TODO default
}
object SHIFT_CTRL extends Stageable(ShiftCtrlEnum())
object SHIFT_RIGHT extends Stageable(Bits(32 bits))
override def setup(pipeline: VexRiscv): Unit = {
import pipeline.config._
import Riscv._
val immediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.IMI,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True
)
val nonImmediateActions = List[(Stageable[_ <: BaseType],Any)](
LEGAL_INSTRUCTION -> True,
SRC1_CTRL -> Src1CtrlEnum.RS,
SRC2_CTRL -> Src2CtrlEnum.RS,
REGFILE_WRITE_VALID -> True,
BYPASSABLE_EXECUTE_STAGE -> False,
BYPASSABLE_MEMORY_STAGE -> True,
REG1_USE -> True,
REG2_USE -> True
)
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(SHIFT_CTRL, ShiftCtrlEnum.DISABLE)
decoderService.add(List(
SLL -> (nonImmediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SLL)),
SRL -> (nonImmediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRL)),
SRA -> (nonImmediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRA))
))
decoderService.add(List(
SLLI -> (immediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SLL)),
SRLI -> (immediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRL)),
SRAI -> (immediateActions ++ List(SHIFT_CTRL -> ShiftCtrlEnum.SRA))
))
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
execute plug new Area{
import execute._
val amplitude = input(SRC2)(4 downto 0).asUInt
val reversed = Mux(input(SHIFT_CTRL) === ShiftCtrlEnum.SLL, Reverse(input(SRC1)), input(SRC1))
insert(SHIFT_RIGHT) := (Cat(input(SHIFT_CTRL) === ShiftCtrlEnum.SRA & reversed.msb, reversed).asSInt >> amplitude)(31 downto 0).asBits
}
memory plug new Area{
import memory._
switch(input(SHIFT_CTRL)){
is(ShiftCtrlEnum.SLL){
output(REGFILE_WRITE_DATA) := Reverse(input(SHIFT_RIGHT))
}
is(ShiftCtrlEnum.SRL,ShiftCtrlEnum.SRA){
output(REGFILE_WRITE_DATA) := input(SHIFT_RIGHT)
}
}
}
}
}
object TopLevel {
def main(args: Array[String]) {
@ -958,15 +31,15 @@ object TopLevel {
)
config.plugins ++= List(
new PcManagerSimplePlugin(0, true),
new PcManagerSimplePlugin(0, false),
new IBusSimplePlugin(true),
new DecoderSimplePlugin,
new RegFilePlugin(SYNC),
new RegFilePlugin(Plugin.SYNC),
new IntAluPlugin,
new SrcPlugin,
new FullBarrielShifterPlugin,
new DBusSimplePlugin,
new HazardSimplePlugin(true,true,true,true),
new HazardSimplePlugin(false, true, false, true),
// new HazardSimplePlugin(false, false, false, false),
new NoPredictionBranchPlugin(false)
)

View File

@ -0,0 +1,60 @@
package SpinalRiscv
import SpinalRiscv.Plugin.Plugin
import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
case class VexRiscvConfig(pcWidth : Int){
val plugins = ArrayBuffer[Plugin[VexRiscv]]()
//TODO apply defaults to decoder
//Default Stageables
object BYPASSABLE_EXECUTE_STAGE extends Stageable(Bool)
object BYPASSABLE_MEMORY_STAGE extends Stageable(Bool)
object REG1 extends Stageable(Bits(32 bits))
object REG2 extends Stageable(Bits(32 bits))
object REG1_USE extends Stageable(Bool)
object REG2_USE extends Stageable(Bool)
object RESULT extends Stageable(UInt(32 bits))
object PC extends Stageable(UInt(pcWidth bits))
object INSTRUCTION extends Stageable(Bits(32 bits))
object LEGAL_INSTRUCTION extends Stageable(Bool)
object REGFILE_WRITE_VALID extends Stageable(Bool)
object REGFILE_WRITE_DATA extends Stageable(Bits(32 bits))
object SRC1 extends Stageable(Bits(32 bits))
object SRC2 extends Stageable(Bits(32 bits))
object SRC_ADD_SUB extends Stageable(Bits(32 bits))
object SRC_LESS extends Stageable(Bool)
object SRC_USE_SUB_LESS extends Stageable(Bool)
object SRC_LESS_UNSIGNED extends Stageable(Bool)
object Src1CtrlEnum extends SpinalEnum(binarySequential){
val RS, IMU, FOUR = newElement() //IMU, IMZ IMJB
}
object Src2CtrlEnum extends SpinalEnum(binarySequential){
val RS, IMI, IMS, PC = newElement()
}
object SRC1_CTRL extends Stageable(Src1CtrlEnum())
object SRC2_CTRL extends Stageable(Src2CtrlEnum())
}
class VexRiscv(val config : VexRiscvConfig) extends Component with Pipeline{
type T = VexRiscv
import config._
stages ++= List.fill(6)(new Stage())
val prefetch :: fetch :: decode :: execute :: memory :: writeBack :: Nil = stages.toList
plugins ++= config.plugins
//regression usage
writeBack.input(config.INSTRUCTION) keep() addAttribute("verilator public")
writeBack.input(config.PC) keep() addAttribute("verilator public")
writeBack.arbitration.isValid keep() addAttribute("verilator public")
}