diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml new file mode 100644 index 0000000..2d4547f --- /dev/null +++ b/.github/workflows/scala.yml @@ -0,0 +1,69 @@ +name: Scala CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 120 + + steps: + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-v2 + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache SBT + uses: actions/cache@v2 + with: + path: | + ~/.ivy2/cache + ~/.sbt + key: ${{ runner.os }}-sbt-${{ hashFiles('**/build.sbt') }} + + - name: Cache tools + id: tools + uses: actions/cache@v2 + with: + path: | + ~/tools + key: ${{ runner.os }}-tools_v2 + + - name: Setup env + run: echo "$HOME/tools/bin" >> $GITHUB_PATH + + - name: Install cached tools + if: steps.tools.outputs.cache-hit != 'true' + run: source tools.sh && (cd ~/ && install_verilator) + + - name: Install uncached tools + run: (cd .. && git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev) + + - name: Compile tests + run: sbt "+test:compile" + + - name: Test Dhrystones + run: make regression_dhrystone -C scripts/regression + + - name: Test Baremetal + run: make regression_random_baremetal -C scripts/regression + + - name: Test Machine OS + run: make regression_random_machine_os -C scripts/regression + + - name: Test Linux + run: make regression_random_linux -C scripts/regression + diff --git a/README.md b/README.md index b61d682..8f2eb81 100644 --- a/README.md +++ b/README.md @@ -300,6 +300,7 @@ To create a new debug configuration: You can use the Eclipse + Zylin embedded CDT plugin to do it (http://opensource.zylin.com/embeddedcdt.html). Tested with Helios Service Release 2 (http://www.Eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/SR2/Eclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz) and the corresponding zylin plugin. To following commands will download Eclipse and install the plugin. + ```sh wget http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/SR2/eclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz tar -xvzf download.php?file=%2Ftechnology%2Fepp%2Fdownloads%2Frelease%2Fhelios%2FSR2%2Feclipse-cpp-helios-SR2-linux-gtk-x86_64.tar.gz @@ -311,6 +312,10 @@ See https://drive.google.com/drive/folders/1NseNHH05B6lmIXqQFVwK8xRjWE4ydeG-?usp Note that sometimes Eclipse needs to be restarted in order to be able to place new breakpoints. +If you want to get more information about how all this JTAG / GDB stuff work, you can find great blog about it here : + + + ## Briey SoC As a demonstration, a SoC named Briey is implemented in `src/main/scala/vexriscv/demo/Briey.scala`. This SoC is very similar to the [Pinsec SoC](https://spinalhdl.github.io/SpinalDoc-RTD/SpinalHDL/Legacy/pinsec/hardware_toplevel.html#): diff --git a/build.sbt b/build.sbt index 07ec182..733f5b8 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val spinalVersion = "1.5.0" +val spinalVersion = "1.6.0" lazy val root = (project in file(".")). settings( @@ -11,7 +11,7 @@ lazy val root = (project in file(".")). "com.github.spinalhdl" % "spinalhdl-core_2.11" % spinalVersion, "com.github.spinalhdl" % "spinalhdl-lib_2.11" % spinalVersion, compilerPlugin("com.github.spinalhdl" % "spinalhdl-idsl-plugin_2.11" % spinalVersion), - "org.scalatest" % "scalatest_2.11" % "2.2.1", + "org.scalatest" %% "scalatest" % "3.2.5", "org.yaml" % "snakeyaml" % "1.8" ), name := "VexRiscv" diff --git a/scripts/regression/regression.mk b/scripts/regression/regression.mk index 8e3fba8..89e760d 100644 --- a/scripts/regression/regression.mk +++ b/scripts/regression/regression.mk @@ -11,7 +11,7 @@ regression_random: regression_random_linux: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=3 + export VEXRISCV_REGRESSION_CONFIG_COUNT=2 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=1.0 export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 export VEXRISCV_REGRESSION_FREERTOS_COUNT=1 @@ -22,7 +22,7 @@ regression_random_linux: regression_random_machine_os: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=15 + export VEXRISCV_REGRESSION_CONFIG_COUNT=10 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=1.0 export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 @@ -33,7 +33,7 @@ regression_random_machine_os: regression_random_baremetal: cd ../.. - export VEXRISCV_REGRESSION_CONFIG_COUNT=40 + export VEXRISCV_REGRESSION_CONFIG_COUNT=30 export VEXRISCV_REGRESSION_CONFIG_LINUX_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE=0.0 export VEXRISCV_REGRESSION_CONFIG_SECURE_RATE=0.0 diff --git a/src/main/scala/vexriscv/demo/Briey.scala b/src/main/scala/vexriscv/demo/Briey.scala index dd794a6..76c688d 100644 --- a/src/main/scala/vexriscv/demo/Briey.scala +++ b/src/main/scala/vexriscv/demo/Briey.scala @@ -174,9 +174,9 @@ class Briey(config: BrieyConfig) extends Component{ val io = new Bundle{ //Clocks / reset - val asyncReset = in Bool - val axiClk = in Bool - val vgaClk = in Bool + val asyncReset = in Bool() + val axiClk = in Bool() + val vgaClk = in Bool() //Main components IO val jtag = slave(Jtag()) @@ -188,7 +188,7 @@ class Briey(config: BrieyConfig) extends Component{ val uart = master(Uart()) val vga = master(Vga(vgaRgbConfig)) val timerExternal = in(PinsecTimerCtrlExternal()) - val coreInterrupt = in Bool + val coreInterrupt = in Bool() } val resetCtrlClockDomain = ClockDomain( diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 82bceb3..05c8e00 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -157,8 +157,8 @@ case class Murax(config : MuraxConfig) extends Component{ val io = new Bundle { //Clocks / reset - val asyncReset = in Bool - val mainClk = in Bool + val asyncReset = in Bool() + val mainClk = in Bool() //Main components IO val jtag = slave(Jtag()) diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 1e22157..22bc438 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -142,7 +142,7 @@ class MuraxApb3Timer extends Component{ addressWidth = 8, dataWidth = 32 )) - val interrupt = out Bool + val interrupt = out Bool() } val prescaler = Prescaler(16) diff --git a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala index 03131c1..5aacc2b 100644 --- a/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala +++ b/src/main/scala/vexriscv/demo/smp/VexRiscvSmpCluster.scala @@ -167,6 +167,7 @@ object VexRiscvSmpClusterGen { dBusWidth : Int = 64, loadStoreWidth : Int = 32, coherency : Boolean = true, + atomic : Boolean = true, iCacheSize : Int = 8192, dCacheSize : Int = 8192, iCacheWays : Int = 2, @@ -193,6 +194,32 @@ object VexRiscvSmpClusterGen { assert(dCacheSize/dCacheWays <= 4096, "Data cache ways can't be bigger than 4096 bytes") assert(!(withDouble && !withFloat)) + val csrConfig = if(withSupervisor){ + CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY) + } else { + CsrPluginConfig( + catchIllegalAccess = true, + mvendorid = null, + marchid = null, + mimpid = null, + mhartid = 0, + misaExtensionsInit = 0, + misaAccess = CsrAccess.NONE, + mtvecAccess = CsrAccess.READ_WRITE, + mtvecInit = null, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = false, + mcauseAccess = CsrAccess.READ_ONLY, + mbadaddrAccess = CsrAccess.READ_ONLY, + mcycleAccess = CsrAccess.NONE, + minstretAccess = CsrAccess.NONE, + ecallGen = true, + ebreakGen = true, + wfiGenAsWait = false, + wfiGenAsNop = true, + ucycleAccess = CsrAccess.NONE + ) + } val config = VexRiscvConfig( plugins = List( if(withMmu)new MmuPlugin( @@ -245,9 +272,9 @@ object VexRiscvSmpClusterGen { catchAccessError = true, catchIllegal = true, catchUnaligned = true, - withLrSc = true, - withAmo = true, - withExclusive = coherency, + withLrSc = atomic, + withAmo = atomic, + withExclusive = atomic, withInvalidate = coherency, withWriteAggregation = dBusWidth > 32 ), @@ -290,7 +317,7 @@ object VexRiscvSmpClusterGen { mulUnrollFactor = 32, divUnrollFactor = 1 ), - new CsrPlugin(CsrPluginConfig.openSbi(mhartid = hartId, misa = Riscv.misaToInt(s"ima${if(withFloat) "f" else ""}${if(withDouble) "d" else ""}s")).copy(utimeAccess = CsrAccess.READ_ONLY)), + new CsrPlugin(csrConfig), new BranchPlugin( earlyBranch = earlyBranch, catchAddressMisaligned = true, diff --git a/src/test/scala/vexriscv/DhrystoneBench.scala b/src/test/scala/vexriscv/DhrystoneBench.scala index a98377c..48d1b67 100644 --- a/src/test/scala/vexriscv/DhrystoneBench.scala +++ b/src/test/scala/vexriscv/DhrystoneBench.scala @@ -2,13 +2,13 @@ package vexriscv import java.io.File -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import spinal.core.SpinalVerilog import vexriscv.demo._ import scala.sys.process._ -class DhrystoneBench extends FunSuite { +class DhrystoneBench extends AnyFunSuite { def doCmd(cmd: String): String = { val stdOut = new StringBuilder() class Logger extends ProcessLogger { diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 71c6697..bd5acb0 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -3,7 +3,9 @@ package vexriscv import java.io.{File, OutputStream} import java.util.concurrent.{ForkJoinPool, TimeUnit} import org.apache.commons.io.FileUtils -import org.scalatest.{BeforeAndAfterAll, FunSuite, ParallelTestExecution, Tag, Transformer} +import org.scalatest.{BeforeAndAfterAll, ParallelTestExecution, Tag, Transformer} +import org.scalatest.funsuite.AnyFunSuite + import spinal.core._ import spinal.lib.DoCmd import vexriscv.demo._ @@ -617,7 +619,7 @@ object PlayFuture extends App{ Thread.sleep(8000) } -class MultithreadedFunSuite(threadCount : Int) extends FunSuite { +class MultithreadedFunSuite(threadCount : Int) extends AnyFunSuite { val finalThreadCount = if(threadCount > 0) threadCount else { new oshi.SystemInfo().getHardware.getProcessor.getLogicalProcessorCount } @@ -650,7 +652,7 @@ class MultithreadedFunSuite(threadCount : Int) extends FunSuite { } } - override protected def test(testName: String, testTags: Tag*)(testFun: => Unit) { + def testMp(testName: String, testTags: Tag*)(testFun: => Unit) { val job = new Job(testFun) super.test(testName, testTags :_*)(job.join()) } @@ -662,7 +664,7 @@ class MultithreadedFunSuite(threadCount : Int) extends FunSuite { class FunTestPara extends MultithreadedFunSuite(3){ def createTest(name : String): Unit ={ - test(name){ + testMp(name){ for(i <- 0 to 4) { println(s"$name $i") Thread.sleep(500) @@ -745,7 +747,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE stdOut.toString() } - test(prefix + name) { + testMp(prefix + name) { println("START TEST " + prefix + name) //Cleanup @@ -787,7 +789,7 @@ class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VE val rand = new Random(seed) - test("Info"){ + testMp("Info"){ println(s"MAIN_SEED=$seed") } println(s"Seed=$seed") diff --git a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala index 280a5fe..11182ac 100644 --- a/src/test/scala/vexriscv/ip/fpu/FpuTest.scala +++ b/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -5,7 +5,7 @@ import java.lang import java.util.Scanner import org.apache.commons.io.FileUtils -import org.scalatest.FunSuite +import org.scalatest.funsuite.AnyFunSuite import spinal.core.SpinalEnumElement import spinal.core.sim._ import spinal.core._ @@ -18,9 +18,10 @@ import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import scala.sys.process.ProcessLogger import scala.util.Random +import org.scalatest.funsuite.AnyFunSuite //TODO Warning DataCache write aggregation will disable itself -class FpuTest extends FunSuite{ +class FpuTest extends AnyFunSuite{ val b2f = lang.Float.intBitsToFloat(_) val b2d = lang.Double.longBitsToDouble(_) diff --git a/tools.sh b/tools.sh new file mode 100644 index 0000000..ebe0592 --- /dev/null +++ b/tools.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +install_verilator(){ + sudo apt install -y git make autoconf g++ flex libfl-dev bison # 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 v4.040 + autoconf # Create ./configure script + ./configure --prefix ~/tools + make -j$(nproc) + make install + cd .. +} + +install_ghdl(){ + sudo apt install -y gnat-9 libgnat-9 zlib1g-dev libboost-dev + git clone https://github.com/ghdl/ghdl ghdl-build && cd ghdl-build + git reset --hard "0316f95368837dc163173e7ca52f37ecd8d3591d" + mkdir build + cd build + ../configure --prefix=~/tools + make -j$(nproc) + make install + cd .. +} + +install_iverilog(){ + sudo apt install -y gperf readline-common bison flex libfl-dev + curl -fsSL https://github.com/steveicarus/iverilog/archive/v10_3.tar.gz | tar -xvz + cd iverilog-10_3 + autoconf + ./configure --prefix ~/tools + make -j$(nproc) + make install + cd .. +} + +install_cocotb(){ + pip3 install --user cocotb + sudo apt install -y git make gcc g++ swig python3-dev +} + +purge_cocotb(){ + # Force cocotb to compile VPI to avoid race condition when tests are start in parallel + cd tester/src/test/python/spinal/Dummy + make TOPLEVEL_LANG=verilog + make TOPLEVEL_LANG=vhdl + cd ../../../../../.. +} + +install_packages(){ + sudo apt install -y gnat-9 libgnat-9 zlib1g-dev libboost-dev +} + +install_tools(){ + install_verilator + install_ghdl + install_iverilog + install_cocotb +} \ No newline at end of file