Reorganize project
This commit is contained in:
parent
bf5bebda08
commit
401be6ca83
|
@ -1,5 +1,6 @@
|
|||
package SpinalRiscv
|
||||
|
||||
import SpinalRiscv.Plugin.Plugin
|
||||
import spinal.core._
|
||||
|
||||
import scala.collection.mutable
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package SpinalRiscv
|
||||
package SpinalRiscv.Plugin
|
||||
|
||||
import SpinalRiscv.{Pipeline, Stage}
|
||||
import spinal.core.Area
|
||||
|
||||
/**
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue