From a66efcb35b513f8545d95e60c1f52a6fac269189 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Tue, 17 Apr 2018 23:56:44 +0200 Subject: [PATCH 1/7] Add wishbone support for i$ / d$ (not tested) --- .../spinal/lib/bus/wishbone/Wishbone.scala | 241 ++++++++++++++++++ src/main/scala/vexriscv/ip/DataCache.scala | 63 ++++- .../scala/vexriscv/ip/InstructionCache.scala | 47 +++- 3 files changed, 347 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala diff --git a/src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala b/src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala new file mode 100644 index 0000000..1f41faa --- /dev/null +++ b/src/main/scala/spinal/lib/bus/wishbone/Wishbone.scala @@ -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() + } +} diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 769d089..231dd8c 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -3,9 +3,9 @@ package vexriscv.ip import vexriscv._ import spinal.core._ 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.wishbone.{Wishbone, WishboneConfig} case class DataCacheConfig( cacheSize : Int, bytePerLine : Int, @@ -46,6 +46,21 @@ case class DataCacheConfig( cacheSize : Int, useResponse = true, maximumPendingReadTransactions = 2 ) + + def getWishboneConfig() = WishboneConfig( + addressWidth = 32, + 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,50 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave mm } + + def toWishbone(): Wishbone = { + val wishboneConfig = p.getWishboneConfig() + val bus = Wishbone(wishboneConfig) + val counter = Reg(UInt(log2Up(p.burstSize) bits)) + + val cmdBridge = Stream (DataCacheMemCmd(p)) + cmdBridge.valid := cmd.valid + cmdBridge.address := (cmd.address >> widthOf(counter) + 2) @@ counter @@ "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 + } + } + + + val isBurst = cmdBridge.length =/= 0 + bus.ADR := cmdBridge.address + 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 := bus.ACK + when(cmdBridge.valid) { + bus.CYC := True + bus.STB := True + } + + rsp.valid := RegNext(bus.WE && bus.ACK) init(False) + rsp.data := RegNext(bus.DAT_MISO) + rsp.error := False //TODO + bus + } } diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index fe57dc1..03b6f2c 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -3,8 +3,9 @@ package vexriscv.ip import vexriscv._ import spinal.core._ import spinal.lib._ -import spinal.lib.bus.amba4.axi.{Axi4ReadOnly, Axi4Config} -import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM} +import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly} +import spinal.lib.bus.avalon.{AvalonMM, AvalonMMConfig} +import spinal.lib.bus.wishbone.{Wishbone, WishboneConfig} case class InstructionCacheConfig( cacheSize : Int, @@ -42,6 +43,20 @@ case class InstructionCacheConfig( cacheSize : Int, constantBurstBehavior = true ) + def getWishboneConfig() = WishboneConfig( + addressWidth = 32, + 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,34 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit rsp.error := mm.response =/= AvalonMM.Response.OKAY mm } + + def toWishbone(): Wishbone = { + val wishboneConfig = p.getWishboneConfig() + val bus = Wishbone(wishboneConfig) + val counter = Reg(UInt(log2Up(p.burstSize) bits)) + val pending = counter =/= 0 + val lastCycle = counter === counter.maxValue + + bus.ADR := (cmd.address >> widthOf(counter) + 2) @@ counter @@ "00" + bus.CTI := lastCycle ? B"111" | B"010" + bus.BTE := "00" + bus.SEL := "1111" + bus.WE := False + bus.DAT_MOSI.assignDontCare() + when(cmd.valid || pending){ + bus.CYC := True + bus.STB := True + when(bus.ACK){ + counter := counter + 1 + } + } + + cmd.ready := !pending + rsp.valid := RegNext(bus.ACK) init(False) + rsp.data := RegNext(bus.DAT_MISO) + rsp.error := False //TODO + bus + } } From b37fc3fcc8634ce5a17514d594ffea6e686b617b Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 18 Apr 2018 12:54:20 +0200 Subject: [PATCH 2/7] Add VexRiscv Wishbone demo for sim (generation ok) --- .../demo/VexRiscvCachedWishboneForSim.scala | 159 ++++++++++++++++++ src/main/scala/vexriscv/ip/DataCache.scala | 6 +- .../scala/vexriscv/ip/InstructionCache.scala | 2 + 3 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala diff --git a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala new file mode 100644 index 0000000..3663098 --- /dev/null +++ b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala @@ -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_AVALON IBUS=CACHED_AVALON MMU=no CSR=no DEBUG_PLUGIN=AVALON + +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) + } +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 231dd8c..bde7b6f 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -334,10 +334,8 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.DAT_MOSI := cmdBridge.data cmdBridge.ready := bus.ACK - when(cmdBridge.valid) { - bus.CYC := True - bus.STB := True - } + bus.CYC := cmdBridge.valid + bus.STB := cmdBridge.valid rsp.valid := RegNext(bus.WE && bus.ACK) init(False) rsp.data := RegNext(bus.DAT_MISO) diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 03b6f2c..62b9709 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -178,6 +178,8 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit 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 From 6e59ddcc7325e37a263df54bd5b1306bee2642fb Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 18 Apr 2018 13:51:33 +0200 Subject: [PATCH 3/7] Cached wishbone demo is passing regression tests --- .../demo/VexRiscvCachedWishboneForSim.scala | 2 +- src/main/scala/vexriscv/ip/DataCache.scala | 6 +- .../scala/vexriscv/ip/InstructionCache.scala | 6 +- src/test/cpp/regression/main.cpp | 89 +++++++++++++++++++ 4 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala index 3663098..08faa6d 100644 --- a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala +++ b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala @@ -15,8 +15,8 @@ import vexriscv.{VexRiscv, VexRiscvConfig, plugin} // //} -//make clean run DBUS=CACHED_AVALON IBUS=CACHED_AVALON MMU=no CSR=no DEBUG_PLUGIN=AVALON +// 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{ diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index bde7b6f..bee154c 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -304,7 +304,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave def toWishbone(): Wishbone = { val wishboneConfig = p.getWishboneConfig() val bus = Wishbone(wishboneConfig) - val counter = Reg(UInt(log2Up(p.burstSize) bits)) + val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) val cmdBridge = Stream (DataCacheMemCmd(p)) cmdBridge.valid := cmd.valid @@ -333,11 +333,11 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave bus.WE := cmdBridge.wr bus.DAT_MOSI := cmdBridge.data - cmdBridge.ready := bus.ACK + cmdBridge.ready := cmdBridge.valid && bus.ACK bus.CYC := cmdBridge.valid bus.STB := cmdBridge.valid - rsp.valid := RegNext(bus.WE && bus.ACK) init(False) + rsp.valid := RegNext(cmdBridge.valid && !bus.WE && bus.ACK) init(False) rsp.data := RegNext(bus.DAT_MISO) rsp.error := False //TODO bus diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 62b9709..2b77a5d 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -168,7 +168,7 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit def toWishbone(): Wishbone = { val wishboneConfig = p.getWishboneConfig() val bus = Wishbone(wishboneConfig) - val counter = Reg(UInt(log2Up(p.burstSize) bits)) + val counter = Reg(UInt(log2Up(p.burstSize) bits)) init(0) val pending = counter =/= 0 val lastCycle = counter === counter.maxValue @@ -188,8 +188,8 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit } } - cmd.ready := !pending - rsp.valid := RegNext(bus.ACK) init(False) + 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 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index af0fcda..f9634b9 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -686,6 +686,49 @@ public: }; #endif + +#ifdef IBUS_CACHED_WISHBONE +#include + + +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) { + assertEq(top->iBusWishbone_ADR & 3,0); + if(top->iBusWishbone_WE){ + + } else { + bool error; + ws->iBusAccess(top->iBusWishbone_ADR,&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 class DBusSimple : public SimElement{ public: @@ -782,8 +825,48 @@ public: }; #endif +#ifdef DBUS_CACHED_WISHBONE +#include +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) { + assertEq(top->dBusWishbone_ADR & 3,0); + if(top->dBusWishbone_WE){ + bool dummy; + ws->dBusAccess(top->dBusWishbone_ADR,1,2,top->dBusWishbone_SEL,&top->dBusWishbone_DAT_MOSI,&dummy); + } else { + bool error; + ws->dBusAccess(top->dBusWishbone_ADR,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 //#include "VVexRiscv_DataCache.h" @@ -1216,6 +1299,9 @@ void Workspace::fillSimELements(){ #ifdef IBUS_CACHED_AVALON simElements.push_back(new IBusCachedAvalon(this)); #endif + #ifdef IBUS_CACHED_WISHBONE + simElements.push_back(new IBusCachedWishbone(this)); + #endif #ifdef DBUS_SIMPLE simElements.push_back(new DBusSimple(this)); #endif @@ -1228,6 +1314,9 @@ void Workspace::fillSimELements(){ #ifdef DBUS_CACHED_AVALON simElements.push_back(new DBusCachedAvalon(this)); #endif + #ifdef DBUS_CACHED_WISHBONE + simElements.push_back(new DBusCachedWishbone(this)); + #endif #ifdef DEBUG_PLUGIN_STD simElements.push_back(new DebugPluginStd(this)); #endif From 455607b6b42909378ec12496b583aa6215b8bfc9 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Wed, 18 Apr 2018 14:11:59 +0200 Subject: [PATCH 4/7] Fix dBus IO access --- src/main/scala/vexriscv/ip/DataCache.scala | 4 ++-- src/test/cpp/regression/main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index bee154c..0963de1 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -307,8 +307,9 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave 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 := (cmd.address >> widthOf(counter) + 2) @@ counter @@ "00" + 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 @@ -325,7 +326,6 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave } - val isBurst = cmdBridge.length =/= 0 bus.ADR := cmdBridge.address bus.CTI := Mux(isBurst, cmdBridge.last ? B"111" | B"010", B"000") bus.BTE := "00" diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index f9634b9..7d9a0b8 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -430,8 +430,6 @@ public: top->eval(); - dump(i + 1); - 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(); + dump(i + 1); + if(withInstructionReadCheck){ if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself && !top->VexRiscv->decode_arbitration_flushAll){ uint32_t expectedData; From 6598e8292000e9a15c0e35e19c53937b1db13a43 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Thu, 19 Apr 2018 11:22:06 +0200 Subject: [PATCH 5/7] wishbone => word address, not byte address --- src/main/scala/vexriscv/ip/DataCache.scala | 4 ++-- src/main/scala/vexriscv/ip/InstructionCache.scala | 4 ++-- src/test/cpp/regression/main.cpp | 8 +++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/scala/vexriscv/ip/DataCache.scala b/src/main/scala/vexriscv/ip/DataCache.scala index 0963de1..9099885 100644 --- a/src/main/scala/vexriscv/ip/DataCache.scala +++ b/src/main/scala/vexriscv/ip/DataCache.scala @@ -48,7 +48,7 @@ case class DataCacheConfig( cacheSize : Int, ) def getWishboneConfig() = WishboneConfig( - addressWidth = 32, + addressWidth = 30, dataWidth = 32, selWidth = 4, useSTALL = false, @@ -326,7 +326,7 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave } - bus.ADR := cmdBridge.address + 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" diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 2b77a5d..c1171a4 100644 --- a/src/main/scala/vexriscv/ip/InstructionCache.scala +++ b/src/main/scala/vexriscv/ip/InstructionCache.scala @@ -44,7 +44,7 @@ case class InstructionCacheConfig( cacheSize : Int, ) def getWishboneConfig() = WishboneConfig( - addressWidth = 32, + addressWidth = 30, dataWidth = 32, selWidth = 4, useSTALL = false, @@ -172,7 +172,7 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit val pending = counter =/= 0 val lastCycle = counter === counter.maxValue - bus.ADR := (cmd.address >> widthOf(counter) + 2) @@ counter @@ "00" + bus.ADR := (cmd.address >> widthOf(counter) + 2) @@ counter bus.CTI := lastCycle ? B"111" | B"010" bus.BTE := "00" bus.SEL := "1111" diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 7d9a0b8..99317f3 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -710,12 +710,11 @@ public: virtual void preCycle(){ top->iBusWishbone_DAT_MISO = VL_RANDOM_I(32); if (top->iBusWishbone_CYC && top->iBusWishbone_STB && top->iBusWishbone_ACK) { - assertEq(top->iBusWishbone_ADR & 3,0); if(top->iBusWishbone_WE){ } else { bool error; - ws->iBusAccess(top->iBusWishbone_ADR,&top->iBusWishbone_DAT_MISO,&error); + ws->iBusAccess(top->iBusWishbone_ADR << 2,&top->iBusWishbone_DAT_MISO,&error); top->iBusWishbone_ERR = error; } } @@ -848,13 +847,12 @@ public: virtual void preCycle(){ top->dBusWishbone_DAT_MISO = VL_RANDOM_I(32); if (top->dBusWishbone_CYC && top->dBusWishbone_STB && top->dBusWishbone_ACK) { - assertEq(top->dBusWishbone_ADR & 3,0); if(top->dBusWishbone_WE){ bool dummy; - ws->dBusAccess(top->dBusWishbone_ADR,1,2,top->dBusWishbone_SEL,&top->dBusWishbone_DAT_MOSI,&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,0,2,0xF,&top->dBusWishbone_DAT_MISO,&error); + ws->dBusAccess(top->dBusWishbone_ADR << 2,0,2,0xF,&top->dBusWishbone_DAT_MISO,&error); top->dBusWishbone_ERR = error; } } From 74f2a4194a8d28b3626165493ad2ddab0f86f8d6 Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Fri, 20 Apr 2018 17:56:21 +0200 Subject: [PATCH 6/7] Add ExternalInterruptArrayPlugin --- .../plugin/ExternalInterruptArrayPlugin.scala | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala diff --git a/src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala b/src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala new file mode 100644 index 0000000..b205f0f --- /dev/null +++ b/src/main/scala/vexriscv/plugin/ExternalInterruptArrayPlugin.scala @@ -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) + } +} From 978eb9b6b26bcb8241b937b951522d1ed7611cef Mon Sep 17 00:00:00 2001 From: Dolu1990 Date: Sun, 22 Apr 2018 11:46:01 +0200 Subject: [PATCH 7/7] DBusCachedPlugin add CSR info --- src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index bdd60f1..ee7caa3 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -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._ var dBus : DataCacheMemBus = null var mmuBus : MemoryTranslatorBus = null @@ -213,7 +215,12 @@ class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : An when(arbitration.isValid && input(MEMORY_ENABLE)) { output(REGFILE_WRITE_DATA) := rspFormated } - } + } + + if(csrInfo){ + val csr = service(classOf[CsrPlugin]) + csr.r(0xCC0, 0 -> U(cacheSize/wayCount), 20 -> U(bytePerLine)) + } } }