Merge remote-tracking branch 'origin/Wishbone'
This commit is contained in:
commit
c7d852c497
|
@ -0,0 +1,241 @@
|
||||||
|
package spinal.lib.bus.wishbone
|
||||||
|
|
||||||
|
import spinal.core._
|
||||||
|
import spinal.lib._
|
||||||
|
|
||||||
|
/** This class is used for configuring the Wishbone class
|
||||||
|
* @param addressWidth size in bits of the address line
|
||||||
|
* @param dataWidth size in bits of the data line
|
||||||
|
* @param selWidth size in bits of the selection line, deafult to 0 (disabled)
|
||||||
|
* @param useSTALL activate the stall line, default to false (disabled)
|
||||||
|
* @param useLOCK activate the lock line, default to false (disabled)
|
||||||
|
* @param useERR activate the error line, default to false (disabled)
|
||||||
|
* @param useRTY activate the retry line, default to false (disabled)
|
||||||
|
* @param tgaWidth size in bits of the tag address linie, deafult to 0 (disabled)
|
||||||
|
* @param tgcWidth size in bits of the tag cycle line, deafult to 0 (disabled)
|
||||||
|
* @param tgdWidth size in bits of the tag data line, deafult to 0 (disabled)
|
||||||
|
* @param useBTE activate the BTE line, deafult to 0 (disabled)
|
||||||
|
* @param useCTI activate the CTI line, deafult to 0 (disabled)
|
||||||
|
* @example {{{
|
||||||
|
* val wishboneBusConf = new WishboneConfig(32,8).withCycleTag(8).withDataTag(8)
|
||||||
|
* val wishboneBus = new Wishbone(wishboneBusConf)
|
||||||
|
* }}}
|
||||||
|
* @todo test example
|
||||||
|
*/
|
||||||
|
case class WishboneConfig(
|
||||||
|
val addressWidth : Int,
|
||||||
|
val dataWidth : Int,
|
||||||
|
val selWidth : Int = 0,
|
||||||
|
val useSTALL : Boolean = false,
|
||||||
|
val useLOCK : Boolean = false,
|
||||||
|
val useERR : Boolean = false,
|
||||||
|
val useRTY : Boolean = false,
|
||||||
|
val tgaWidth : Int = 0,
|
||||||
|
val tgcWidth : Int = 0,
|
||||||
|
val tgdWidth : Int = 0,
|
||||||
|
val useBTE : Boolean = false,
|
||||||
|
val useCTI : Boolean = false
|
||||||
|
){
|
||||||
|
def useTGA = tgaWidth > 0
|
||||||
|
def useTGC = tgcWidth > 0
|
||||||
|
def useTGD = tgdWidth > 0
|
||||||
|
def useSEL = selWidth > 0
|
||||||
|
def isPipelined = useSTALL
|
||||||
|
def pipelined : WishboneConfig = this.copy(useSTALL = true)
|
||||||
|
def withDataTag(size : Int) : WishboneConfig = this.copy(tgdWidth = size)
|
||||||
|
def withAddressTag(size : Int) : WishboneConfig = this.copy(tgaWidth = size)
|
||||||
|
def withCycleTag(size : Int) : WishboneConfig = this.copy(tgdWidth = size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This class rappresent a Wishbone bus
|
||||||
|
* @param config an istance of WishboneConfig, it will be used to configurate the Wishbone Bus
|
||||||
|
*/
|
||||||
|
case class Wishbone(config: WishboneConfig) extends Bundle with IMasterSlave {
|
||||||
|
/////////////////////
|
||||||
|
// MINIMAL SIGNALS //
|
||||||
|
/////////////////////
|
||||||
|
val CYC = Bool
|
||||||
|
val STB = Bool
|
||||||
|
val ACK = Bool
|
||||||
|
val WE = Bool
|
||||||
|
val ADR = UInt(config.addressWidth bits)
|
||||||
|
val DAT_MISO = Bits(config.dataWidth bits)
|
||||||
|
val DAT_MOSI = Bits(config.dataWidth bits)
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// OPTIONAL FLOW CONTROS //
|
||||||
|
///////////////////////////
|
||||||
|
val SEL = if(config.useSEL) Bits(config.selWidth bits) else null
|
||||||
|
val STALL = if(config.useSTALL) Bool else null
|
||||||
|
val LOCK = if(config.useLOCK) Bool else null
|
||||||
|
val ERR = if(config.useERR) Bool else null
|
||||||
|
val RTY = if(config.useRTY) Bool else null
|
||||||
|
|
||||||
|
//////////
|
||||||
|
// TAGS //
|
||||||
|
//////////
|
||||||
|
val TGD_MISO = if(config.useTGD) Bits(config.tgdWidth bits) else null
|
||||||
|
val TGD_MOSI = if(config.useTGD) Bits(config.tgdWidth bits) else null
|
||||||
|
val TGA = if(config.useTGA) Bits(config.tgaWidth bits) else null
|
||||||
|
val TGC = if(config.useTGC) Bits(config.tgcWidth bits) else null
|
||||||
|
val BTE = if(config.useBTE) Bits(2 bits) else null
|
||||||
|
val CTI = if(config.useCTI) Bits(3 bits) else null
|
||||||
|
|
||||||
|
override def asMaster(): Unit = {
|
||||||
|
outWithNull(DAT_MOSI, TGD_MOSI, ADR, CYC, LOCK, SEL, STB, TGA, TGC, WE, CTI, BTE)
|
||||||
|
inWithNull(DAT_MISO, TGD_MISO, ACK, STALL, ERR, RTY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// def isCycle : Bool = if(config.useERR) !ERR && CYC else CYC
|
||||||
|
// def isWrite : Bool = isCycle && WE
|
||||||
|
// def isRead : Bool = isCycle && !WE
|
||||||
|
// def isReadCycle : Bool = isRead && STB
|
||||||
|
// def isWriteCycle : Bool = isWrite && STB
|
||||||
|
// def isStalled : Bool = if(config.isPipelined) isCycle && STALL else False
|
||||||
|
// def isAcknoledge : Bool = isCycle && ACK
|
||||||
|
// def isStrobe : Bool = isCycle && STB
|
||||||
|
|
||||||
|
// def doSlaveWrite : Bool = this.CYC && this.STB && this.WE
|
||||||
|
// def doSlaveRead : Bool = this.CYC && this.STB && !this.WE
|
||||||
|
// def doSlavePipelinedWrite : Bool = this.CYC && this.WE
|
||||||
|
// def doSlavePipelinedRead : Bool = this.CYC && !this.WE
|
||||||
|
|
||||||
|
/** Connect the istance of this bus with another, allowing for resize of data
|
||||||
|
* @param that the wishbone instance that will be connected and resized
|
||||||
|
* @param allowDataResize allow to resize "that" data lines, default to false (disable)
|
||||||
|
* @param allowAddressResize allow to resize "that" address lines, default to false (disable)
|
||||||
|
* @param allowTagResize allow to resize "that" tag lines, default to false (disable)
|
||||||
|
*/
|
||||||
|
def connectTo(that : Wishbone, allowDataResize : Boolean = false, allowAddressResize : Boolean = false, allowTagResize : Boolean = false) : Unit = {
|
||||||
|
this.CYC <> that.CYC
|
||||||
|
this.STB <> that.STB
|
||||||
|
this.WE <> that.WE
|
||||||
|
this.ACK <> that.ACK
|
||||||
|
|
||||||
|
if(allowDataResize){
|
||||||
|
this.DAT_MISO.resized <> that.DAT_MISO
|
||||||
|
this.DAT_MOSI <> that.DAT_MOSI.resized
|
||||||
|
} else {
|
||||||
|
this.DAT_MOSI <> that.DAT_MOSI
|
||||||
|
this.DAT_MISO <> that.DAT_MISO
|
||||||
|
}
|
||||||
|
|
||||||
|
if(allowAddressResize){
|
||||||
|
this.ADR <> that.ADR.resized
|
||||||
|
} else {
|
||||||
|
this.ADR <> that.ADR
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// OPTIONAL FLOW CONTROS //
|
||||||
|
///////////////////////////
|
||||||
|
if(this.config.useSTALL && that.config.useSTALL) this.STALL <> that.STALL
|
||||||
|
if(this.config.useERR && that.config.useERR) this.ERR <> that.ERR
|
||||||
|
if(this.config.useRTY && that.config.useRTY) this.RTY <> that.RTY
|
||||||
|
if(this.config.useSEL && that.config.useSEL) this.SEL <> that.SEL
|
||||||
|
if(this.config.useCTI && that.config.useCTI) this.CTI <> that.CTI
|
||||||
|
|
||||||
|
//////////
|
||||||
|
// TAGS //
|
||||||
|
//////////
|
||||||
|
if(this.config.useTGA && that.config.useTGA)
|
||||||
|
if(allowTagResize) this.TGA <> that.TGA.resized else this.TGA <> that.TGA
|
||||||
|
|
||||||
|
if(this.config.useTGC && that.config.useTGC)
|
||||||
|
if(allowTagResize) this.TGC <> that.TGC.resized else this.TGC <> that.TGC
|
||||||
|
|
||||||
|
if(this.config.useBTE && that.config.useBTE)
|
||||||
|
if(allowTagResize) this.BTE <> that.BTE.resized else this.BTE <> that.BTE
|
||||||
|
|
||||||
|
if(this.config.useTGD && that.config.useTGD){
|
||||||
|
if(allowTagResize){
|
||||||
|
this.TGD_MISO <> that.TGD_MISO.resized
|
||||||
|
this.TGD_MOSI <> that.TGD_MOSI.resized
|
||||||
|
} else {
|
||||||
|
this.TGD_MISO <> that.TGD_MISO
|
||||||
|
this.TGD_MOSI <> that.TGD_MOSI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Connect common Wishbone signals
|
||||||
|
* @example{{{wishbone1 <-> wishbone2}}}
|
||||||
|
*/
|
||||||
|
def <-> (sink : Wishbone) : Unit = {
|
||||||
|
/////////////////////
|
||||||
|
// MINIMAL SIGNALS //
|
||||||
|
/////////////////////
|
||||||
|
sink.CYC <> this.CYC
|
||||||
|
sink.ADR <> this.ADR
|
||||||
|
sink.DAT_MOSI <> this.DAT_MOSI
|
||||||
|
sink.DAT_MISO <> this.DAT_MISO
|
||||||
|
sink.STB <> this.STB
|
||||||
|
sink.WE <> this.WE
|
||||||
|
sink.ACK <> this.ACK
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// OPTIONAL FLOW CONTROS //
|
||||||
|
///////////////////////////
|
||||||
|
if(this.config.useSTALL && sink.config.useSTALL) sink.STALL <> this.STALL
|
||||||
|
if(this.config.useERR && sink.config.useERR) sink.ERR <> this.ERR
|
||||||
|
if(this.config.useRTY && sink.config.useRTY) sink.RTY <> this.RTY
|
||||||
|
if(this.config.useSEL && sink.config.useSEL) sink.SEL <> this.SEL
|
||||||
|
|
||||||
|
//////////
|
||||||
|
// TAGS //
|
||||||
|
//////////
|
||||||
|
if(this.config.useTGA && sink.config.useTGA) sink.TGA <> this.TGA
|
||||||
|
if(this.config.useTGC && sink.config.useTGC) sink.TGC <> this.TGC
|
||||||
|
if(this.config.useCTI && sink.config.useCTI) sink.CTI <> this.CTI
|
||||||
|
if(this.config.useBTE && sink.config.useBTE) sink.BTE <> this.BTE
|
||||||
|
if(this.config.useTGD && sink.config.useTGD){
|
||||||
|
sink.TGD_MISO <> this.TGD_MISO
|
||||||
|
sink.TGD_MOSI <> this.TGD_MOSI
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clear all the relevant signals in the wishbone bus
|
||||||
|
* @example{{{
|
||||||
|
* val wishbone1 = master(Wishbone(WishboneConfig(8,8)))
|
||||||
|
* val wishbone2 = slave(Wishbone(WishboneConfig(8,8)))
|
||||||
|
* val wishbone2 = slave(Wishbone(WishboneConfig(8,8).withDataTag(8)))
|
||||||
|
*
|
||||||
|
* // this will clear only the following signals: CYC,ADR,DAT_MOSI,STB,WE
|
||||||
|
* wishbone1.clearAll()
|
||||||
|
* // this will clear only the following signals: DAT_MISO,ACK
|
||||||
|
* wishbone2.clearAll()
|
||||||
|
* // this will clear only the following signals: DAT_MISO,ACK,TGD_MISO
|
||||||
|
* wishbone3.clearAll()
|
||||||
|
* }}}
|
||||||
|
*/
|
||||||
|
def clearAll() : Unit = {
|
||||||
|
/////////////////////
|
||||||
|
// MINIMAl SIGLALS //
|
||||||
|
/////////////////////
|
||||||
|
if( isMasterInterface) this.CYC.clear()
|
||||||
|
if( isMasterInterface) this.ADR.clearAll()
|
||||||
|
if( isMasterInterface) this.DAT_MOSI.clearAll()
|
||||||
|
if(!isMasterInterface) this.DAT_MISO.clearAll()
|
||||||
|
if( isMasterInterface) this.STB.clear()
|
||||||
|
if( isMasterInterface) this.WE.clear()
|
||||||
|
if(!isMasterInterface) this.ACK.clear()
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// OPTIONAL FLOW CONTROS //
|
||||||
|
///////////////////////////
|
||||||
|
if(this.config.useSTALL && !isMasterInterface) this.STALL.clear()
|
||||||
|
if(this.config.useERR && !isMasterInterface) this.ERR.clear()
|
||||||
|
if(this.config.useRTY && !isMasterInterface) this.RTY.clear()
|
||||||
|
if(this.config.useSEL && isMasterInterface) this.SEL.clearAll()
|
||||||
|
|
||||||
|
//////////
|
||||||
|
// TAGS //
|
||||||
|
//////////
|
||||||
|
if(this.config.useTGA && isMasterInterface) this.TGA.clearAll()
|
||||||
|
if(this.config.useTGC && isMasterInterface) this.TGC.clearAll()
|
||||||
|
if(this.config.useCTI && isMasterInterface) this.CTI.clearAll()
|
||||||
|
if(this.config.useBTE && isMasterInterface) this.BTE.clearAll()
|
||||||
|
if(this.config.useTGD && !isMasterInterface) this.TGD_MISO.clearAll()
|
||||||
|
if(this.config.useTGD && isMasterInterface) this.TGD_MOSI.clearAll()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
package vexriscv.demo
|
||||||
|
|
||||||
|
import spinal.core._
|
||||||
|
import spinal.lib._
|
||||||
|
import spinal.lib.bus.avalon.AvalonMM
|
||||||
|
import spinal.lib.eda.altera.{InterruptReceiverTag, QSysify, ResetEmitterTag}
|
||||||
|
import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig}
|
||||||
|
import vexriscv.plugin._
|
||||||
|
import vexriscv.{VexRiscv, VexRiscvConfig, plugin}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by spinalvm on 14.07.17.
|
||||||
|
*/
|
||||||
|
//class VexRiscvAvalon(debugClockDomain : ClockDomain) extends Component{
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
// make clean run DBUS=CACHED_WISHBONE IBUS=CACHED_WISHBONE MMU=no CSR=no DEBUG_PLUGIN=no
|
||||||
|
object VexRiscvCachedWishboneForSim{
|
||||||
|
def main(args: Array[String]) {
|
||||||
|
val report = SpinalVerilog{
|
||||||
|
|
||||||
|
//CPU configuration
|
||||||
|
val cpuConfig = VexRiscvConfig(
|
||||||
|
plugins = List(
|
||||||
|
new PcManagerSimplePlugin(0x00000000l, false),
|
||||||
|
// new IBusSimplePlugin(
|
||||||
|
// interfaceKeepData = false,
|
||||||
|
// catchAccessFault = false
|
||||||
|
// ),
|
||||||
|
// new DBusSimplePlugin(
|
||||||
|
// catchAddressMisaligned = false,
|
||||||
|
// catchAccessFault = false
|
||||||
|
// ),
|
||||||
|
new IBusCachedPlugin(
|
||||||
|
config = InstructionCacheConfig(
|
||||||
|
cacheSize = 4096,
|
||||||
|
bytePerLine =32,
|
||||||
|
wayCount = 1,
|
||||||
|
addressWidth = 32,
|
||||||
|
cpuDataWidth = 32,
|
||||||
|
memDataWidth = 32,
|
||||||
|
catchIllegalAccess = true,
|
||||||
|
catchAccessFault = true,
|
||||||
|
catchMemoryTranslationMiss = true,
|
||||||
|
asyncTagMemory = false,
|
||||||
|
twoCycleRam = true
|
||||||
|
)
|
||||||
|
// askMemoryTranslation = true,
|
||||||
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
// portTlbSize = 4
|
||||||
|
// )
|
||||||
|
),
|
||||||
|
new DBusCachedPlugin(
|
||||||
|
config = new DataCacheConfig(
|
||||||
|
cacheSize = 4096,
|
||||||
|
bytePerLine = 32,
|
||||||
|
wayCount = 1,
|
||||||
|
addressWidth = 32,
|
||||||
|
cpuDataWidth = 32,
|
||||||
|
memDataWidth = 32,
|
||||||
|
catchAccessError = true,
|
||||||
|
catchIllegal = true,
|
||||||
|
catchUnaligned = true,
|
||||||
|
catchMemoryTranslationMiss = true
|
||||||
|
),
|
||||||
|
memoryTranslatorPortConfig = null
|
||||||
|
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
|
||||||
|
// portTlbSize = 6
|
||||||
|
// )
|
||||||
|
),
|
||||||
|
new StaticMemoryTranslatorPlugin(
|
||||||
|
ioRange = _(31 downto 28) === 0xF
|
||||||
|
),
|
||||||
|
new DecoderSimplePlugin(
|
||||||
|
catchIllegalInstruction = true
|
||||||
|
),
|
||||||
|
new RegFilePlugin(
|
||||||
|
regFileReadyKind = plugin.SYNC,
|
||||||
|
zeroBoot = false
|
||||||
|
),
|
||||||
|
new IntAluPlugin,
|
||||||
|
new SrcPlugin(
|
||||||
|
separatedAddSub = false,
|
||||||
|
executeInsertion = true
|
||||||
|
),
|
||||||
|
new FullBarrielShifterPlugin,
|
||||||
|
new MulPlugin,
|
||||||
|
new DivPlugin,
|
||||||
|
new HazardSimplePlugin(
|
||||||
|
bypassExecute = true,
|
||||||
|
bypassMemory = true,
|
||||||
|
bypassWriteBack = true,
|
||||||
|
bypassWriteBackBuffer = true,
|
||||||
|
pessimisticUseSrc = false,
|
||||||
|
pessimisticWriteRegFile = false,
|
||||||
|
pessimisticAddressMatch = false
|
||||||
|
),
|
||||||
|
// new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))),
|
||||||
|
new BranchPlugin(
|
||||||
|
earlyBranch = false,
|
||||||
|
catchAddressMisaligned = true,
|
||||||
|
prediction = STATIC
|
||||||
|
),
|
||||||
|
new CsrPlugin(
|
||||||
|
config = CsrPluginConfig.small(mtvecInit = 0x80000020l)
|
||||||
|
),
|
||||||
|
new YamlPlugin("cpu0.yaml")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
//CPU instanciation
|
||||||
|
val cpu = new VexRiscv(cpuConfig)
|
||||||
|
|
||||||
|
//CPU modifications to be an Avalon one
|
||||||
|
//cpu.setDefinitionName("VexRiscvAvalon")
|
||||||
|
cpu.rework {
|
||||||
|
for (plugin <- cpuConfig.plugins) plugin match {
|
||||||
|
// case plugin: IBusSimplePlugin => {
|
||||||
|
// plugin.iBus.asDirectionLess() //Unset IO properties of iBus
|
||||||
|
// iBus = master(plugin.iBus.toAvalon())
|
||||||
|
// .setName("iBusAvalon")
|
||||||
|
// .addTag(ClockDomainTag(ClockDomain.current)) //Specify a clock domain to the iBus (used by QSysify)
|
||||||
|
// }
|
||||||
|
case plugin: IBusCachedPlugin => {
|
||||||
|
plugin.iBus.asDirectionLess() //Unset IO properties of iBus
|
||||||
|
master(plugin.iBus.toWishbone()).setName("iBusWishbone")
|
||||||
|
}
|
||||||
|
// case plugin: DBusSimplePlugin => {
|
||||||
|
// plugin.dBus.asDirectionLess()
|
||||||
|
// master(plugin.dBus.toAvalon())
|
||||||
|
// .setName("dBusAvalon")
|
||||||
|
// .addTag(ClockDomainTag(ClockDomain.current))
|
||||||
|
// }
|
||||||
|
case plugin: DBusCachedPlugin => {
|
||||||
|
plugin.dBus.asDirectionLess()
|
||||||
|
master(plugin.dBus.toWishbone()).setName("dBusWishbone")
|
||||||
|
}
|
||||||
|
// case plugin: DebugPlugin => {
|
||||||
|
// plugin.io.bus.asDirectionLess()
|
||||||
|
// slave(plugin.io.bus.fromAvalon())
|
||||||
|
// .setName("debugBusAvalon")
|
||||||
|
// .addTag(ClockDomainTag(plugin.debugClockDomain))
|
||||||
|
// .parent = null //Avoid the io bundle to be interpreted as a QSys conduit
|
||||||
|
// plugin.io.resetOut
|
||||||
|
// .addTag(ResetEmitterTag(plugin.debugClockDomain))
|
||||||
|
// .parent = null //Avoid the io bundle to be interpreted as a QSys conduit
|
||||||
|
// }
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cpu
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate the QSys TCL script to integrate the CPU
|
||||||
|
QSysify(report.toplevel)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,9 @@ package vexriscv.ip
|
||||||
import vexriscv._
|
import vexriscv._
|
||||||
import spinal.core._
|
import spinal.core._
|
||||||
import spinal.lib._
|
import spinal.lib._
|
||||||
import spinal.lib.bus.amba4.axi.{Axi4Shared, Axi4Config}
|
import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4Shared}
|
||||||
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||||
|
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
||||||
|
|
||||||
case class DataCacheConfig( cacheSize : Int,
|
case class DataCacheConfig( cacheSize : Int,
|
||||||
bytePerLine : Int,
|
bytePerLine : Int,
|
||||||
|
@ -46,6 +46,21 @@ case class DataCacheConfig( cacheSize : Int,
|
||||||
useResponse = true,
|
useResponse = true,
|
||||||
maximumPendingReadTransactions = 2
|
maximumPendingReadTransactions = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def getWishboneConfig() = WishboneConfig(
|
||||||
|
addressWidth = 30,
|
||||||
|
dataWidth = 32,
|
||||||
|
selWidth = 4,
|
||||||
|
useSTALL = false,
|
||||||
|
useLOCK = false,
|
||||||
|
useERR = true,
|
||||||
|
useRTY = false,
|
||||||
|
tgaWidth = 0,
|
||||||
|
tgcWidth = 0,
|
||||||
|
tgdWidth = 0,
|
||||||
|
useBTE = true,
|
||||||
|
useCTI = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -285,6 +300,48 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave
|
||||||
|
|
||||||
mm
|
mm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def toWishbone(): Wishbone = {
|
||||||
|
val wishboneConfig = p.getWishboneConfig()
|
||||||
|
val bus = Wishbone(wishboneConfig)
|
||||||
|
val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0)
|
||||||
|
|
||||||
|
val cmdBridge = Stream (DataCacheMemCmd(p))
|
||||||
|
val isBurst = cmdBridge.length =/= 0
|
||||||
|
cmdBridge.valid := cmd.valid
|
||||||
|
cmdBridge.address := (isBurst ? (cmd.address(31 downto widthOf(counter) + 2) @@ counter @@ "00") | (cmd.address(31 downto 2) @@ "00"))
|
||||||
|
cmdBridge.wr := cmd.wr
|
||||||
|
cmdBridge.mask := cmd.mask
|
||||||
|
cmdBridge.data := cmd.data
|
||||||
|
cmdBridge.length := cmd.length
|
||||||
|
cmdBridge.last := counter === cmd.length
|
||||||
|
cmd.ready := cmdBridge.ready && (cmdBridge.wr || cmdBridge.last)
|
||||||
|
|
||||||
|
|
||||||
|
when(cmdBridge.fire){
|
||||||
|
counter := counter + 1
|
||||||
|
when(cmdBridge.last){
|
||||||
|
counter := 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bus.ADR := cmdBridge.address >> 2
|
||||||
|
bus.CTI := Mux(isBurst, cmdBridge.last ? B"111" | B"010", B"000")
|
||||||
|
bus.BTE := "00"
|
||||||
|
bus.SEL := cmdBridge.wr ? cmdBridge.mask | "1111"
|
||||||
|
bus.WE := cmdBridge.wr
|
||||||
|
bus.DAT_MOSI := cmdBridge.data
|
||||||
|
|
||||||
|
cmdBridge.ready := cmdBridge.valid && bus.ACK
|
||||||
|
bus.CYC := cmdBridge.valid
|
||||||
|
bus.STB := cmdBridge.valid
|
||||||
|
|
||||||
|
rsp.valid := RegNext(cmdBridge.valid && !bus.WE && bus.ACK) init(False)
|
||||||
|
rsp.data := RegNext(bus.DAT_MISO)
|
||||||
|
rsp.error := False //TODO
|
||||||
|
bus
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,9 @@ package vexriscv.ip
|
||||||
import vexriscv._
|
import vexriscv._
|
||||||
import spinal.core._
|
import spinal.core._
|
||||||
import spinal.lib._
|
import spinal.lib._
|
||||||
import spinal.lib.bus.amba4.axi.{Axi4ReadOnly, Axi4Config}
|
import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly}
|
||||||
import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
|
import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig}
|
||||||
|
import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig}
|
||||||
|
|
||||||
|
|
||||||
case class InstructionCacheConfig( cacheSize : Int,
|
case class InstructionCacheConfig( cacheSize : Int,
|
||||||
|
@ -42,6 +43,20 @@ case class InstructionCacheConfig( cacheSize : Int,
|
||||||
constantBurstBehavior = true
|
constantBurstBehavior = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def getWishboneConfig() = WishboneConfig(
|
||||||
|
addressWidth = 30,
|
||||||
|
dataWidth = 32,
|
||||||
|
selWidth = 4,
|
||||||
|
useSTALL = false,
|
||||||
|
useLOCK = false,
|
||||||
|
useERR = true,
|
||||||
|
useRTY = false,
|
||||||
|
tgaWidth = 0,
|
||||||
|
tgcWidth = 0,
|
||||||
|
tgdWidth = 0,
|
||||||
|
useBTE = true,
|
||||||
|
useCTI = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,6 +164,36 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit
|
||||||
rsp.error := mm.response =/= AvalonMM.Response.OKAY
|
rsp.error := mm.response =/= AvalonMM.Response.OKAY
|
||||||
mm
|
mm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def toWishbone(): Wishbone = {
|
||||||
|
val wishboneConfig = p.getWishboneConfig()
|
||||||
|
val bus = Wishbone(wishboneConfig)
|
||||||
|
val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0)
|
||||||
|
val pending = counter =/= 0
|
||||||
|
val lastCycle = counter === counter.maxValue
|
||||||
|
|
||||||
|
bus.ADR := (cmd.address >> widthOf(counter) + 2) @@ counter
|
||||||
|
bus.CTI := lastCycle ? B"111" | B"010"
|
||||||
|
bus.BTE := "00"
|
||||||
|
bus.SEL := "1111"
|
||||||
|
bus.WE := False
|
||||||
|
bus.DAT_MOSI.assignDontCare()
|
||||||
|
bus.CYC := False
|
||||||
|
bus.STB := False
|
||||||
|
when(cmd.valid || pending){
|
||||||
|
bus.CYC := True
|
||||||
|
bus.STB := True
|
||||||
|
when(bus.ACK){
|
||||||
|
counter := counter + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.ready := cmd.valid && bus.ACK
|
||||||
|
rsp.valid := RegNext(bus.CYC && bus.ACK) init(False)
|
||||||
|
rsp.data := RegNext(bus.DAT_MISO)
|
||||||
|
rsp.error := False //TODO
|
||||||
|
bus
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ class DAxiCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv]{
|
class DBusCachedPlugin(config : DataCacheConfig,
|
||||||
|
memoryTranslatorPortConfig : Any = null,
|
||||||
|
csrInfo : Boolean = false) extends Plugin[VexRiscv]{
|
||||||
import config._
|
import config._
|
||||||
var dBus : DataCacheMemBus = null
|
var dBus : DataCacheMemBus = null
|
||||||
var mmuBus : MemoryTranslatorBus = null
|
var mmuBus : MemoryTranslatorBus = null
|
||||||
|
@ -213,7 +215,12 @@ class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An
|
||||||
when(arbitration.isValid && input(MEMORY_ENABLE)) {
|
when(arbitration.isValid && input(MEMORY_ENABLE)) {
|
||||||
output(REGFILE_WRITE_DATA) := rspFormated
|
output(REGFILE_WRITE_DATA) := rspFormated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(csrInfo){
|
||||||
|
val csr = service(classOf[CsrPlugin])
|
||||||
|
csr.r(0xCC0, 0 -> U(cacheSize/wayCount), 20 -> U(bytePerLine))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package vexriscv.plugin
|
||||||
|
|
||||||
|
import spinal.core._
|
||||||
|
import vexriscv.VexRiscv
|
||||||
|
|
||||||
|
class ExternalInterruptArrayPlugin(arrayWidth : Int = 32) extends Plugin[VexRiscv]{
|
||||||
|
var externalInterruptArray : Bits = null
|
||||||
|
|
||||||
|
override def setup(pipeline: VexRiscv): Unit = {
|
||||||
|
externalInterruptArray = in(Bits(arrayWidth bits)).setName("externalInterruptArray")
|
||||||
|
}
|
||||||
|
|
||||||
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
|
val csr = pipeline.service(classOf[CsrPlugin])
|
||||||
|
val mask = Reg(Bits(arrayWidth bits)) init(0)
|
||||||
|
val pendings = mask & RegNext(externalInterruptArray)
|
||||||
|
csr.externalInterrupt.asDirectionLess() := pendings.orR
|
||||||
|
csr.rw(0x330, mask)
|
||||||
|
csr.r(0x360, pendings)
|
||||||
|
}
|
||||||
|
}
|
|
@ -430,8 +430,6 @@ public:
|
||||||
top->eval();
|
top->eval();
|
||||||
|
|
||||||
|
|
||||||
dump(i + 1);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
|
if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){
|
||||||
|
@ -444,6 +442,8 @@ public:
|
||||||
|
|
||||||
for(SimElement* simElement : simElements) simElement->preCycle();
|
for(SimElement* simElement : simElements) simElement->preCycle();
|
||||||
|
|
||||||
|
dump(i + 1);
|
||||||
|
|
||||||
if(withInstructionReadCheck){
|
if(withInstructionReadCheck){
|
||||||
if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself && !top->VexRiscv->decode_arbitration_flushAll){
|
if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself && !top->VexRiscv->decode_arbitration_flushAll){
|
||||||
uint32_t expectedData;
|
uint32_t expectedData;
|
||||||
|
@ -686,6 +686,48 @@ public:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef IBUS_CACHED_WISHBONE
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
|
||||||
|
class IBusCachedWishbone : public SimElement{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Workspace *ws;
|
||||||
|
VVexRiscv* top;
|
||||||
|
|
||||||
|
IBusCachedWishbone(Workspace* ws){
|
||||||
|
this->ws = ws;
|
||||||
|
this->top = ws->top;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onReset(){
|
||||||
|
top->iBusWishbone_ACK = !ws->iStall;
|
||||||
|
top->iBusWishbone_ERR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void preCycle(){
|
||||||
|
top->iBusWishbone_DAT_MISO = VL_RANDOM_I(32);
|
||||||
|
if (top->iBusWishbone_CYC && top->iBusWishbone_STB && top->iBusWishbone_ACK) {
|
||||||
|
if(top->iBusWishbone_WE){
|
||||||
|
|
||||||
|
} else {
|
||||||
|
bool error;
|
||||||
|
ws->iBusAccess(top->iBusWishbone_ADR << 2,&top->iBusWishbone_DAT_MISO,&error);
|
||||||
|
top->iBusWishbone_ERR = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void postCycle(){
|
||||||
|
if(ws->iStall)
|
||||||
|
top->iBusWishbone_ACK = VL_RANDOM_I(7) < 100;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef DBUS_SIMPLE
|
#ifdef DBUS_SIMPLE
|
||||||
class DBusSimple : public SimElement{
|
class DBusSimple : public SimElement{
|
||||||
public:
|
public:
|
||||||
|
@ -782,8 +824,47 @@ public:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DBUS_CACHED_WISHBONE
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
|
||||||
|
class DBusCachedWishbone : public SimElement{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Workspace *ws;
|
||||||
|
VVexRiscv* top;
|
||||||
|
|
||||||
|
DBusCachedWishbone(Workspace* ws){
|
||||||
|
this->ws = ws;
|
||||||
|
this->top = ws->top;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onReset(){
|
||||||
|
top->dBusWishbone_ACK = !ws->iStall;
|
||||||
|
top->dBusWishbone_ERR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void preCycle(){
|
||||||
|
top->dBusWishbone_DAT_MISO = VL_RANDOM_I(32);
|
||||||
|
if (top->dBusWishbone_CYC && top->dBusWishbone_STB && top->dBusWishbone_ACK) {
|
||||||
|
if(top->dBusWishbone_WE){
|
||||||
|
bool dummy;
|
||||||
|
ws->dBusAccess(top->dBusWishbone_ADR << 2 ,1,2,top->dBusWishbone_SEL,&top->dBusWishbone_DAT_MOSI,&dummy);
|
||||||
|
} else {
|
||||||
|
bool error;
|
||||||
|
ws->dBusAccess(top->dBusWishbone_ADR << 2,0,2,0xF,&top->dBusWishbone_DAT_MISO,&error);
|
||||||
|
top->dBusWishbone_ERR = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void postCycle(){
|
||||||
|
if(ws->iStall)
|
||||||
|
top->dBusWishbone_ACK = VL_RANDOM_I(7) < 100;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DBUS_CACHED
|
#ifdef DBUS_CACHED
|
||||||
|
|
||||||
//#include "VVexRiscv_DataCache.h"
|
//#include "VVexRiscv_DataCache.h"
|
||||||
|
@ -1216,6 +1297,9 @@ void Workspace::fillSimELements(){
|
||||||
#ifdef IBUS_CACHED_AVALON
|
#ifdef IBUS_CACHED_AVALON
|
||||||
simElements.push_back(new IBusCachedAvalon(this));
|
simElements.push_back(new IBusCachedAvalon(this));
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef IBUS_CACHED_WISHBONE
|
||||||
|
simElements.push_back(new IBusCachedWishbone(this));
|
||||||
|
#endif
|
||||||
#ifdef DBUS_SIMPLE
|
#ifdef DBUS_SIMPLE
|
||||||
simElements.push_back(new DBusSimple(this));
|
simElements.push_back(new DBusSimple(this));
|
||||||
#endif
|
#endif
|
||||||
|
@ -1228,6 +1312,9 @@ void Workspace::fillSimELements(){
|
||||||
#ifdef DBUS_CACHED_AVALON
|
#ifdef DBUS_CACHED_AVALON
|
||||||
simElements.push_back(new DBusCachedAvalon(this));
|
simElements.push_back(new DBusCachedAvalon(this));
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DBUS_CACHED_WISHBONE
|
||||||
|
simElements.push_back(new DBusCachedWishbone(this));
|
||||||
|
#endif
|
||||||
#ifdef DEBUG_PLUGIN_STD
|
#ifdef DEBUG_PLUGIN_STD
|
||||||
simElements.push_back(new DebugPluginStd(this));
|
simElements.push_back(new DebugPluginStd(this));
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue