diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..924f882 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,60 @@ +language: scala + +notifications: + email: + on_success: never + +# See 'project/Version.scala' +scala: + - 2.11.6 + +sbt_args: -no-colors -J-Xss2m + +script: + - sbt -jvm-opts travis/jvmopts.compile compile + - sbt -jvm-opts travis/jvmopts.test test + +jdk: + - oraclejdk8 +# - oraclejdk7 +# - openjdk7 + +env: + - secure: "v7FHP8yK/zixpv1ML05qcRhZfDVDFdTmTPjfMZHL7gmrJveVDgze22x4tY4tB1+JEXhKuVTYvimOrX/Ok+rOOT5gVKLowv4PUQwCR+HgWVIbqjcfZNLsa369v03/p4K/zbjJSiXFahZYOXa0ApED2KWHcVfCrNsPv0UF7YZGiIa1Q/lPBwfmpN1rLih2Mpgn4KVaJky22t7JXJyVrNdGVmIA51slVbyFwFAE8Ww/0tkC+i2PUcWWRMIxtXP4iyq/9Npcq5VdqOatKfWHqAElLfKSPNMYLMlcyxyNpNx4paq8cL6fQxFcBLi9M2msz2i/qpKv30a0tzNo5bQQgucAXOQJB2Buks728upLuqsr+k25hwcqrtjyMOr9UQkt7qXAJH/0kimW7aW1yoMxbm/6mNG98X9D1EzNRewHAKatwJeFy1bw5qIuSQxPBwQMGloManrHOHGotmHKk7Y+dgM/z1UlaAdxSQuKWGXBc8QlQvif8puPYEdJMoInJNRxiWfYu06XnmzTXgMketK7RdULM9DVYzw8hzS2EIWKu8Oa0zn0PTevD2YeJNd4G8mDqO0vz5hloIc7pFsq/exQUB/kFozfCsnvhW8P+MPN0LpuSpptBQTsLWbM5BH0hd46HoWcneDdlMvVrUcgsTPmmSroIkLIEUo+Y2iN5eQHPPp85Cw=" + +before_install: + # JDK fix + - cat /etc/hosts # optionally check the content *before* + - sudo hostname "$(hostname | cut -c1-63)" + - sed -e "s/^\\(127\\.0\\.0\\.1.*\\)/\\1 $(hostname | cut -c1-63)/" /etc/hosts | sudo tee /etc/hosts + - cat /etc/hosts # optionally check the content *after* + - cd .. + + # Verilator + #- sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites + #- git clone http://git.veripool.org/git/verilator # Only first time + #- unset VERILATOR_ROOT # For bash + #- cd verilator + #- git pull # Make sure we're up-to-date + #- git checkout verilator_3_916 + #- autoconf # Create ./configure script + #- ./configure + #- make -j$(nproc) + #- sudo make install + #- cd .. + + - cd VexRiscv + - curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md + - curl -X POST -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/publish + - sbt compile + + +before_cache: + # Tricks to avoid unnecessary cache updates + - find $HOME/.ivy2 -name "ivydata-*.properties" -delete + - find $HOME/.sbt -name "*.lock" -delete + +cache: + directories: + - $HOME/.ivy2/cache + - $HOME/.sbt/boot/ diff --git a/README.md b/README.md index 1df8da0..7b75f86 100644 --- a/README.md +++ b/README.md @@ -19,27 +19,6 @@ - [CPU clock and resets](#cpu-clock-and-resets) - [VexRiscv Architecture](#vexriscv-architecture) * [Plugins](#plugins) - + [PcManagerSimplePlugin](#pcmanagersimpleplugin) - + [IBusSimplePlugin](#ibussimpleplugin) - + [IBusCachedPlugin](#ibuscachedplugin) - + [DecoderSimplePlugin](#decodersimpleplugin) - + [RegFilePlugin](#regfileplugin) - + [HazardSimplePlugin](#hazardsimpleplugin) - + [SrcPlugin](#srcplugin) - + [IntAluPlugin](#intaluplugin) - + [LightShifterPlugin](#lightshifterplugin) - + [FullBarrielShifterPlugin](#fullbarrielshifterplugin) - + [BranchPlugin](#branchplugin) - + [DBusSimplePlugin](#dbussimpleplugin) - + [DBusCachedPlugin](#dbuscachedplugin) - + [MulPlugin](#mulplugin) - + [DivPlugin](#divplugin) - + [MulDivIterativePlugin](#muldiviterativeplugin) - + [CsrPlugin](#csrplugin) - + [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) - + [MemoryTranslatorPlugin](#memorytranslatorplugin) - + [DebugPlugin](#debugplugin) - + [YamlPlugin](#yamlplugin) @@ -47,7 +26,7 @@ This repository host an RISC-V implementation written in SpinalHDL. There is some specs : -- RV32IM instruction set +- RV32I[M] instruction set - Pipelined on 5 stages (Fetch, Decode, Execute, Memory, WriteBack) - 1.44 DMIPS/Mhz when all features are enabled - Optimized for FPGA, fully portable @@ -60,6 +39,8 @@ This repository host an RISC-V implementation written in SpinalHDL. There is som - Two implementation of shift instructions, Single cycle / shiftNumber cycles - Each stage could have bypass or interlock hazard logic - FreeRTOS port https://github.com/Dolu1990/FreeRTOS-RISCV +- The data cache support atomic LR/SC +- RV32 compressed instruction are supported in the reworkFetch branch for configurations without instruction cache (will be merge in master, WIP) The hardware description of this CPU is done by using an very software oriented approach (without any overhead in the generated hardware). There is a list of software concepts used : @@ -86,21 +67,25 @@ VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass, no interrupt) -> Artix 7 -> 346 Mhz 481 LUT 539 FF Cyclone V -> 201 Mhz 347 ALMs Cyclone IV -> 190 Mhz 673 LUT 529 FF + iCE40 -> 81 Mhz 1130 LC VexRiscv smallest (RV32I, 0.52 DMIPS/Mhz, no datapath bypass) -> Artix 7 -> 340 Mhz 562 LUT 589 FF Cyclone V -> 202 Mhz 387 ALMs Cyclone IV -> 180 Mhz 780 LUT 579 FF + iCE40 -> 71 Mhz 1278 LC VexRiscv small and productive (RV32I, 0.82 DMIPS/Mhz) -> Artix 7 -> 327 Mhz 698 LUT 558 FF Cyclone V -> 158 Mhz 524 ALMs Cyclone IV -> 146 Mhz 1,061 LUT 552 FF - + iCE40 -> 55 Mhz 1541 LC + VexRiscv small and productive with I$ (RV32I, 0.72 DMIPS/Mhz, 4KB-I$) -> Artix 7 -> 331 Mhz 727 LUT 600 FF Cyclone V -> 152 Mhz 536 ALMs Cyclone IV -> 156 Mhz 1,075 LUT 565 FF + iCE40 -> 54 Mhz 1686 LC VexRiscv full no cache (RV32IM, 1.22 DMIPS/Mhz, single cycle barrel shifter, debug module, catch exceptions, static branch) -> Artix 7 -> 295 Mhz 1399 LUT 971 FF @@ -629,7 +614,29 @@ So again, if you generate the CPU without any plugin, it will only contain the 5 ### Plugins -This chapter (WIP) will describe plugins currently implemented +This chapter is describing plugins currently implemented. + +- [PcManagerSimplePlugin](#pcmanagersimpleplugin) +- [IBusSimplePlugin](#ibussimpleplugin) +- [IBusCachedPlugin](#ibuscachedplugin) +- [DecoderSimplePlugin](#decodersimpleplugin) +- [RegFilePlugin](#regfileplugin) +- [HazardSimplePlugin](#hazardsimpleplugin) +- [SrcPlugin](#srcplugin) +- [IntAluPlugin](#intaluplugin) +- [LightShifterPlugin](#lightshifterplugin) +- [FullBarrielShifterPlugin](#fullbarrielshifterplugin) +- [BranchPlugin](#branchplugin) +- [DBusSimplePlugin](#dbussimpleplugin) +- [DBusCachedPlugin](#dbuscachedplugin) +- [MulPlugin](#mulplugin) +- [DivPlugin](#divplugin) +- [MulDivIterativePlugin](#muldiviterativeplugin) +- [CsrPlugin](#csrplugin) +- [StaticMemoryTranslatorPlugin](#staticmemorytranslatorplugin) +- [MemoryTranslatorPlugin](#memorytranslatorplugin) +- [DebugPlugin](#debugplugin) +- [YamlPlugin](#yamlplugin) #### PcManagerSimplePlugin diff --git a/assets/brieySoc.png b/assets/brieySoc.png index b7d5fb4..77e2757 100644 Binary files a/assets/brieySoc.png and b/assets/brieySoc.png differ 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/spinal/lib/eda/icestorm/IcestormFlow.scala b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala new file mode 100644 index 0000000..08f0821 --- /dev/null +++ b/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala @@ -0,0 +1,195 @@ +package spinal.lib.eda.icestorm +import spinal.lib.eda._ +import spinal.lib.eda.bench.{Report, Rtl, Target} + +import scala.collection.mutable.ArrayBuffer +import java.io.File +import java.nio.file.Paths + +import org.apache.commons.io.FileUtils +import spinal.core._ +import spinal.lib.StreamFifo +import spinal.lib.eda.bench.Report + +import scala.sys.process._ + +object IcestormFlow { + def doCmd(cmd : Seq[String], path : String): String ={ + println(cmd) + val str = new StringBuilder() + val log = new ProcessLogger { + override def err(s: => String): Unit = { + str ++= s + stderr.println(s) + } + + override def out(s: => String): Unit = { + str ++= s + stdout.println(s) + } + + override def buffer[T](f: => T) = f + } + if(isWindows) + Process("cmd /C " + cmd, new java.io.File(path)) !(log) + else + Process.apply(cmd, new java.io.File(path)) !(log) + + return str.toString() + } + + val isWindows = System.getProperty("os.name").toLowerCase().contains("win") + + def apply(workspacePath : String,toplevelPath : String,family : String,device : String, pack : String) : Report = { + val projectName = toplevelPath.split("/").last.split("[.]").head + + + + val workspacePathFile = new File(workspacePath) + FileUtils.deleteDirectory(workspacePathFile) + workspacePathFile.mkdir() + FileUtils.copyFileToDirectory(new File(toplevelPath), workspacePathFile) + doCmd(List("yosys", "-v3", "-p", s"synth_ice40 -top $projectName -blif ${projectName}.blif", s"$projectName.v" ), workspacePath) + val arachne = doCmd(List("arachne-pnr", "-d", device.replace("hx","").replace("up",""), "--max-passes", "600", "-P", pack, s"$projectName.blif" ,"-o", s"$projectName.asc"), workspacePath) + doCmd(List("icepack", s"$projectName.asc", s"$projectName.bin"), workspacePath) + val icetime = doCmd(List("icetime", "-tmd", device, s"${projectName}.asc"), workspacePath) + new Report{ + val intFind = "(\\d+,?)+".r + val fMaxReg = """[-+]?(\d*[.])?\d+""".r + override def getFMax() = { + try { + fMaxReg.findAllMatchIn("Total path delay: [^\\n]* MHz".r.findFirstIn(icetime).get).drop(1).next.toString().toDouble * 1e6 + } catch { + case e : Throwable => -1 + } + } + override def getArea() = { + try { + intFind.findFirstIn("LCs[^\\n]*\\/".r.findFirstIn(arachne).get).get.toString() + " LC" + } catch { + case e : Throwable => "error" + } + } + } +// mkdir -p bin +// rm -f Murax.v*.bin +// cp ../../../Murax.v*.bin . | true +// yosys -v3 -p "synth_ice40 -top toplevel -blif bin/toplevel.blif" ${VERILOG} +// +// val isVhdl = toplevelPath.endsWith(".vhd") || toplevelPath.endsWith(".vhdl") +// +// val tcl = new java.io.FileWriter(Paths.get(workspacePath,"doit.tcl").toFile) +// tcl.write( +// s"""read_${if(isVhdl) "vhdl" else "verilog"} $toplevelPath +//read_xdc doit.xdc +// +//synth_design -part $device -top ${toplevelPath.split("\\.").head} +//opt_design +//place_design +//route_design +// +//report_utilization +//report_timing""" +// ) +// +// tcl.flush(); +// tcl.close(); +// +// +// val xdc = new java.io.FileWriter(Paths.get(workspacePath,"doit.xdc").toFile) +// xdc.write(s"""create_clock -period ${(targetPeriod*1e9) toBigDecimal} [get_ports clk]""") +// +// xdc.flush(); +// xdc.close(); +// +// doCmd(s"$vivadoPath/vivado -nojournal -log doit.log -mode batch -source doit.tcl", workspacePath) +// +// new Report{ +// override def getFMax(): Double = { +// import scala.io.Source +// val report = Source.fromFile(Paths.get(workspacePath,"doit.log").toFile).getLines.mkString +// val intFind = "-?(\\d+\\.?)+".r +// val slack = try { +// (family match { +// case "Artix 7" => +// intFind.findFirstIn("-?(\\d+.?)+ns \\(required time - arrival time\\)".r.findFirstIn(report).get).get +// }).toDouble +// }catch{ +// case e : Exception => -1.0 +// } +// return 1.0/(targetPeriod.toDouble-slack*1e-9) +// } +// override def getArea(): String = { +// import scala.io.Source +// val report = Source.fromFile(Paths.get(workspacePath,"doit.log").toFile).getLines.mkString +// val intFind = "(\\d+,?)+".r +// val leArea = try { +// family match { +// case "Artix 7" => +// intFind.findFirstIn("Slice LUTs[ ]*\\|[ ]*(\\d+,?)+".r.findFirstIn(report).get).get + " LUT " + +// intFind.findFirstIn("Slice Registers[ ]*\\|[ ]*(\\d+,?)+".r.findFirstIn(report).get).get + " FF " +// } +// }catch{ +// case e : Exception => "???" +// } +// return leArea +// } +// } + } + + def main(args: Array[String]) { +// SpinalVerilog(StreamFifo(Bits(8 bits), 64)) +// val report = IcestormFlow( +// workspacePath="/home/spinalvm/tmp", +// toplevelPath="StreamFifo.v", +// family="iCE40", +// device="hx8k", +// pack = "ct256" +// ) +// println(report.getArea()) +// println(report.getFMax()) +// } + SpinalVerilog(StreamFifo(Bits(8 bits), 64)) + val report = IcestormFlow( + workspacePath="/home/spinalvm/tmp", + toplevelPath="StreamFifo.v", + family="iCE40", + device="up5k", + pack = "sg48" + ) + println(report.getArea()) + println(report.getFMax()) + } +} + +object IcestormStdTargets { + def apply(): Seq[Target] = { + val targets = ArrayBuffer[Target]() + targets += new Target { + override def getFamilyName(): String = "iCE40" + override def synthesise(rtl: Rtl, workspace: String): Report = { + IcestormFlow( + workspacePath=workspace, + toplevelPath=rtl.getRtlPath(), + family=getFamilyName(), + device="hx8k", + pack = "ct256" + ) + } + } + + targets += new Target { + override def getFamilyName(): String = "iCE40Ultra" + override def synthesise(rtl: Rtl, workspace: String): Report = { + IcestormFlow( + workspacePath=workspace, + toplevelPath=rtl.getRtlPath(), + family=getFamilyName(), + device="up5k", + pack = "sg48" + ) + } + } + targets + } +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index 21841f0..451fdd9 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -391,6 +391,21 @@ object Briey{ } } +//DE1-SoC with memory init +object BrieyWithMemoryInit{ + def main(args: Array[String]) { + val config = SpinalConfig() + config.generateVerilog({ + val toplevel = new Briey(BrieyConfig.default) + toplevel.axi.vgaCtrl.vga.ctrl.io.error.addAttribute(Verilator.public) + toplevel.axi.vgaCtrl.vga.ctrl.io.frameStart.addAttribute(Verilator.public) + HexTools.initRam(toplevel.axi.ram.ram, "src/main/ressource/hex/muraxDemo.hex", 0x80000000l) + toplevel + }) + } +} + + //DE0-Nano object BrieyDe0Nano{ def main(args: Array[String]) { diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 6b71e65..80e0922 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -73,7 +73,45 @@ class MuraxMasterArbiter(simpleBusConfig : SimpleBusConfig) extends Component{ io.dBus.rsp.error := False } +object HexTools{ + def readHexFile(path : String, callback : (Int, Int) => Unit): Unit ={ + import scala.io.Source + def hToI(that : String, start : Int, size : Int) = Integer.parseInt(that.substring(start,start + size), 16) + var offset = 0 + for (line <- Source.fromFile(path).getLines) { + if (line.charAt(0) == ':'){ + val byteCount = hToI(line, 1, 2) + val nextAddr = hToI(line, 3, 4) + offset + val key = hToI(line, 7, 2) + key match { + case 0 => + for(i <- 0 until byteCount){ + callback(nextAddr + i, hToI(line, 9 + i * 2, 2)) + } + case 2 => + offset = hToI(line, 9, 4) << 4 + case 4 => + offset = hToI(line, 9, 4) << 16 + case 3 => + case 5 => + case 1 => + } + } + } + } + + + + def initRam[T <: Data](ram : Mem[T], onChipRamHexFile : String, ramOffset : BigInt): Unit ={ + val initContent = Array.fill[BigInt](ram.wordCount)(0) + HexTools.readHexFile(onChipRamHexFile,(address,data) => { + val addressWithoutOffset = (address - ramOffset).toInt + initContent(addressWithoutOffset >> 2) |= BigInt(data) << ((addressWithoutOffset & 3)*8) + }) + ram.initBigInt(initContent) + } +} class MuraxSimpleBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, simpleBusConfig : SimpleBusConfig) extends Component{ val io = new Bundle{ @@ -92,39 +130,7 @@ class MuraxSimpleBusRam(onChipRamSize : BigInt, onChipRamHexFile : String, simpl io.bus.cmd.ready := True if(onChipRamHexFile != null){ - def readHexFile(path : String, callback : (Int, Int) => Unit): Unit ={ - import scala.io.Source - def hToI(that : String, start : Int, size : Int) = Integer.parseInt(that.substring(start,start + size), 16) - - var offset = 0 - for (line <- Source.fromFile(path).getLines) { - if (line.charAt(0) == ':'){ - val byteCount = hToI(line, 1, 2) - val nextAddr = hToI(line, 3, 4) + offset - val key = hToI(line, 7, 2) - key match { - case 0 => - for(i <- 0 until byteCount){ - callback(nextAddr + i, hToI(line, 9 + i * 2, 2)) - } - case 2 => - offset = hToI(line, 9, 4) << 4 - case 4 => - offset = hToI(line, 9, 4) << 16 - case 3 => - case 5 => - case 1 => - } - } - } - } - - val initContent = Array.fill[BigInt](ram.wordCount)(0) - readHexFile(onChipRamHexFile,(address,data) => { - val addressWithoutOffset = address + Int.MinValue - initContent(addressWithoutOffset >> 2) |= BigInt(data) << ((addressWithoutOffset & 3)*8) - }) - ram.initBigInt(initContent) + HexTools.initRam(ram, onChipRamHexFile, 0x80000000l) } } diff --git a/src/main/scala/vexriscv/demo/SynthesisBench.scala b/src/main/scala/vexriscv/demo/SynthesisBench.scala index acf488f..c7d3448 100644 --- a/src/main/scala/vexriscv/demo/SynthesisBench.scala +++ b/src/main/scala/vexriscv/demo/SynthesisBench.scala @@ -2,8 +2,9 @@ package vexriscv.demo import spinal.core._ import spinal.lib.eda.bench._ +import spinal.lib.eda.icestorm.IcestormStdTargets import vexriscv.VexRiscv -import vexriscv.plugin.DecoderSimplePlugin +import vexriscv.plugin.{DecoderSimplePlugin, KeepAttribute} import scala.collection.mutable.ArrayBuffer @@ -14,6 +15,11 @@ object VexRiscvSynthesisBench { def main(args: Array[String]) { def wrap(that : => Component) : Component = that +// def wrap(that : => Component) : Component = { +// val c = that +// c.getAllIo.foreach(io => KeepAttribute(io.asDirectionLess())) +// c +// } // Wrap with input/output registers // def wrap(that : => Component) : Component = { // //new WrapWithReg.Wrapper(that) @@ -105,8 +111,9 @@ object VexRiscvSynthesisBench { ) ++ AlteraStdTargets( quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin", quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin" - ) + ) ++ IcestormStdTargets() +// val targets = IcestormStdTargets() Bench(rtls, targets, "/eda/tmp/") } } @@ -147,7 +154,7 @@ object MuraxSynthesisBench { override def getName(): String = "Murax" override def getRtlPath(): String = "Murax.v" SpinalVerilog({ - val murax = new Murax(MuraxConfig.default).setDefinitionName(getRtlPath().split("\\.").head) + val murax = new Murax(MuraxConfig.defsbault).setDefinitionName(getRtlPath().split("\\.").head) murax.io.mainClk.setName("clk") murax }) diff --git a/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala b/src/main/scala/vexriscv/demo/VexRiscvCachedWishboneForSim.scala new file mode 100644 index 0000000..c81814f --- /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_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( + prediction = STATIC, + 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 + ), + 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 dc58c95..3ce2a8b 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 = 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 } + + 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 + } } diff --git a/src/main/scala/vexriscv/ip/InstructionCache.scala b/src/main/scala/vexriscv/ip/InstructionCache.scala index 7892715..0f74e14 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, @@ -44,6 +45,20 @@ case class InstructionCacheConfig( cacheSize : Int, 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 + ) } @@ -162,6 +177,36 @@ 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)) 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 + } } diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 96abb1e..1c4e0b3 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -312,7 +312,8 @@ class CsrPlugin(config : CsrPluginConfig) extends Plugin[VexRiscv] with Exceptio val base = Reg(UInt(2 bits)) init(U"01") allowUnsetRegToAvoidLatch val extensions = Reg(Bits(26 bits)) init(misaExtensionsInit) allowUnsetRegToAvoidLatch } - val mtvec = RegInit(U(mtvecInit,xlen bits)) allowUnsetRegToAvoidLatch + val mtvec = Reg(UInt(xlen bits)).allowUnsetRegToAvoidLatch + if(mtvecInit != null) mtvec init(mtvecInit) val mepc = Reg(UInt(xlen bits)) val mstatus = new Area{ val MIE, MPIE = RegInit(False) diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index 1085c30..0547c69 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 @@ -214,7 +216,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)) + } } } 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) + } +} diff --git a/src/main/scala/vexriscv/plugin/Fetcher.scala b/src/main/scala/vexriscv/plugin/Fetcher.scala index 9550b9c..dfe5f54 100644 --- a/src/main/scala/vexriscv/plugin/Fetcher.scala +++ b/src/main/scala/vexriscv/plugin/Fetcher.scala @@ -22,6 +22,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, var prefetchExceptionPort : Flow[ExceptionCause] = null var decodePrediction : DecodePredictionBus = null var fetchPrediction : FetchPredictionBus = null + var externalResetVector : UInt = null assert(cmdToRspStageCount >= 1) assert(!(cmdToRspStageCount == 1 && !injectorStage)) assert(!(compressedGen && !decodePcGen)) @@ -58,6 +59,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, if(catchAccessFault) { val exceptionService = pipeline.service(classOf[ExceptionService]) } + if(resetVector == null) externalResetVector = in(UInt(32 bits).setName("externalResetVector")) pipeline(RVC_GEN) = compressedGen @@ -105,7 +107,8 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, val fetchPc = if(relaxedPcCalculation) new PcFetch { //PC calculation without Jump - val pcReg = Reg(UInt(32 bits)) init (resetVector) addAttribute (Verilator.public) + val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) + val pcPlus4 = pcReg + 4 if (keepPcPlus4) KeepAttribute(pcPlus4) when(preOutput.fire) { @@ -133,7 +136,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, preOutput.payload := pcReg } else new PcFetch{ //PC calculation without Jump - val pcReg = Reg(UInt(32 bits)) init(resetVector) addAttribute(Verilator.public) + val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) val inc = RegInit(False) val pc = pcReg + (inc ## B"00").asUInt @@ -178,7 +181,7 @@ abstract class IBusFetcherImpl(val catchAccessFault : Boolean, val decodePc = ifGen(decodePcGen)(new Area { //PC calculation without Jump - val pcReg = Reg(UInt(32 bits)) init (resetVector) addAttribute (Verilator.public) + val pcReg = Reg(UInt(32 bits)) init(if(resetVector != null) resetVector else externalResetVector) addAttribute(Verilator.public) val pcPlus = if(compressedGen) pcReg + ((decode.input(IS_RVC)) ? U(2) | U(4)) else diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 57e25c0..2ef79d6 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -442,8 +442,6 @@ public: top->eval(); - dump(i + 1); - if(top->VexRiscv->writeBack_arbitration_isFiring){ if(top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_valid == 1 && top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){ @@ -463,6 +461,8 @@ public: for(SimElement* simElement : simElements) simElement->preCycle(); + dump(i + 1); + #ifndef COMPRESSED if(withInstructionReadCheck){ if(top->VexRiscv->decode_arbitration_isValid && !top->VexRiscv->decode_arbitration_haltItself && !top->VexRiscv->decode_arbitration_flushAll){ @@ -713,6 +713,48 @@ 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) { + 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 class DBusSimple : public SimElement{ public: @@ -809,8 +851,47 @@ 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) { + 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 //#include "VVexRiscv_DataCache.h" @@ -1243,6 +1324,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 @@ -1255,6 +1339,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