Merge remote-tracking branch 'origin/master' into reworkFetcher
Conflicts: src/main/scala/vexriscv/plugin/PcManagerSimplePlugin.scala src/test/cpp/regression/main.cpp
This commit is contained in:
commit
9815763b7f
|
@ -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/
|
55
README.md
55
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
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 151 KiB |
|
@ -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,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
|
||||
}
|
||||
}
|
|
@ -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]) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 <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
|
||||
class DBusSimple : public SimElement{
|
||||
public:
|
||||
|
@ -809,8 +851,47 @@ public:
|
|||
};
|
||||
#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
|
||||
|
||||
//#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
|
||||
|
|
Loading…
Reference in New Issue