diff options
Diffstat (limited to 'VexRiscv/src/test/scala/vexriscv')
9 files changed, 3167 insertions, 0 deletions
diff --git a/VexRiscv/src/test/scala/vexriscv/DhrystoneBench.scala b/VexRiscv/src/test/scala/vexriscv/DhrystoneBench.scala new file mode 100644 index 0000000..48d1b67 --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/DhrystoneBench.scala @@ -0,0 +1,164 @@ +package vexriscv + +import java.io.File + +import org.scalatest.funsuite.AnyFunSuite +import spinal.core.SpinalVerilog +import vexriscv.demo._ + +import scala.sys.process._ + +class DhrystoneBench extends AnyFunSuite { + def doCmd(cmd: String): String = { + val stdOut = new StringBuilder() + class Logger extends ProcessLogger { + override def err(s: => String): Unit = { + if (!s.startsWith("ar: creating ")) println(s) + } + + override def out(s: => String): Unit = { + println(s) + stdOut ++= s + } + + override def buffer[T](f: => T) = f + } + Process(cmd, new File("src/test/cpp/regression")).!(new Logger) + stdOut.toString() + } + + val report = new StringBuilder() + + def getDmips(name: String, gen: => Unit, testCmd: String): Unit = { + var genPassed = false + test(name + "_gen") { + gen + genPassed = true + } + test(name + "_test") { + assert(genPassed) + val str = doCmd(testCmd) + assert(!str.contains("FAIL")) + val intFind = "(\\d+\\.?)+".r + val dmips = intFind.findFirstIn("DMIPS per Mhz\\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble + val coremarkTicks = intFind.findFirstIn("Total ticks \\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble + val coremarkIterations = intFind.findFirstIn("Iterations \\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble + val coremarkHzs = intFind.findFirstIn("DCLOCKS_PER_SEC=(\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble + val coremarkPerMhz = 1e6 * coremarkIterations / coremarkTicks + report ++= s"$name -> $dmips DMIPS/Mhz $coremarkPerMhz Coremark/Mhz\n" + } + + } + + for(withMemoryStage <- List(false, true)){ + val stages = if(withMemoryStage) "Three" else "Two" + getDmips( + name = s"Gen${stages}StageArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = false, + barrielShifter = false, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageBarrielArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = false, + bypass = true, + barrielShifter = true, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageMDArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = false, + barrielShifter = false, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + getDmips( + name = s"Gen${stages}StageMDBarrielArty", + gen = SpinalVerilog(GenTwoThreeStage.cpu( + withMulDiv = true, + bypass = true, + barrielShifter = true, + withMemoryStage = withMemoryStage + )), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=yes DIV=yes COREMARK=yes" + ) + } + + getDmips( + name = "GenSmallestNoCsr", + gen = GenSmallestNoCsr.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + + getDmips( + name = "GenSmallest", + gen = GenSmallest.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + + getDmips( + name = "GenSmallAndProductive", + gen = GenSmallAndProductive.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + getDmips( + name = "GenSmallAndProductiveWithICache", + gen = GenSmallAndProductiveICache.main(null), + testCmd = "make clean run REDO=10 IBUS=CACHED DBUS=SIMPLE CSR=no MMU=no DEBUG_PLUGIN=no MUL=no DIV=no COREMARK=yes" + ) + + + getDmips( + name = "GenFullNoMmuNoCache", + gen = GenFullNoMmuNoCache.main(null), + testCmd = "make clean run REDO=10 IBUS=SIMPLE DBUS=SIMPLE CSR=no MMU=no COREMARK=yes" + ) + + getDmips( + name = "GenNoCacheNoMmuMaxPerf", + gen = GenNoCacheNoMmuMaxPerf.main(null), + testCmd = "make clean run REDO=10 MMU=no CSR=no DBUS=SIMPLE IBUS=SIMPLE COREMARK=yes" + ) + + + getDmips( + name = "GenFullNoMmuMaxPerf", + gen = GenFullNoMmuMaxPerf.main(null), + testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" + ) + getDmips( + name = "GenFullNoMmu", + gen = GenFullNoMmu.main(null), + testCmd = "make clean run REDO=10 MMU=no CSR=no COREMARK=yes" + ) + + getDmips( + name = "GenFull", + gen = GenFull.main(null), + testCmd = "make clean run REDO=10 CSR=no MMU=no COREMARK=yes" + ) + + getDmips( + name = "GenLinuxBalenced", + gen = LinuxGen.main(Array.fill[String](0)("")), + testCmd = "make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=no CSR=yes CSR_SKIP_TEST=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=no" + ) + + + test("final_report") { + println(report) + } +} diff --git a/VexRiscv/src/test/scala/vexriscv/MuraxSim.scala b/VexRiscv/src/test/scala/vexriscv/MuraxSim.scala new file mode 100644 index 0000000..6a6a19c --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/MuraxSim.scala @@ -0,0 +1,110 @@ +package vexriscv + +import java.awt +import java.awt.event.{ActionEvent, ActionListener, MouseEvent, MouseListener} + +import spinal.sim._ +import spinal.core._ +import spinal.core.sim._ +import vexriscv.demo.{Murax, MuraxConfig} +import javax.swing._ + +import spinal.lib.com.jtag.sim.JtagTcp +import spinal.lib.com.uart.sim.{UartDecoder, UartEncoder} +import vexriscv.test.{JLedArray, JSwitchArray} + +import scala.collection.mutable + + + +object MuraxSim { + def main(args: Array[String]): Unit = { +// def config = MuraxConfig.default.copy(onChipRamSize = 256 kB) + def config = MuraxConfig.default(withXip = false).copy(onChipRamSize = 4 kB, onChipRamHexFile = "src/main/ressource/hex/muraxDemo.hex") + val simSlowDown = false + SimConfig.allOptimisation.compile(new Murax(config)).doSimUntilVoid{dut => + val mainClkPeriod = (1e12/dut.config.coreFrequency.toDouble).toLong + val jtagClkPeriod = mainClkPeriod*4 + val uartBaudRate = 115200 + val uartBaudPeriod = (1e12/uartBaudRate).toLong + + val clockDomain = ClockDomain(dut.io.mainClk, dut.io.asyncReset) + clockDomain.forkStimulus(mainClkPeriod) +// clockDomain.forkSimSpeedPrinter(2) + + val tcpJtag = JtagTcp( + jtag = dut.io.jtag, + jtagClkPeriod = jtagClkPeriod + ) + + val uartTx = UartDecoder( + uartPin = dut.io.uart.txd, + baudPeriod = uartBaudPeriod + ) + + val uartRx = UartEncoder( + uartPin = dut.io.uart.rxd, + baudPeriod = uartBaudPeriod + ) + + if(config.xipConfig != null)dut.io.xip.data(1).read #= 0 + + val guiThread = fork{ + val guiToSim = mutable.Queue[Any]() + + var ledsValue = 0l + var switchValue : () => BigInt = null + val ledsFrame = new JFrame{ + setLayout(new BoxLayout(getContentPane, BoxLayout.Y_AXIS)) + + add(new JLedArray(8){ + override def getValue = ledsValue + }) + add{ + val switches = new JSwitchArray(8) + switchValue = switches.getValue + switches + } + + add(new JButton("Reset"){ + addActionListener(new ActionListener { + override def actionPerformed(actionEvent: ActionEvent): Unit = { + println("ASYNC RESET") + guiToSim.enqueue("asyncReset") + } + }) + setAlignmentX(awt.Component.CENTER_ALIGNMENT) + }) + setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) + pack() + setVisible(true) + + } + + //Fast refresh +// clockDomain.onSampling{ +// dut.io.gpioA.read #= (dut.io.gpioA.write.toLong & dut.io.gpioA.writeEnable.toLong) | (switchValue() << 8) +// } + + //Slow refresh + while(true){ + sleep(mainClkPeriod*50000) + + val dummy = if(guiToSim.nonEmpty){ + val request = guiToSim.dequeue() + if(request == "asyncReset"){ + dut.io.asyncReset #= true + sleep(mainClkPeriod*32) + dut.io.asyncReset #= false + } + } + + dut.io.gpioA.read #= (dut.io.gpioA.write.toLong & dut.io.gpioA.writeEnable.toLong) | (switchValue() << 8) + ledsValue = dut.io.gpioA.write.toLong + ledsFrame.repaint() + if(simSlowDown) Thread.sleep(400) + } + } + } + } +} diff --git a/VexRiscv/src/test/scala/vexriscv/TestIndividualFeatures.scala b/VexRiscv/src/test/scala/vexriscv/TestIndividualFeatures.scala new file mode 100644 index 0000000..bd5acb0 --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -0,0 +1,875 @@ +package vexriscv + +import java.io.{File, OutputStream} +import java.util.concurrent.{ForkJoinPool, TimeUnit} +import org.apache.commons.io.FileUtils +import org.scalatest.{BeforeAndAfterAll, ParallelTestExecution, Tag, Transformer} +import org.scalatest.funsuite.AnyFunSuite + +import spinal.core._ +import spinal.lib.DoCmd +import vexriscv.demo._ +import vexriscv.ip.{DataCacheConfig, InstructionCacheConfig} +import vexriscv.plugin._ + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer +import scala.concurrent.duration.Duration +import scala.concurrent.{Await, ExecutionContext, Future} +import scala.sys.process._ +import scala.util.Random + + +abstract class ConfigUniverse + +abstract class ConfigDimension[T <: ConfigPosition[_]](val name: String) { + def randomPosition(universes : Seq[ConfigUniverse], r : Random) : T = { + val ret = randomPositionImpl(universes, r) + ret.dimension = this + ret + } + + protected def randomPositionImpl(universes : Seq[ConfigUniverse], r : Random) : T + protected def random[X](r : Random, positions : List[X]) : X = positions(r.nextInt(positions.length)) +} + +abstract class VexRiscvDimension(name: String) extends ConfigDimension[VexRiscvPosition](name) + +abstract class ConfigPosition[T](val name: String) { + def applyOn(config: T): Unit + var dimension : ConfigDimension[_] = null + def isCompatibleWith(positions : Seq[ConfigPosition[T]]) : Boolean = true +} + +abstract class VexRiscvPosition(name: String) extends ConfigPosition[VexRiscvConfig](name){ + def testParam : String = "" +} + +class VexRiscvUniverse extends ConfigUniverse + +object VexRiscvUniverse{ + val CACHE_ALL = new VexRiscvUniverse + val CATCH_ALL = new VexRiscvUniverse + val MMU = new VexRiscvUniverse + val PMP = new VexRiscvUniverse + val FORCE_MULDIV = new VexRiscvUniverse + val SUPERVISOR = new VexRiscvUniverse + val NO_WRITEBACK = new VexRiscvUniverse + val NO_MEMORY = new VexRiscvUniverse + val EXECUTE_RF = new VexRiscvUniverse +} + + +object Hack{ + var dCounter = 0 +} + +class ShiftDimension extends VexRiscvDimension("Shift") { + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + var l = List( + new VexRiscvPosition("FullEarly") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new FullBarrelShifterPlugin(earlyInjection = true) + }, + new VexRiscvPosition("Light") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new LightShifterPlugin + } + ) + + if(!universes.contains(VexRiscvUniverse.NO_MEMORY)) l = new VexRiscvPosition("FullLate") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new FullBarrelShifterPlugin(earlyInjection = false) + } :: l + + random(r, l) + } +} + +class BranchDimension extends VexRiscvDimension("Branch") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val early = r.nextBoolean() || universes.contains(VexRiscvUniverse.NO_MEMORY) + new VexRiscvPosition(if(early) "Early" else "Late") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new BranchPlugin( + earlyBranch = early, + catchAddressMisaligned = catchAll + ) + } + } +} + + + +class MulDivDimension extends VexRiscvDimension("MulDiv") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) + val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) + + var l = List[VexRiscvPosition]() + + + + l = new VexRiscvPosition("MulDivFpgaSimple") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulSimplePlugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + + if(!noMemory && !noWriteBack) l = new VexRiscvPosition("MulDivFpga16BitsDsp") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new Mul16Plugin + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + + if(!noMemory) { + l = new VexRiscvPosition("MulDivAsic") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 4 + ) + } + } :: new VexRiscvPosition("MulDivFpgaNoDsp") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 1, + divUnrollFactor = 1 + ) + } + } :: new VexRiscvPosition("MulDivFpgaNoDspFastMul") { + override def testParam = "MUL=yes DIV=yes" + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulDivIterativePlugin( + genMul = true, + genDiv = true, + mulUnrollFactor = 8, + divUnrollFactor = 1 + ) + } + } :: l + } + + if(!universes.contains(VexRiscvUniverse.FORCE_MULDIV)) l = new VexRiscvPosition("NoMulDiv") { + override def applyOn(config: VexRiscvConfig): Unit = {} + override def testParam = "MUL=no DIV=no" + } :: l + + + if(!noMemory && !noWriteBack) { + val inputBuffer = r.nextBoolean() + val outputBuffer = r.nextBoolean() + l = new VexRiscvPosition(s"MulDivFpga$inputBuffer$outputBuffer") { + override def testParam = "MUL=yes DIV=yes" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MulPlugin( + inputBuffer = inputBuffer, + outputBuffer = outputBuffer + ) + config.plugins += new MulDivIterativePlugin( + genMul = false, + genDiv = true, + mulUnrollFactor = 32, + divUnrollFactor = 1 + ) + } + } :: l + } + + random(r, l) + } +} + +trait InstructionAnticipatedPosition{ + def instructionAnticipatedOk() : Boolean +} + +class RegFileDimension extends VexRiscvDimension("RegFile") { + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val executeRf = universes.contains(VexRiscvUniverse.EXECUTE_RF) + random(r, List( + new VexRiscvPosition("Async" + (if(executeRf) "ER" else "DR")) { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new RegFilePlugin( + regFileReadyKind = plugin.ASYNC, + zeroBoot = true, + readInExecute = executeRf + ) + }, + new VexRiscvPosition("Sync" + (if(executeRf) "ER" else "DR")) { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = true, + readInExecute = executeRf + ) + + override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = executeRf || positions.exists{ + case p : InstructionAnticipatedPosition => p.instructionAnticipatedOk() + case _ => false + } + } + )) + } +} + + + +class HazardDimension extends VexRiscvDimension("Hazard") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) : VexRiscvPosition = { + if(r.nextDouble() < 0.8){ + random(r, List( + new VexRiscvPosition("Interlock") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ) + }, + new VexRiscvPosition("BypassAll") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = true, + bypassWriteBack = true, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ) + } + )) + }else { + random(r, List( + new VexRiscvPosition("BypassExecute") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new HazardSimplePlugin( + bypassExecute = true, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ) + }, + new VexRiscvPosition("BypassMemory") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = true, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ) + }, + new VexRiscvPosition("BypassWriteBack") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = true, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ) + }, + new VexRiscvPosition("BypassWriteBackBuffer") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = true, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ) + } + )) + } + }} + + +class SrcDimension extends VexRiscvDimension("Src") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val separatedAddSub = r.nextBoolean() + val executeInsertion = universes.contains(VexRiscvUniverse.EXECUTE_RF) || r.nextBoolean() + new VexRiscvPosition((if (separatedAddSub) "AddSub" else "") + (if (executeInsertion) "Execute" else "")) { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new SrcPlugin( + separatedAddSub = separatedAddSub, + executeInsertion = executeInsertion + ) + } + } +} + + +class IBusDimension(rvcRate : Double) extends VexRiscvDimension("IBus") { + + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL) + + if(r.nextDouble() < 0.5 && !cacheAll){ + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4) else null + + val latency = r.nextInt(5) + 1 + val compressed = r.nextDouble() < rvcRate + val injectorStage = r.nextBoolean() || latency == 1 + val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val cmdForkOnSecondStage = r.nextBoolean() + val cmdForkPersistence = r.nextBoolean() + new VexRiscvPosition("Simple" + latency + (if(cmdForkOnSecondStage) "S2" else "") + (if(cmdForkPersistence) "P" else "") + (if(injectorStage) "InjStage" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")) with InstructionAnticipatedPosition{ + override def testParam = "IBUS=SIMPLE" + (if(compressed) " COMPRESSED=yes" else "") + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = cmdForkOnSecondStage, + cmdForkPersistence = cmdForkPersistence, + prediction = prediction, + catchAccessFault = catchAll, + compressedGen = compressed, + busLatencyMin = latency, + injectorStage = injectorStage, + memoryTranslatorPortConfig = mmuConfig + ) + override def instructionAnticipatedOk() = injectorStage + } + } else { + val twoStageMmu = r.nextBoolean() + val asyncTagMemory = r.nextBoolean() + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig(portTlbSize = 4, latency = if(twoStageMmu) 1 else 0, earlyRequireMmuLockup = Random.nextBoolean() && twoStageMmu, earlyCacheHits = Random.nextBoolean() && twoStageMmu) else null + + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val compressed = r.nextDouble() < rvcRate + val tighlyCoupled = r.nextBoolean() && !catchAll + val reducedBankWidth = r.nextBoolean() +// val tighlyCoupled = false + val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) + val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() + val twoCycleRam = r.nextBoolean() && twoCycleCache + val twoCycleRamInnerMux = r.nextBoolean() && twoCycleRam + val memDataWidth = List(32,64,128)(r.nextInt(3)) + val bytePerLine = Math.max(memDataWidth/8, List(8,16,32,64)(r.nextInt(4))) + var cacheSize = 0 + var wayCount = 0 + do{ + cacheSize = 512 << r.nextInt(5) + wayCount = 1 << r.nextInt(3) + }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) + + new VexRiscvPosition(s"Cached${memDataWidth}d" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "") + (if(asyncTagMemory) "Atm" else "")) with InstructionAnticipatedPosition{ + override def testParam = s"IBUS=CACHED IBUS_DATA_WIDTH=$memDataWidth" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") + override def applyOn(config: VexRiscvConfig): Unit = { + val p = new IBusCachedPlugin( + resetVector = 0x80000000l, + compressedGen = compressed, + prediction = prediction, + relaxedPcCalculation = relaxedPcCalculation, + injectorStage = injectorStage, + memoryTranslatorPortConfig = mmuConfig, + config = InstructionCacheConfig( + cacheSize = cacheSize, + bytePerLine = bytePerLine, + wayCount = wayCount, + addressWidth = 32, + cpuDataWidth = 32, + memDataWidth = memDataWidth, + catchIllegalAccess = catchAll, + catchAccessFault = catchAll, + asyncTagMemory = asyncTagMemory, + twoCycleRam = twoCycleRam, + twoCycleCache = twoCycleCache, + twoCycleRamInnerMux = twoCycleRamInnerMux, + reducedBankWidth = reducedBankWidth + ) + ) + if(tighlyCoupled) p.newTightlyCoupledPort(TightlyCoupledPortParameter("iBusTc", a => a(30 downto 28) === 0x0)) + config.plugins += p + } + override def instructionAnticipatedOk() = !twoCycleCache || ((!twoCycleRam || wayCount == 1) && !compressed) + } + } + } +} + + + + +class DBusDimension extends VexRiscvDimension("DBus") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val cacheAll = universes.contains(VexRiscvUniverse.CACHE_ALL) + val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) + val noWriteBack = universes.contains(VexRiscvUniverse.NO_WRITEBACK) + + if((r.nextDouble() < 0.4 || noMemory) && !cacheAll){ + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig( portTlbSize = 4, latency = 0) else null + val withLrSc = catchAll + val earlyInjection = r.nextBoolean() && !universes.contains(VexRiscvUniverse.NO_WRITEBACK) + new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { + override def testParam = "DBUS=SIMPLE " + (if(withLrSc) "LRSC=yes " else "") + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DBusSimplePlugin( + catchAddressMisaligned = catchAll, + catchAccessFault = catchAll, + earlyInjection = earlyInjection, + memoryTranslatorPortConfig = mmuConfig, + withLrSc = withLrSc + ) +// override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) + } + } else { + val twoStageMmu = r.nextBoolean() && !noMemory && !noWriteBack + val mmuConfig = if(universes.contains(VexRiscvUniverse.MMU)) MmuPortConfig(portTlbSize = 4, latency = if(twoStageMmu) 1 else 0, earlyRequireMmuLockup = Random.nextBoolean() && twoStageMmu, earlyCacheHits = Random.nextBoolean() && twoStageMmu) else null + val memDataWidth = List(32,64,128)(r.nextInt(3)) + val cpuDataWidthChoices = List(32,64,128).filter(_ <= memDataWidth) + val cpuDataWidth = cpuDataWidthChoices(r.nextInt(cpuDataWidthChoices.size)) + val bytePerLine = Math.max(memDataWidth/8, List(8,16,32,64)(r.nextInt(4))) + var cacheSize = 0 + var wayCount = 0 + val withLrSc = catchAll + val withSmp = withLrSc && r.nextBoolean() + val withAmo = catchAll && r.nextBoolean() || withSmp + val dBusRspSlavePipe = r.nextBoolean() || withSmp + val relaxedMemoryTranslationRegister = r.nextBoolean() + val earlyWaysHits = r.nextBoolean() && !noWriteBack + val directTlbHit = r.nextBoolean() && mmuConfig.isInstanceOf[MmuPortConfig] + val dBusCmdMasterPipe, dBusCmdSlavePipe = false //As it create test bench issues + val asyncTagMemory = r.nextBoolean() + + do{ + cacheSize = 512 << r.nextInt(5) + wayCount = 1 << r.nextInt(3) + }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) + new VexRiscvPosition(s"Cached${memDataWidth}d${cpuDataWidth}c" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(dBusCmdMasterPipe) "Cmp " else "") + (if(dBusCmdSlavePipe) "Csp " else "") + (if(dBusRspSlavePipe) "Rsp " else "") + (if(relaxedMemoryTranslationRegister) "Rmtr " else "") + (if(earlyWaysHits) "Ewh " else "") + (if(withAmo) "Amo " else "") + (if(withSmp) "Smp " else "") + (if(directTlbHit) "Dtlb " else "") + (if(twoStageMmu) "Tsmmu " else "") + (if(asyncTagMemory) "Atm" else "")) { + override def testParam = s"DBUS=CACHED DBUS_LOAD_DATA_WIDTH=$memDataWidth DBUS_STORE_DATA_WIDTH=$cpuDataWidth " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") + (if(withSmp) "DBUS_EXCLUSIVE=yes DBUS_INVALIDATE=yes " else "") + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new DBusCachedPlugin( + config = new DataCacheConfig( + cacheSize = cacheSize, + bytePerLine = bytePerLine, + wayCount = wayCount, + addressWidth = 32, + cpuDataWidth = cpuDataWidth, //Not tested + memDataWidth = memDataWidth, + catchAccessError = catchAll, + catchIllegal = catchAll, + catchUnaligned = catchAll, + withLrSc = withLrSc, + withAmo = withAmo, + earlyWaysHits = earlyWaysHits, + withExclusive = withSmp, + withInvalidate = withSmp, + directTlbHit = directTlbHit, + asyncTagMemory = asyncTagMemory + ), + dBusCmdMasterPipe = dBusCmdMasterPipe, + dBusCmdSlavePipe = dBusCmdSlavePipe, + dBusRspSlavePipe = dBusRspSlavePipe, + relaxedMemoryTranslationRegister = relaxedMemoryTranslationRegister, + memoryTranslatorPortConfig = mmuConfig + ) + } + } + } + } +} + + +class MmuPmpDimension extends VexRiscvDimension("DBus") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + if(universes.contains(VexRiscvUniverse.MMU)) { + new VexRiscvPosition("WithMmu") { + override def testParam = "MMU=yes PMP=no" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new MmuPlugin( + ioRange = (x => x(31 downto 28) === 0xF) + ) + } + } + } else if (universes.contains(VexRiscvUniverse.PMP)) { + new VexRiscvPosition("WithPmp") { + override def testParam = "MMU=no PMP=yes" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new PmpPlugin( + regions = 16, + granularity = 32, + ioRange = _ (31 downto 28) === 0xF + ) + } + } + } else { + new VexRiscvPosition("NoMemProtect") { + override def testParam = "MMU=no PMP=no" + + override def applyOn(config: VexRiscvConfig): Unit = { + config.plugins += new StaticMemoryTranslatorPlugin( + ioRange = _ (31 downto 28) === 0xF + ) + } + } + } + } +} + + + +trait CatchAllPosition + + +class CsrDimension(freertos : String, zephyr : String, linux : String) extends VexRiscvDimension("Csr") { + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val pmp = universes.contains(VexRiscvUniverse.PMP) + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + val supervisor = universes.contains(VexRiscvUniverse.SUPERVISOR) + if(supervisor){ + new VexRiscvPosition("Supervisor") with CatchAllPosition{ + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) + override def testParam = s"FREERTOS=$freertos ZEPHYR=$zephyr LINUX_REGRESSION=$linux SUPERVISOR=yes" + } + } else if(pmp){ + new VexRiscvPosition("Secure") with CatchAllPosition{ + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.secure(0x80000020l)) + override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr" + } + } else if(catchAll){ + new VexRiscvPosition("MachineOs") with CatchAllPosition{ + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l)) + override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr" + } + } else if(r.nextDouble() < 0.3){ + new VexRiscvPosition("AllNoException") with CatchAllPosition{ + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.all(0x80000020l).noExceptionButEcall) + override def testParam = s"CSR=yes CSR_SKIP_TEST=yes FREERTOS=$freertos ZEPHYR=$zephyr" + } + } else { + new VexRiscvPosition("None") { + override def applyOn(config: VexRiscvConfig): Unit = {} + override def testParam = "CSR=no" + } + } + } +} + +class DebugDimension extends VexRiscvDimension("Debug") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = random(r, List( + new VexRiscvPosition("None") { + override def applyOn(config: VexRiscvConfig): Unit = {} + override def testParam = "DEBUG_PLUGIN=no" + }, + new VexRiscvPosition("Enable") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DebugPlugin(ClockDomain.current.clone(reset = Bool().setName("debugReset"))) + override def testParam = "CONCURRENT_OS_EXECUTIONS=yes" + } + )) +} + +class DecoderDimension extends VexRiscvDimension("Decoder") { + + override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) + new VexRiscvPosition("") { + override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DecoderSimplePlugin( + catchIllegalInstruction = catchAll, + throwIllegalInstruction = false + ) + +// override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) + } + } +} + +object PlayFuture extends App{ + implicit val ec = ExecutionContext.global + val x = for(i <- 0 until 160) yield Future { + print(s"$i ") + Thread.sleep(1000) + } + + Thread.sleep(8000) +} + +class MultithreadedFunSuite(threadCount : Int) extends AnyFunSuite { + val finalThreadCount = if(threadCount > 0) threadCount else { + new oshi.SystemInfo().getHardware.getProcessor.getLogicalProcessorCount + } + implicit val ec = ExecutionContext.fromExecutorService( + new ForkJoinPool(finalThreadCount, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) + ) + class Job(body : => Unit){ + val originalOutput = Console.out + val buffer = mutable.Queue[Char]() + var bufferEnabled = true + def redirector() = new OutputStream{ + override def write(i: Int): Unit = synchronized { + if(bufferEnabled) buffer += i.toChar + else originalOutput.print(i.toChar) + } + } + val future = Future{ + Console.withOut(redirector()){ + Console.withErr(redirector())(body) + } + } + + def join(): Unit = { + Thread.sleep(50) + synchronized{ + bufferEnabled = false + buffer.foreach(originalOutput.print) + } + Await.result(future, Duration.Inf) + } + } + + def testMp(testName: String, testTags: Tag*)(testFun: => Unit) { + val job = new Job(testFun) + super.test(testName, testTags :_*)(job.join()) + } + protected def testSingleThread(testName: String, testTags: Tag*)(testFun: => Unit) { + super.test(testName, testTags :_*)(testFun) + } +} + + +class FunTestPara extends MultithreadedFunSuite(3){ + def createTest(name : String): Unit ={ + testMp(name){ + for(i <- 0 to 4) { + println(s"$name $i") + Thread.sleep(500) + } + } + } + (0 to 80).map(_.toString).foreach(createTest) +} + +//class FunTestPlay extends FunSuite { +// def createTest(name : String): Unit ={ +// test(name){ +// Thread.sleep(500) +// for(i <- 0 to 4) { +// println(s"$name $i") +// Thread.sleep(500) +// } +// } +// } +// (0 to 80).map(_.toString).foreach(createTest) +//} + +class TestIndividualFeatures extends MultithreadedFunSuite(sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", "0").toInt) { + val testCount = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_COUNT", "100").toInt + val seed = sys.env.getOrElse("VEXRISCV_REGRESSION_SEED", Random.nextLong().toString).toLong + val testId : Set[Int] = sys.env.get("VEXRISCV_REGRESSION_TEST_ID") match { + case Some(x) if x != "" => x.split(',').map(_.toInt).toSet + case _ => (0 until testCount).toSet + } + val rvcRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_RVC_RATE", "0.5").toDouble + val linuxRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_LINUX_RATE", "0.3").toDouble + val machineOsRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_MACHINE_OS_RATE", "0.5").toDouble + val secureRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_SECURE_RATE", "0.2").toDouble + val linuxRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_LINUX_REGRESSION", "yes") + val coremarkRegression = sys.env.getOrElse("VEXRISCV_REGRESSION_COREMARK", "yes") + val zephyrCount = sys.env.getOrElse("VEXRISCV_REGRESSION_ZEPHYR_COUNT", "4") + val demwRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEMW_RATE", "0.6").toDouble + val demRate = sys.env.getOrElse("VEXRISCV_REGRESSION_CONFIG_DEM_RATE", "0.5").toDouble + val stopOnError = sys.env.getOrElse("VEXRISCV_REGRESSION_STOP_ON_ERROR", "no") + val lock = new{} + + + + val dimensions = List( + new IBusDimension(rvcRate), + new DBusDimension, + new MulDivDimension, + new ShiftDimension, + new BranchDimension, + new HazardDimension, + new RegFileDimension, + new SrcDimension, + new CsrDimension(/*sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "1")*/ "0", zephyrCount, linuxRegression), //Freertos old port software is broken + new DecoderDimension, + new DebugDimension, + new MmuPmpDimension + ) + + var clockCounter = 0l + var startAt = System.currentTimeMillis() + def doTest(positionsToApply : List[VexRiscvPosition], prefix : String = "", testSeed : Int, universes : mutable.HashSet[VexRiscvUniverse]): Unit ={ + val noMemory = universes.contains(VexRiscvUniverse.NO_MEMORY) + val noWriteback = universes.contains(VexRiscvUniverse.NO_WRITEBACK) + val name = (if(noMemory) "noMemoryStage_" else "") + (if(noWriteback) "noWritebackStage_" else "") + positionsToApply.map(d => d.dimension.name + "_" + d.name).mkString("_") + val workspace = "simWorkspace" + val project = s"$workspace/$prefix" + def doCmd(cmd: String): String = { + val stdOut = new StringBuilder() + class Logger extends ProcessLogger { + override def err(s: => String): Unit = { + if (!s.startsWith("ar: creating ")) println(s) + } + override def out(s: => String): Unit = { + println(s) + stdOut ++= s + } + override def buffer[T](f: => T) = f + } + Process(cmd, new File(project)).!(new Logger) + stdOut.toString() + } + + testMp(prefix + name) { + println("START TEST " + prefix + name) + + //Cleanup + FileUtils.deleteDirectory(new File(project)) + FileUtils.forceMkdir(new File(project)) + + //Generate RTL + FileUtils.deleteQuietly(new File("VexRiscv.v")) + SpinalConfig(targetDirectory = project).generateVerilog{ + val config = VexRiscvConfig( + withMemoryStage = !noMemory, + withWriteBackStage = !noWriteback, + plugins = List( + new IntAluPlugin, + new YamlPlugin("cpu0.yaml") + ) + ) + for (positionToApply <- positionsToApply) positionToApply.applyOn(config) + new VexRiscv(config) + } + + //Setup test + val files = List("main.cpp", "encoding.h" ,"makefile", "dhrystoneO3.logRef", "dhrystoneO3C.logRef","dhrystoneO3MC.logRef","dhrystoneO3M.logRef") + files.foreach(f => FileUtils.copyFileToDirectory(new File(s"src/test/cpp/regression/$f"), new File(project))) + + //Test RTL + val debug = true + val stdCmd = (s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=$stopOnError DHRYSTONE=yes COREMARK=${coremarkRegression} THREAD_COUNT=1 ") + s" SEED=${testSeed} " + val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") + println(testCmd) + val str = doCmd(testCmd) + assert(str.contains("REGRESSION SUCCESS") && !str.contains("Broken pipe")) + val pattern = "Had simulate ([0-9]+)".r + val hit = pattern.findFirstMatchIn(str) + + lock.synchronized(clockCounter += hit.get.group(1).toLong) + } + } + + val rand = new Random(seed) + + testMp("Info"){ + println(s"MAIN_SEED=$seed") + } + println(s"Seed=$seed") + for(i <- 0 until testCount){ + var positions : List[VexRiscvPosition] = null + var universe = mutable.HashSet[VexRiscvUniverse]() + if(rand.nextDouble() < 0.5) universe += VexRiscvUniverse.EXECUTE_RF + if(linuxRate > rand.nextDouble()) { + universe += VexRiscvUniverse.CATCH_ALL + universe += VexRiscvUniverse.MMU + universe += VexRiscvUniverse.FORCE_MULDIV + universe += VexRiscvUniverse.SUPERVISOR + if(demwRate < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } + } else if (secureRate > rand.nextDouble()) { + universe += VexRiscvUniverse.CACHE_ALL + universe += VexRiscvUniverse.CATCH_ALL + universe += VexRiscvUniverse.PMP + if(demwRate < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } + } else { + if(machineOsRate > rand.nextDouble()) { + universe += VexRiscvUniverse.CATCH_ALL + if(demwRate < rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } + } + if(demwRate > rand.nextDouble()){ + }else if(demRate > rand.nextDouble()){ + universe += VexRiscvUniverse.NO_WRITEBACK + } else { + universe += VexRiscvUniverse.NO_WRITEBACK + universe += VexRiscvUniverse.NO_MEMORY + } + } + + do{ + positions = dimensions.map(d => d.randomPosition(universe.toList, rand)) + }while(!positions.forall(_.isCompatibleWith(positions))) + + val testSeed = rand.nextInt() + if(testId.contains(i)) + doTest(positions,"test_id_" + i + "_", testSeed, universe) + Hack.dCounter += 1 + } + testSingleThread("report"){ + val time = (System.currentTimeMillis() - startAt)*1e-3 + val clockPerSecond = (clockCounter/time*1e-3).toLong + println(s"Duration=${(time/60).toInt}mn clocks=${(clockCounter*1e-6).toLong}M clockPerSecond=${clockPerSecond}K") + } +} + + +object TestIndividualExplore extends App{ + val seeds = mutable.HashSet[Int]() + val futures = mutable.ArrayBuffer[Future[Unit]]() + implicit val ec = ExecutionContext.fromExecutorService( + new ForkJoinPool(24, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) + ) + for(i <- 0 until 1000){ + val seed = Random.nextInt(1000000) + 1 + futures += Future { + if (!seeds.contains(seed)) { +// val cmd = s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=1 TRACE=yes TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=mo THREAD_COUNT=1 IBUS=CACHED IBUS_DATA_WIDTH=128 COMPRESSED=yes DBUS=SIMPLE LRSC=yes MUL=yes DIV=yes FREERTOS=0 ZEPHYR=0 LINUX_REGRESSION=no SUPERVISOR=yes CONCURRENT_OS_EXECUTIONS=yes MMU=yes PMP=no SEED=$seed" + val cmd = s"make run REGRESSION_PATH=../../src/test/cpp/regression VEXRISCV_FILE=VexRiscv.v WITH_USER_IO=no REDO=10 TRACE=yes TRACE_START=100000000000ll FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=1 IBUS=CACHED IBUS_DATA_WIDTH=128 COMPRESSED=yes DBUS=SIMPLE LRSC=yes MUL=yes DIV=yes FREERTOS=0 ZEPHYR=2 LINUX_REGRESSION=yes SUPERVISOR=yes CONCURRENT_OS_EXECUTIONS=yes MMU=yes PMP=no SEED=$seed" + val workspace = s"explor/seed_$seed" + FileUtils.copyDirectory(new File("simWorkspace/ref"), new File(workspace)) + val str = DoCmd.doCmdWithLog(cmd, workspace) + if(!str.contains("REGRESSION SUCCESS")){ + println(s"seed $seed FAILED with\n\n$str") + sys.exit(1) + } + FileUtils.deleteDirectory(new File(workspace)) + println(s"seed $seed PASSED") + } + } + } + + futures.foreach(Await.result(_, Duration.Inf)) + +}
\ No newline at end of file diff --git a/VexRiscv/src/test/scala/vexriscv/experimental/Experiments.scala b/VexRiscv/src/test/scala/vexriscv/experimental/Experiments.scala new file mode 100644 index 0000000..1fead21 --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/experimental/Experiments.scala @@ -0,0 +1,34 @@ +package vexriscv.experimental + +import spinal.core._ + +class Stageable[T <: Data](val dataType : T) extends HardType[T](dataType) with Nameable{ + setWeakName(this.getClass.getSimpleName.replace("$","")) +} + +trait Stage{ + def read[T <: Data](stageable : Stageable[T]) : T + def write[T <: Data](stageable : Stageable[T], value : T, cond : Bool = null) : Unit + + def haltBySelf : Bool //user settable, stuck the instruction, should only be set by the instruction itself + def haltByOthers : Bool //When settable, stuck the instruction, should only be set by something else than the stucked instruction + def removeIt : Bool //When settable, unschedule the instruction as if it was never executed (no side effect) + def flushAll : Bool //When settable, unschedule instructions in the current stage and all prior ones + + def isValid : Bool //Inform if a instruction is in the current stage + def isStuck : Bool //Inform if the instruction is stuck (haltItself || haltByOther) + def isStuckByOthers: Bool //Inform if the instruction is stuck by sombody else + def isRemoved : Bool //Inform if the instruction is going to be unschedule the current cycle + def isFlushed : Bool //Inform if the instruction is flushed (flushAll set in the current or subsequents stages) + def isFiring : Bool //Inform if the current instruction will go to the next stage the next cycle (isValid && !isStuck && !removeIt) +} + +abstract class UnusedStage extends Stage +abstract class AsyncStage extends Stage +abstract class CycleStage extends Stage +abstract class SyncStage extends Stage +abstract class CutStage extends Stage + +abstract class PipelineStd{ + val prefetch, fetch, decode, execute, memory, writeback = 0 +}
\ No newline at end of file diff --git a/VexRiscv/src/test/scala/vexriscv/experimental/GenMicro.scala b/VexRiscv/src/test/scala/vexriscv/experimental/GenMicro.scala new file mode 100644 index 0000000..90666a7 --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/experimental/GenMicro.scala @@ -0,0 +1,162 @@ +package vexriscv.experimental + +import spinal.core._ +import spinal.lib.eda.bench.{AlteraStdTargets, Bench, Rtl, XilinxStdTargets} +import spinal.lib.eda.icestorm.IcestormStdTargets +import vexriscv.demo.{GenSmallestNoCsr, Murax, MuraxConfig} +import vexriscv.plugin._ +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} + +/** + * Created by spinalvm on 15.06.17. + */ +object GenMicro extends App{ + def cpu() = { + val removeOneFetchStage = true + val pessimisticHazard = true + val writeBackOpt = true + val rspHoldValue = true + val withCompliantCsr = true + val withCompliantCsrPlusEmulation = true + val earlyBranch = false + val noShifter = false + val onlyLoadWords = false + new VexRiscv( + config = VexRiscvConfig( + plugins = List( + // new PcManagerSimplePlugin( + // resetVector = 0x00000000l, + // relaxedPcCalculation = false + // ), + + new IBusSimplePlugin( + resetVector = 0x80000000l, + cmdForkOnSecondStage = false, + cmdForkPersistence = false, + prediction = NONE, + catchAccessFault = false, + compressedGen = false, + injectorStage = !removeOneFetchStage, + rspHoldValue = rspHoldValue + ), + new DBusSimplePlugin( + catchAddressMisaligned = withCompliantCsr, + catchAccessFault = false, + earlyInjection = writeBackOpt, + onlyLoadWords = onlyLoadWords + ), + new DecoderSimplePlugin( + catchIllegalInstruction = withCompliantCsrPlusEmulation + ), + new RegFilePlugin( + regFileReadyKind = plugin.SYNC, + zeroBoot = false, + readInExecute = removeOneFetchStage, + writeRfInMemoryStage = writeBackOpt + ), + new IntAluPlugin, + new SrcPlugin( + separatedAddSub = false, + executeInsertion = removeOneFetchStage + ), + if(!pessimisticHazard) + new HazardSimplePlugin( + bypassExecute = false, + bypassMemory = false, + bypassWriteBack = false, + bypassWriteBackBuffer = false, + pessimisticUseSrc = false, + pessimisticWriteRegFile = false, + pessimisticAddressMatch = false + ) + else + new HazardPessimisticPlugin(), + new BranchPlugin( + earlyBranch = earlyBranch, + catchAddressMisaligned = withCompliantCsr, + fenceiGenAsAJump = withCompliantCsr + ), + new YamlPlugin("cpu0.yaml") + ) ++ (if(noShifter) Nil else List(new LightShifterPlugin)) + ++ (if(!withCompliantCsr) Nil else List(new CsrPlugin( + config = if(withCompliantCsrPlusEmulation)CsrPluginConfig( + catchIllegalAccess = true, + mvendorid = null, + marchid = null, + mimpid = null, + mhartid = null, + misaExtensionsInit = 0, + misaAccess = CsrAccess.NONE, + mtvecAccess = CsrAccess.NONE, + mtvecInit = 0x80000020l, + mepcAccess = CsrAccess.NONE, + mscratchGen = false, + mcauseAccess = CsrAccess.READ_ONLY, + mbadaddrAccess = CsrAccess.NONE, + mcycleAccess = CsrAccess.NONE, + minstretAccess = CsrAccess.NONE, + ecallGen = false, + ebreakGen = false, + wfiGenAsWait = false, + wfiGenAsNop = false, + ucycleAccess = CsrAccess.NONE, + noCsrAlu = true + ) else CsrPluginConfig( + catchIllegalAccess = false, + mvendorid = null, + marchid = null, + mimpid = null, + mhartid = null, + misaExtensionsInit = 0, + misaAccess = CsrAccess.READ_ONLY, + mtvecAccess = CsrAccess.WRITE_ONLY, + mtvecInit = 0x80000020l, + mepcAccess = CsrAccess.READ_WRITE, + mscratchGen = true, + 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 + ) + ))) + ) + ) + } + SpinalConfig(mergeAsyncProcess = false).generateVerilog(cpu()) +} + + + +object GenMicroSynthesis { + def main(args: Array[String]) { + val microNoCsr = new Rtl { + override def getName(): String = "MicroNoCsr" + override def getRtlPath(): String = "MicroNoCsr.v" + SpinalVerilog(GenMicro.cpu().setDefinitionName(getRtlPath().split("\\.").head)) + } + + val smallestNoCsr = new Rtl { + override def getName(): String = "SmallestNoCsr" + override def getRtlPath(): String = "SmallestNoCsr.v" + SpinalVerilog(GenSmallestNoCsr.cpu().setDefinitionName(getRtlPath().split("\\.").head)) + } + + val rtls = List(microNoCsr) +// val rtls = List(smallestNoCsr) + + val targets = IcestormStdTargets().take(1) ++ XilinxStdTargets( + vivadoArtix7Path = "/eda/Xilinx/Vivado/2017.2/bin" + ) ++ AlteraStdTargets( + quartusCycloneIVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/", + quartusCycloneVPath = "/eda/intelFPGA_lite/17.0/quartus/bin/" + ) + + + Bench(rtls, targets, "/eda/tmp/") + } +}
\ No newline at end of file diff --git a/VexRiscv/src/test/scala/vexriscv/experimental/PlicCost.scala b/VexRiscv/src/test/scala/vexriscv/experimental/PlicCost.scala new file mode 100644 index 0000000..79d5c66 --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/experimental/PlicCost.scala @@ -0,0 +1,76 @@ +package vexriscv.experimental + +import spinal.core._ +import spinal.lib._ +import spinal.lib.bus.amba3.apb._ +import spinal.lib.eda.bench.{Bench, Rtl, XilinxStdTargets} +import spinal.lib.eda.icestorm.IcestormStdTargets +import spinal.lib.misc.plic._ +import vexriscv.VexRiscv +import vexriscv.demo.LinuxGen + +import scala.collection.mutable.ArrayBuffer + +class PlicBench(inputCount : Int) extends Component{ + val io = new Bundle { + val apb = slave(Apb3(addressWidth = 16, dataWidth = 32)) + val interrupts = in Bits(inputCount bits) + val cpuInterrupt = out Bool() + } + + + val priorityWidth = 1 + val gateways = ArrayBuffer[PlicGateway]() + + for(i <- 0 until inputCount) { + gateways += PlicGatewayActiveHigh( + source = io.interrupts(i), + id = 1 + i, + priorityWidth = priorityWidth + ) + } + + + val targets = Seq( + PlicTarget( + gateways = gateways, + priorityWidth = priorityWidth + ) + ) + io.cpuInterrupt := targets(0).iep + + val plicMapping = PlicMapping.light.copy( +// gatewayPriorityReadGen = true, +// gatewayPendingReadGen = true, +// targetThresholdReadGen = true + ) + + gateways.foreach(_.priority := 1) + targets.foreach(_.threshold := 0) + // targets.foreach(_.ie.foreach(_ := True)) + + val bus = Apb3SlaveFactory(io.apb) + val mapping = PlicMapper(bus, plicMapping)( + gateways = gateways, + targets = targets + ) +} + + +object PlicCost extends App{ + def rtlGen(inputCount : Int) = new Rtl { + override def getName(): String = s"PlicBench$inputCount" + override def getRtlPath(): String = s"PlicBench$inputCount.v" + SpinalVerilog(new PlicBench(inputCount).setDefinitionName(getRtlPath().split("\\.").head)) + } + + val rtls = List(8, 12, 16, 32).map(rtlGen) + // val rtls = List(smallestNoCsr, smallest, smallAndProductive, smallAndProductiveWithICache) + // val rtls = List(smallAndProductive, smallAndProductiveWithICache, fullNoMmuMaxPerf, fullNoMmu, full) + // val rtls = List(fullNoMmu) + + val targets = IcestormStdTargets().take(1) + + + Bench(rtls, targets, "/eda/tmp") +} diff --git a/VexRiscv/src/test/scala/vexriscv/experimental/config.scala b/VexRiscv/src/test/scala/vexriscv/experimental/config.scala new file mode 100644 index 0000000..d6eca55 --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/experimental/config.scala @@ -0,0 +1,36 @@ +package vexriscv.experimental + +import spinal.core.SpinalVerilog +import vexriscv.ip.InstructionCacheConfig +import vexriscv.{VexRiscv, VexRiscvConfig, plugin} +import vexriscv.plugin._ + +import scala.collection.mutable.ArrayBuffer + +object Presentation extends App{ + + val config = VexRiscvConfig() + + config.plugins ++= List( +// new IBusSimplePlugin(resetVector = 0x80000000l), + new DBusSimplePlugin, + new CsrPlugin(CsrPluginConfig.smallest), + new DecoderSimplePlugin, + new RegFilePlugin(regFileReadyKind = plugin.SYNC), + new IntAluPlugin, + new SrcPlugin, + new MulDivIterativePlugin( + mulUnrollFactor = 4, + divUnrollFactor = 1 + ), + new FullBarrelShifterPlugin, + new HazardSimplePlugin, + new BranchPlugin( + earlyBranch = false + ), + new YamlPlugin("cpu0.yaml") + ) + + new VexRiscv(config) +} + diff --git a/VexRiscv/src/test/scala/vexriscv/ip/fpu/FpuTest.scala b/VexRiscv/src/test/scala/vexriscv/ip/fpu/FpuTest.scala new file mode 100644 index 0000000..11182ac --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/ip/fpu/FpuTest.scala @@ -0,0 +1,1663 @@ +package vexriscv.ip.fpu + +import java.io.File +import java.lang +import java.util.Scanner + +import org.apache.commons.io.FileUtils +import org.scalatest.funsuite.AnyFunSuite +import spinal.core.SpinalEnumElement +import spinal.core.sim._ +import spinal.core._ +import spinal.lib.DoCmd +import spinal.lib.experimental.math.Floating +import spinal.lib.sim._ +import spinal.sim.Backend.{isMac, isWindows} + +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 AnyFunSuite{ + + val b2f = lang.Float.intBitsToFloat(_) + val b2d = lang.Double.longBitsToDouble(_) + val f2b = lang.Float.floatToRawIntBits(_) + val d2bOffset = BigInt("10000000000000000",16) + def d2b(that : Double) = { + val l = lang.Double.doubleToRawLongBits(that) + var a = BigInt(l) + if(l < 0) { + a = d2bOffset + a + } + a + } + + + test("f32f64") { + val p = FpuParameter( + withDouble = true, +// withAdd = false, +// withMul = false, +// withDivSqrt = false, + sim = true + ) + testP(p) + } + test("f32") { + val p = FpuParameter( + withDouble = false, + sim = true + ) + testP(p) + } + + def testP(p : FpuParameter){ + val portCount = 4 + + val config = SimConfig + config.allOptimisation +// config.withFstWave + config.compile(new FpuCore(portCount, p){ + for(i <- 0 until portCount) out(Bits(5 bits)).setName(s"flagAcc$i") := io.port(i).completion.flags.asBits + setDefinitionName("FpuCore"+ (if(p.withDouble) "Double" else "")) + }).doSim(seed = 42){ dut => + dut.clockDomain.forkStimulus(10) + dut.clockDomain.forkSimSpeedPrinter(5.0) + + + class TestCase(op : String){ + def build(arg : String) = new ProcessStream(s"testfloat_gen $arg -tininessafter -forever -$op"){ + def f32_f32_f32 ={ + val s = new Scanner(next) + val a,b,c = (s.nextLong(16).toInt) + (b2f(a), b2f(b), b2f(c), s.nextInt(16)) + } + + def i32_f32 ={ + val s = new Scanner(next) + (s.nextLong(16).toInt, b2f(s.nextLong(16).toInt), s.nextInt(16)) + } + + def f32_i32 = { + val s = new Scanner(next) + (b2f(s.nextLong(16).toInt), s.nextLong(16).toInt, s.nextInt(16)) + } + + def f32_f32_i32 = { + val s = new Scanner(next) + val a,b,c = (s.nextLong(16).toInt) + (b2f(a), b2f(b), c, s.nextInt(16)) + } + + def f32_f32 = { + val s = new Scanner(next) + val a,b = (s.nextLong(16).toInt) + (b2f(a), b2f(b), s.nextInt(16)) + } + + + def nextLong(s : Scanner) : Long = java.lang.Long.parseUnsignedLong( s.next(),16) + + def f64_f64_f64 ={ + val s = new Scanner(next) + val a,b,c = nextLong(s) + (b2d(a), b2d(b), b2d(c), s.nextInt(16)) + } + + def i32_f64 ={ + val s = new Scanner(next) + (s.nextLong(16).toInt, b2d(nextLong(s)), s.nextInt(16)) + } + + def f64_i32 = { + val s = new Scanner(next) + (b2d(nextLong(s)), s.nextLong(16).toInt, s.nextInt(16)) + } + + def f64_f64_i32 = { + val str = next + val s = new Scanner(str) + val a,b = (nextLong(s)) + (b2d(a), b2d(b), s.nextInt(16), s.nextInt(16)) + } + + def f64_f64 = { + val s = new Scanner(next) + val a,b = nextLong(s) + (b2d(a), b2d(b), s.nextInt(16)) + } + + + def f32_f64_i32 = { + val s = new Scanner(next) + val a,b = nextLong(s) + (b2f(a.toInt), b2d(b), s.nextInt(16)) + } + def f64_f32_i32 = { + val s = new Scanner(next) + val a,b = nextLong(s) + (b2d(a), b2f(b.toInt), s.nextInt(16)) + } + } + lazy val RAW = build("") + lazy val RNE = build("-rnear_even") + lazy val RTZ = build("-rminMag") + lazy val RDN = build("-rmin") + lazy val RUP = build("-rmax") + lazy val RMM = build("-rnear_maxMag") + lazy val all = List(RNE, RTZ, RDN, RUP, RMM, RAW) + def kill = all.foreach(_.kill) + def apply(rounding : FpuRoundMode.E) = rounding match { + case FpuRoundMode.RNE => RNE + case FpuRoundMode.RTZ => RTZ + case FpuRoundMode.RDN => RDN + case FpuRoundMode.RUP => RUP + case FpuRoundMode.RMM => RMM + } + } + + class TestVector(f : String) { + val add = new TestCase(s"${f}_add") + val sub = new TestCase(s"${f}_sub") + val mul = new TestCase(s"${f}_mul") + val ui2f = new TestCase(s"ui32_to_${f}") + val i2f = new TestCase(s"i32_to_${f}") + val f2ui = new TestCase(s"${f}_to_ui32 -exact") + val f2i = new TestCase(s"${f}_to_i32 -exact") + val eq = new TestCase(s"${f}_eq") + val lt = new TestCase(s"${f}_lt") + val le = new TestCase(s"${f}_le") + val min = new TestCase(s"${f}_le") + val max = new TestCase(s"${f}_lt") + val transfer = new TestCase(s"${f}_eq") + val fclass = new TestCase(s"${f}_eq") + val sgnj = new TestCase(s"${f}_eq") + val sgnjn = new TestCase(s"${f}_eq") + val sgnjx = new TestCase(s"${f}_eq") + val sqrt = new TestCase(s"${f}_sqrt") + val div = new TestCase(s"${f}_div") + } + + val f32 = new TestVector("f32"){ + val f64 = new TestCase(s"f32_eq") + val cvt64 = new TestCase(s"f32_to_f64") + } + val f64 = new TestVector("f64"){ + val f32 = new TestCase(s"f64_eq") + val cvt32 = new TestCase(s"f64_to_f32") + } + + val cpus = for(id <- 0 until portCount) yield new { + val cmdQueue = mutable.Queue[FpuCmd => Unit]() + val commitQueue = mutable.Queue[FpuCommit => Unit]() + val rspQueue = mutable.Queue[FpuRsp => Unit]() + + var pendingMiaou = 0 + var flagAccumulator = 0 + + def cmdAdd(body : FpuCmd => Unit): Unit ={ + pendingMiaou += 1 + cmdQueue += body + } + + def softAssert(cond : Boolean, msg : String) = if(!cond)println(msg) + def flagMatch(ref : Int, value : Float, report : String): Unit ={ + val patch = if(value.abs == 1.17549435E-38f && false) 0x1f & ~2 else 0x1f + flagMatch(ref, report, patch) + } + + def flagMatch(ref : Int, value : Double, report : String): Unit ={ + val patch = if(value.abs == b2d(1 << 52) && false) 0x1f & ~2 else 0x1f + flagMatch(ref, report, patch) + } + + def flagMatch(ref : Int, report : String, mask : Int = 0x1f): Unit ={ + waitUntil(pendingMiaou == 0) + assert((flagAccumulator & mask) == (ref & mask), s"Flag missmatch dut=$flagAccumulator ref=$ref $report") + flagAccumulator = 0 + } + def flagClear(): Unit ={ + waitUntil(pendingMiaou == 0) + flagAccumulator = 0 + } + + val flagAggregated = dut.reflectBaseType(s"flagAcc$id").asInstanceOf[Bits] + dut.clockDomain.onSamplings{ + val c = dut.io.port(id).completion + if(c.valid.toBoolean) { + pendingMiaou -= 1 + flagAccumulator |= flagAggregated.toInt + } + dut.writeback.randomSim.randomize() + } + + StreamDriver(dut.io.port(id).cmd ,dut.clockDomain){payload => + if(cmdQueue.isEmpty) false else { + cmdQueue.dequeue().apply(payload) + true + } + } + + + StreamMonitor(dut.io.port(id)rsp, dut.clockDomain){payload => + pendingMiaou -= 1 + if(payload.NV.toBoolean) flagAccumulator |= 1 << 4 + if(payload.NX.toBoolean) flagAccumulator |= 1 << 0 + rspQueue.dequeue().apply(payload) + } + + StreamReadyRandomizer(dut.io.port(id).rsp, dut.clockDomain) + + + StreamDriver(dut.io.port(id).commit ,dut.clockDomain){payload => + if(commitQueue.isEmpty) false else { + commitQueue.dequeue().apply(payload) + true + } + } + + + + + def loadRaw(rd : Int, value : BigInt, format : FpuFormat.E): Unit ={ + cmdAdd {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.LOAD + cmd.rs1.randomize() + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd #= rd + cmd.arg.randomize() + cmd.roundMode.randomize() + cmd.format #= format + } + commitQueue += {cmd => + cmd.write #= true + cmd.rd #= rd + cmd.value #= value + cmd.opcode #= cmd.opcode.spinalEnum.LOAD + } + } + + + def load(rd : Int, value : Float): Unit ={ + loadRaw(rd, f2b(value).toLong & 0xFFFFFFFFl, FpuFormat.FLOAT) + } + + def load(rd : Int, value : Double): Unit ={ + loadRaw(rd, d2b(value), FpuFormat.DOUBLE) + } + + def storeRaw(rs : Int, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ + cmdAdd {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.STORE + cmd.rs1.randomize() + cmd.rs2 #= rs + cmd.rs3.randomize() + cmd.rd.randomize() + cmd.arg.randomize() + cmd.roundMode.randomize() + cmd.format #= format + } + + rspQueue += body +// waitUntil(rspQueue.isEmpty) + } + + def storeFloat(rs : Int)(body : Float => Unit): Unit ={ + storeRaw(rs, FpuFormat.FLOAT){rsp => body(b2f(rsp.value.toBigInt.toInt))} + } + def store(rs : Int)(body : Double => Unit): Unit ={ + storeRaw(rs, FpuFormat.DOUBLE){rsp => body(b2d(rsp.value.toBigInt.toLong))} + } + + def fpuF2f(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ + cmdAdd {cmd => + cmd.opcode #= opcode + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3 #= rs3 + cmd.rd #= rd + cmd.arg #= arg + cmd.roundMode #= rounding + cmd.format #= format + } + commitQueue += {cmd => + cmd.write #= true + cmd.rd #= rd + cmd.opcode #= opcode + } + } + + def fpuF2i(rs1 : Int, rs2 : Int, opcode : FpuOpcode.E, arg : Int, rounding : FpuRoundMode.E, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ + cmdAdd {cmd => + cmd.opcode #= opcode + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd.randomize() + cmd.arg #= arg + cmd.roundMode #= rounding + cmd.format #= format + } + rspQueue += body + } + + + def mul(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.MUL, 0, rounding, format) + } + + def add(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 0, rounding, format) + } + + def sub(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.ADD, 1, rounding, format) + } + + def div(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.DIV, Random.nextInt(4), rounding, format) + } + + def sqrt(rd : Int, rs1 : Int, rounding : FpuRoundMode.E = FpuRoundMode.RNE, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, Random.nextInt(32), Random.nextInt(32), FpuOpcode.SQRT, Random.nextInt(4), rounding, format) + } + + def fma(rd : Int, rs1 : Int, rs2 : Int, rs3 : Int, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, rs3, FpuOpcode.FMA, 0, rounding, format) + } + + def sgnjRaw(rd : Int, rs1 : Int, rs2 : Int, arg : Int, format : FpuFormat.E): Unit ={ + fpuF2f(rd, rs1, rs2, Random.nextInt(32), FpuOpcode.SGNJ, arg, FpuRoundMode.elements.randomPick(), format) + } + + def sgnj(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null, format : FpuFormat.E): Unit ={ + sgnjRaw(rd, rs1, rs2, 0, format) + } + def sgnjn(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null, format : FpuFormat.E): Unit ={ + sgnjRaw(rd, rs1, rs2, 1, format) + } + def sgnjx(rd : Int, rs1 : Int, rs2 : Int, rounding : FpuRoundMode.E = null, format : FpuFormat.E): Unit ={ + sgnjRaw(rd, rs1, rs2, 2, format) + } + + def cmp(rs1 : Int, rs2 : Int, arg : Int, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ + fpuF2i(rs1, rs2, FpuOpcode.CMP, arg, FpuRoundMode.elements.randomPick(), format)(body) + } + + def f2i(rs1 : Int, signed : Boolean, rounding : FpuRoundMode.E, format : FpuFormat.E)(body : FpuRsp => Unit): Unit ={ + fpuF2i(rs1, Random.nextInt(32), FpuOpcode.F2I, if(signed) 1 else 0, rounding, format)(body) + } + + def i2f(rd : Int, value : Int, signed : Boolean, rounding : FpuRoundMode.E, format : FpuFormat.E): Unit ={ + cmdAdd {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.I2F + cmd.rs1.randomize() + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd #= rd + cmd.arg #= (if(signed) 1 else 0) + cmd.roundMode #= rounding + cmd.format #= format + } + commitQueue += {cmd => + cmd.write #= true + cmd.rd #= rd + cmd.opcode #= FpuOpcode.I2F + cmd.value #= value.toLong & 0xFFFFFFFFl + } + } + + def fmv_x_w(rs1 : Int)(body : Float => Unit): Unit ={ + cmdAdd {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.FMV_X_W + cmd.rs1 #= rs1 + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd.randomize() + cmd.arg #= 0 + cmd.roundMode.randomize() + cmd.format #= FpuFormat.FLOAT + } + rspQueue += {rsp => body(b2f(rsp.value.toBigInt.toInt))} + } + + def fmv_w_x(rd : Int, value : Int): Unit ={ + cmdAdd {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.FMV_W_X + cmd.rs1.randomize() + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd #= rd + cmd.arg #= 0 + cmd.roundMode.randomize() + cmd.format #= FpuFormat.FLOAT + } + commitQueue += {cmd => + cmd.write #= true + cmd.rd #= rd + cmd.opcode #= FpuOpcode.FMV_W_X + cmd.value #= value.toLong & 0xFFFFFFFFl + } + } + + def minMax(rd : Int, rs1 : Int, rs2 : Int, arg : Int, format : FpuFormat.E): Unit ={ + cmdAdd {cmd => + cmd.opcode #= cmd.opcode.spinalEnum.MIN_MAX + cmd.rs1 #= rs1 + cmd.rs2 #= rs2 + cmd.rs3.randomize() + cmd.rd #= rd + cmd.arg #= arg + cmd.roundMode.randomize() + cmd.format #= format + } + commitQueue += {cmd => + cmd.write #= true + cmd.rd #= rd + cmd.opcode #= FpuOpcode.MIN_MAX + } + } + + + + def fclass(rs1 : Int, format : FpuFormat.E)(body : Int => Unit) : Unit = { + cmdAdd {cmd => + cmd.opcode #= FpuOpcode.FCLASS + cmd.rs1 #= rs1 + cmd.rs2.randomize() + cmd.rs3.randomize() + cmd.rd.randomize() + cmd.arg.randomize() + cmd.roundMode.randomize() + cmd.format #= format + } + rspQueue += {rsp => body(rsp.value.toBigInt.toInt)} + } + } + + + + + + val stim = for(cpu <- cpus) yield fork { + import cpu._ + + class RegAllocator(){ + var value = 0 + + def allocate(): Int ={ + while(true){ + val rand = Random.nextInt(32) + val mask = 1 << rand + if((value & mask) == 0) { + value |= mask + return rand + } + } + 0 + } + } + def checkFloat(ref : Float, dut : Float): Boolean ={ + if((f2b(ref) & 0x80000000) != (f2b(dut) & 0x80000000)) return false + if(ref == 0.0 && dut == 0.0 && f2b(ref) != f2b(dut)) return false + if(ref.isNaN && dut.isNaN) return true + if(ref == dut) return true + if(ref.abs * 1.0001f + Float.MinPositiveValue >= dut.abs*0.9999f && ref.abs * 0.9999f - Float.MinPositiveValue <= dut.abs*1.0001f) return true +// if(ref + Float.MinPositiveValue*2.0f === dut || dut + Float.MinPositiveValue*2.0f === ref) + false + } + + def checkDouble(ref : Double, dut : Double): Boolean ={ + if((d2b(ref) & Long.MinValue) != (d2b(dut) & Long.MinValue)) return false + if(ref == 0.0 && dut == 0.0 && d2b(ref) != d2b(dut)) return false + if(ref.isNaN && dut.isNaN) return true + if(ref == dut) return true + if(ref.abs * 1.0001 + Float.MinPositiveValue >= dut.abs*0.9999 && ref.abs * 0.9999 - Double.MinPositiveValue <= dut.abs*1.0001) return true + // if(ref + Float.MinPositiveValue*2.0f === dut || dut + Float.MinPositiveValue*2.0f === ref) + false + } + def checkFloatExact(ref : Float, dut : Float): Boolean ={ + if(ref.signum != dut.signum === dut) return false + if(ref.isNaN && dut.isNaN) return true + if(ref == dut) return true + false + } + + + def randomFloat(): Float ={ + val exp = Random.nextInt(10)-5 + (Random.nextDouble() * (Math.pow(2.0, exp)) * (if(Random.nextBoolean()) -1.0 else 1.0)).toFloat + } + + def randomDouble(): Double ={ + val exp = Random.nextInt(10)-5 + (Random.nextDouble() * (Math.pow(2.0, exp)) * (if(Random.nextBoolean()) -1.0 else 1.0)) + } + + + def testBinaryOp(op : (Int,Int,Int,FpuRoundMode.E, FpuFormat.E) => Unit, a : Float, b : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + op(rd,rs1,rs2, rounding, FpuFormat.FLOAT) + storeFloat(rd){v => + assert(f2b(v) == f2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding") + } + + flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") + } + + + def testBinaryOpF64(op : (Int,Int,Int,FpuRoundMode.E, FpuFormat.E) => Unit, a : Double, b : Double, ref : Double, flag : Int, rounding : FpuRoundMode.E, opName : String): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + op(rd,rs1,rs2, rounding, FpuFormat.DOUBLE) + store(rd){v => + assert(d2b(v) == d2b(ref), f"## ${a} ${opName} $b = $v, $ref $rounding, ${d2b(a).toString(16)} ${d2b(b).toString(16)} ${d2b(ref).toString(16)}") + } + + flagMatch(flag, ref, f"## ${opName} ${a} $b $ref $rounding") + } + + + def testTransferF32Raw(a : Float, iSrc : Boolean, iDst : Boolean): Unit ={ + val rd = Random.nextInt(32) + + def handle(v : Float): Unit ={ + val ref = a + assert(f2b(v) == f2b(ref), f"$a = $v, $ref") + } + + if(iSrc) fmv_w_x(rd, f2b(a)) else load(rd, a) + if(iDst) fmv_x_w(rd)(handle) else storeFloat(rd)(handle) + + flagMatch(0, f"$a") + } + + + def testTransferF64Raw(a : Double): Unit ={ + val rd = Random.nextInt(32) + + def handle(v : Double): Unit ={ + val ref = a + assert(d2b(v) == d2b(ref), f"$a = $v, $ref") + } + + load(rd, a) + store(rd)(handle) + + flagMatch(0, f"$a") + } + + def testTransferF32F64Raw(a : Float, iSrc : Boolean): Unit ={ + val rd = Random.nextInt(32) + if(iSrc) fmv_w_x(rd, f2b(a)) else load(rd, a) + storeRaw(rd, FpuFormat.DOUBLE){rsp => + val v = rsp.value.toBigInt.toLong + val ref = (0xFFFFFFFFl << 32) | f2b(a) + assert(v == ref, f"$a = $v, $ref") + } + flagMatch(0, f"$a") + } + + def testTransferF64F32Raw(a : Double, iDst : Boolean): Unit ={ + val rd = Random.nextInt(32) + load(rd, a) + if(iDst)fmv_x_w(rd){v_ => + val v = f2b(v_).toLong & 0xFFFFFFFFl + val ref = d2b(a) & 0xFFFFFFFFl + assert(v == ref, f"$a = $v, $ref") + } + else storeRaw(rd, FpuFormat.FLOAT){rsp => + val v = rsp.value.toBigInt.toLong & 0xFFFFFFFFl + val ref = d2b(a) & 0xFFFFFFFFl + assert(v == ref, f"$a = $v, $ref") + } + flagMatch(0, f"$a") + } + + + def testCvtF32F64Raw(a : Float, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs, rd = Random.nextInt(32) + load(rs, a) + fpuF2f(rd, rs, Random.nextInt(32), Random.nextInt(32), FpuOpcode.FCVT_X_X, Random.nextInt(3), rounding, FpuFormat.FLOAT) + store(rd){v => + assert(d2b(v) == d2b(ref), f"testCvtF32F64Raw $a $ref $rounding") + } + flagMatch(flag,ref, f"testCvtF32F64Raw $a $ref $rounding") + } + + def testCvtF64F32Raw(a : Double, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs, rd = Random.nextInt(32) + load(rs, a) + fpuF2f(rd, rs, Random.nextInt(32), Random.nextInt(32), FpuOpcode.FCVT_X_X, Random.nextInt(3), rounding, FpuFormat.DOUBLE) + storeFloat(rd){v => + assert(d2b(v) == d2b(ref), f"testCvtF64F32Raw $a $ref $rounding") + } + flagMatch(flag, ref, f"testCvtF64F32Raw $a $ref $rounding") + } + + + def testClassRaw(a : Float) : Unit = { + val rd = Random.nextInt(32) + + + load(rd, a) + fclass(rd, FpuFormat.FLOAT){v => + val mantissa = f2b(a) & 0x7FFFFF + val exp = (f2b(a) >> 23) & 0xFF + val sign = (f2b(a) >> 31) & 0x1 + + val refBit = if(a.isInfinite) (if(sign == 0) 7 else 0) + else if(a.isNaN) (if((mantissa >> 22) != 0) 9 else 8) + else if(exp == 0 && mantissa != 0) (if(sign == 0) 5 else 2) + else if(exp == 0 && mantissa == 0) (if(sign == 0) 4 else 3) + else if(sign == 0) 6 else 1 + + val ref = 1 << refBit + + assert(v == ref, f"fclass $a") + } + } + + + def testClassF64Raw(a : Double) : Unit = { + val rd = Random.nextInt(32) + + + load(rd, a) + fclass(rd, FpuFormat.DOUBLE){v => + val mantissa = d2b(a) & 0x000FFFFFFFFFFFFFl + val exp = (d2b(a) >> 52) & 0x7FF + val sign = (d2b(a) >> 63) & 0x1 + + val refBit = if(a.isInfinite) (if(sign == 0) 7 else 0) + else if(a.isNaN) (if((mantissa >> 51) != 0) 9 else 8) + else if(exp == 0 && mantissa != 0) (if(sign == 0) 5 else 2) + else if(exp == 0 && mantissa == 0) (if(sign == 0) 4 else 3) + else if(sign == 0) 6 else 1 + + val ref = 1 << refBit + + assert(v == ref, f"fclass $a") + } + } + + + + def testFmaRaw(a : Float, b : Float, c : Float): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + load(rs3, c) + + fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.FLOAT) + storeFloat(rd){v => + val ref = a.toDouble * b.toDouble + c.toDouble + val mul = a.toDouble * b.toDouble + if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkFloat(ref.toFloat, v), f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") + } + } + + + + def testFmaF64Raw(a : Double, b : Double, c : Double): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + load(rs3, c) + + fma(rd,rs1,rs2,rs3, FpuRoundMode.RNE, FpuFormat.DOUBLE) + store(rd){v => + val ref = a.toDouble * b.toDouble + c.toDouble + val mul = a.toDouble * b.toDouble + if((mul.abs-c.abs)/mul.abs > 0.1) assert(checkDouble(ref, v), f"$a%.20f * $b%.20f + $c%.20f = $v%.20f, $ref%.20f") + } + } + + def testSqrtF64Exact(a : Double, ref : Double, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + + sqrt(rd,rs1, rounding, FpuFormat.DOUBLE) + + store(rd){v => + assert(d2b(v) == d2b(ref), f"## sqrt${a} = $v, $ref $rounding, ${d2b(a).toString(16)} ${d2b(ref).toString(16)}") + } + + flagMatch(flag, ref, f"## sqrt${a} $ref $rounding") + } + + def testSqrtExact(a : Float, ref : Float, flag : Int, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + + sqrt(rd,rs1, rounding, FpuFormat.FLOAT) + + storeFloat(rd){v => + assert(d2b(v) == d2b(ref), f"## sqrt${a} = $v, $ref $rounding, ${f2b(a).toString()} ${f2b(ref).toString()}") + } + + flagMatch(flag, ref, f"## sqrt${a} $ref $rounding") + } + + + def testF2iExact(a : Float, ref : Int, flag : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + f2i(rs1, signed, rounding, FpuFormat.FLOAT){rsp => + if(signed) { + val v = rsp.value.toBigInt.toInt + var ref2 = ref + if(a >= Int.MaxValue) ref2 = Int.MaxValue + if(a <= Int.MinValue) ref2 = Int.MinValue + if(a.isNaN) ref2 = Int.MaxValue + assert(v == (ref2), f" <= f2i($a) = $v, $ref2, $rounding, $flag") + } else { + val v = rsp.value.toBigInt.toLong & 0xFFFFFFFFl + var ref2 = ref.toLong & 0xFFFFFFFFl + if(a < 0) ref2 = 0 + if(a >= 0xFFFFFFFFl) ref2 = 0xFFFFFFFFl + if(a.isNaN) ref2 = 0xFFFFFFFFl + assert(v == ref2, f" <= f2ui($a) = $v, $ref2, $rounding $flag") + } + } + + flagMatch(flag, ref, f" f2${if(signed) "" else "u"}i($a) $ref $flag $rounding") + } + + + + def testF642iExact(a : Double, ref : Int, flag : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rs1 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + f2i(rs1, signed, rounding, FpuFormat.DOUBLE){rsp => + if(signed) { + val v = rsp.value.toBigInt.toInt + var ref2 = ref + if(a >= Int.MaxValue) ref2 = Int.MaxValue + if(a <= Int.MinValue) ref2 = Int.MinValue + if(a.isNaN) ref2 = Int.MaxValue + assert(v == (ref2), f" <= f2i($a) = $v, $ref2, $rounding, $flag") + } else { + val v = rsp.value.toBigInt.toLong & 0xFFFFFFFFl + var ref2 = ref.toLong & 0xFFFFFFFFl + if(a < 0) ref2 = 0 + if(a >= 0xFFFFFFFFl) ref2 = 0xFFFFFFFFl + if(a.isNaN) ref2 = 0xFFFFFFFFl + assert(v == ref2, f" <= f2ui($a) = $v, $ref2, $rounding $flag") + } + } + + flagMatch(flag, ref, f" f2${if(signed) "" else "u"}i($a) $ref $flag $rounding") + } + + + + def testI2fExact(a : Int, ref : Float, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rd = Random.nextInt(32) + i2f(rd, a, signed, rounding, FpuFormat.FLOAT) + storeFloat(rd){v => + val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl + assert(f2b(v) == f2b(ref), f"i2f($aLong) = $v, $ref $rounding") + } + + + flagMatch(f, ref, f"i2f($a) = $ref") + } + + + + def testI2f64Exact(a : Int, ref : Double, f : Int, signed : Boolean, rounding : FpuRoundMode.E): Unit ={ + val rs = new RegAllocator() + val rd = Random.nextInt(32) + i2f(rd, a, signed, rounding, FpuFormat.DOUBLE) + store(rd){v => + val aLong = if(signed) a.toLong else a.toLong & 0xFFFFFFFFl + assert(d2b(v) == d2b(ref), f"i2f($aLong) = $v, $ref $rounding") + } + + + flagMatch(f, ref, f"i2f($a) = $ref") + } + + + def testCmpExact(a : Float, b : Float, ref : Int, flag : Int, arg : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + cmp(rs1, rs2, arg, FpuFormat.FLOAT){rsp => + val v = rsp.value.toBigInt.toInt + assert(v === ref, f"cmp($a, $b, $arg) = $v, $ref") + } + flagMatch(flag,f"$a < $b $ref $flag ${f2b(a).toHexString} ${f2b(b).toHexString}") + } + def testLeRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 0) + def testEqRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 2) + def testLtRaw(a : Float, b : Float, ref : Int, flag : Int) = testCmpExact(a,b,ref,flag, 1) + + + def testCmpF64Exact(a : Double, b : Double, ref : Int, flag : Int, arg : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2, rs3 = rs.allocate() + val rd = Random.nextInt(32) + load(rs1, a) + load(rs2, b) + cmp(rs1, rs2, arg, FpuFormat.DOUBLE){rsp => + val v = rsp.value.toBigInt.toInt + assert(v === ref, f"cmp($a, $b, $arg) = $v, $ref") + } + flagMatch(flag,f"$a < $b $ref $flag ${d2b(a)} ${d2b(b)}") + } + def testLeF64Raw(a : Double, b : Double, ref : Int, flag : Int) = testCmpF64Exact(a,b,ref,flag, 0) + def testEqF64Raw(a : Double, b : Double, ref : Int, flag : Int) = testCmpF64Exact(a,b,ref,flag, 2) + def testLtF64Raw(a : Double, b : Double, ref : Int, flag : Int) = testCmpF64Exact(a,b,ref,flag, 1) + +// def testFmv_x_w(a : Float): Unit ={ +// val rs = new RegAllocator() +// val rs1, rs2, rs3 = rs.allocate() +// val rd = Random.nextInt(32) +// load(rs1, a)tes +// fmv_x_w(rs1){rsp => +// val ref = f2b(a).toLong & 0xFFFFFFFFl +// val v = rsp.value.toBigInt +// println(f"fmv_x_w $a = $v, $ref") +// assert(v === ref) +// } +// } + +// def testFmv_w_x(a : Int): Unit ={ +// val rs = new RegAllocator() +// val rs1, rs2, rs3 = rs.allocate() +// val rd = Random.nextInt(32) +// fmv_w_x(rd, a) +// storeFloat(rd){v => +// val ref = b2f(a) +// println(f"fmv_w_x $a = $v, $ref") +// assert(v === ref) +// } +// } + + + + def testMinMaxExact(a : Float, b : Float, arg : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2 = rs.allocate() + val rd = Random.nextInt(32) + val ref = (a,b) match { + case _ if a.isNaN && b.isNaN => b2f(0x7FC00000) + case _ if a.isNaN => b + case _ if b.isNaN => a + case _ => if(arg == 0) Math.min(a,b) else Math.max(a,b) + } + val flag = (a,b) match { + case _ if a.isNaN && ((f2b(a) >> 22 ) & 1) == 0 => 16 + case _ if b.isNaN && ((f2b(b) >> 22 ) & 1) == 0 => 16 + case _ => 0 + } + load(rs1, a) + load(rs2, b) + + minMax(rd,rs1,rs2, arg, FpuFormat.FLOAT) + storeFloat(rd){v => + assert(f2b(ref) == f2b(v), f"minMax($a $b $arg) = $v, $ref") + } + flagMatch(flag, f"minmax($a $b $arg)") + } + + def testMinExact(a : Float, b : Float) : Unit = testMinMaxExact(a,b,0) + def testMaxExact(a : Float, b : Float) : Unit = testMinMaxExact(a,b,1) + + + def testMinMaxF64Exact(a : Double, b : Double, arg : Int): Unit ={ + val rs = new RegAllocator() + val rs1, rs2 = rs.allocate() + val rd = Random.nextInt(32) + val ref = (a,b) match { + case _ if a.isNaN && b.isNaN => b2d(0x7ff8000000000000l) + case _ if a.isNaN => b + case _ if b.isNaN => a + case _ => if(arg == 0) Math.min(a,b) else Math.max(a,b) + } + val flag = (a,b) match { + case _ if a.isNaN && ((d2b(a) >> 51 ) & 1) == 0 => 16 + case _ if b.isNaN && ((d2b(b) >> 51 ) & 1) == 0 => 16 + case _ => 0 + } + load(rs1, a) + load(rs2, b) + + minMax(rd,rs1,rs2, arg, FpuFormat.DOUBLE) + store(rd){v => + assert(d2b(ref) == d2b(v), f"minMax($a $b $arg) = $v, $ref") + } + flagMatch(flag, f"minmax($a $b $arg)") + } + + def testMinF64Exact(a : Double, b : Double) : Unit = testMinMaxF64Exact(a,b,0) + def testMaxF64Exact(a : Double, b : Double) : Unit = testMinMaxF64Exact(a,b,1) + + + def testSgnjRaw(a : Float, b : Float): Unit ={ + var ref = b2f((f2b(a) & ~0x80000000) | f2b(b) & 0x80000000) + if(a.isNaN) ref = a + testBinaryOp(sgnj,a,b,ref,0, null,"sgnj") + } + def testSgnjnRaw(a : Float, b : Float): Unit ={ + var ref = b2f((f2b(a) & ~0x80000000) | ((f2b(b) & 0x80000000) ^ 0x80000000)) + if(a.isNaN) ref = a + testBinaryOp(sgnjn,a,b,ref,0, null,"sgnjn") + } + def testSgnjxRaw(a : Float, b : Float): Unit ={ + var ref = b2f(f2b(a) ^ (f2b(b) & 0x80000000)) + if(a.isNaN) ref = a + testBinaryOp(sgnjx,a,b,ref,0, null,"sgnjx") + } + + val f64SignMask = 1l << 63 + def testSgnjF64Raw(a : Double, b : Double): Unit ={ + var ref = b2d((d2b(a).toLong & ~f64SignMask) | d2b(b).toLong & f64SignMask) + if(a.isNaN) ref = a + testBinaryOpF64(sgnj,a,b,ref,0, null,"sgnj") + } + def testSgnjnF64Raw(a : Double, b : Double): Unit ={ + var ref = b2d((d2b(a).toLong & ~f64SignMask) | ((d2b(b).toLong & f64SignMask) ^ f64SignMask)) + if(a.isNaN) ref = a + testBinaryOpF64(sgnjn,a,b,ref,0, null,"sgnjn") + } + def testSgnjxF64Raw(a : Double, b : Double): Unit ={ + var ref = b2d(d2b(a).toLong ^ (d2b(b).toLong & f64SignMask)) + if(a.isNaN) ref = a + testBinaryOpF64(sgnjx,a,b,ref,0, null,"sgnjx") + } + + + def withMinus(that : Seq[Float]) = that.flatMap(f => List(f, -f)) + val fZeros = withMinus(List(0.0f)) + val fSubnormals = withMinus(List(b2f(0x00000000+1), b2f(0x00000000+2), b2f(0x00006800), b2f(0x00800000-2), b2f(0x00800000-1))) + val fExpSmall = withMinus(List(b2f(0x00800000), b2f(0x00800000+1), b2f(0x00800000 + 2))) + val fExpNormal = withMinus(List(b2f(0x3f800000-2), b2f(0x3f800000-1), b2f(0x3f800000), b2f(0x3f800000+1), b2f(0x3f800000+2))) + val fExpBig = withMinus(List(b2f(0x7f7fffff-2), b2f(0x7f7fffff-1), b2f(0x7f7fffff))) + val fInfinity = withMinus(List(Float.PositiveInfinity)) + val fNan = List(Float.NaN, b2f(0x7f820000), b2f(0x7fc00000)) + val fAll = fZeros ++ fSubnormals ++ fExpSmall ++ fExpNormal ++ fExpBig ++ fInfinity ++ fNan + + val iSmall = (0 to 20) + val iBigUnsigned = (0 to 20).map(e => 0xFFFFFFFF - e) + val iBigSigned = (0 to 20).map(e => 0x7FFFFFFF - e) ++ (0 to 20).map(e => 0x80000000 + e) + val iUnsigned = iSmall ++ iBigUnsigned + val iSigned = iSmall ++ iSmall.map(-_) ++ iBigSigned + + + val roundingModes = FpuRoundMode.elements + def foreachRounding(body : FpuRoundMode.E => Unit): Unit ={ + for(rounding <- roundingModes){ + body(rounding) + } + } + + def testFmaF32() : Unit = { + testFmaRaw(randomFloat(), randomFloat(), randomFloat()) + flagClear() + } + + + def testFmaF64() : Unit = { + testFmaF64Raw(randomDouble(), randomDouble(), randomDouble()) + flagClear() + } + + def testLeF32() : Unit = { + val (a,b,i,f) = f32.le.RAW.f32_f32_i32 + testLeRaw(a,b,i, f) + } + def testLtF32() : Unit = { + val (a,b,i,f) = f32.lt.RAW.f32_f32_i32 + testLtRaw(a,b,i, f) + } + + def testEqF32() : Unit = { + val (a,b,i,f) = f32.eq.RAW.f32_f32_i32 + testEqRaw(a,b,i, f) + } + + def testLeF64() : Unit = { + val (a,b,i,f) = f64.le.RAW.f64_f64_i32 + testLeF64Raw(a,b,i, f) + } + def testLtF64() : Unit = { + val (a,b,i,f) = f64.lt.RAW.f64_f64_i32 + testLtF64Raw(a,b,i, f) + } + + def testEqF64() : Unit = { + val (a,b,i,f) = f64.eq.RAW.f64_f64_i32 + testEqF64Raw(a,b,i, f) + } + + + def testF2uiF32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2ui(rounding).f32_i32 + testF2iExact(a,b, f, false, rounding) + } + + def testF2iF32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.f2i(rounding).f32_i32 + testF2iExact(a,b, f, true, rounding) + } + + def testF2uiF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.f2ui(rounding).f64_i32 + testF642iExact(a,b, f, false, rounding) + } + + def testF2iF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.f2i(rounding).f64_i32 + testF642iExact(a,b, f, true, rounding) + } + + + def testDiv() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,r,f) = f32.div(rounding).f32_f32_f32 + testBinaryOp(div, a, b, r, f, rounding, "div") + } + + def testSqrt() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f32.sqrt(rounding).f32_f32 + testSqrtExact(a, r, f, rounding) + flagClear() + } + + def testSgnjF32() : Unit = { + testSgnjRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) + testSgnjnRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) + testSgnjxRaw(b2f(Random.nextInt()), b2f(Random.nextInt())) + val (a,b,r,f) = f32.sgnj.RAW.f32_f32_i32 + testSgnjRaw(a, b) + testSgnjnRaw(a, b) + testSgnjxRaw(a, b) + } + + def testDivF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,r,f) = f64.div(rounding).f64_f64_f64 + // testDivF64Exact(a, b, r, f, rounding) + testBinaryOpF64(div, a, b, r, f,rounding, "div") + flagClear() + } + + def testSqrtF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f64.sqrt(rounding).f64_f64 + testSqrtF64Exact(a, r, f, rounding) + flagClear() + } + + def testSgnjF64() : Unit = { + testSgnjF64Raw(b2d(Random.nextLong()), b2d(Random.nextLong())) + testSgnjnF64Raw(b2d(Random.nextLong()), b2d(Random.nextLong())) + testSgnjxF64Raw(b2d(Random.nextLong()), b2d(Random.nextLong())) + val (a,b,r,f) = f64.sgnj.RAW.f64_f64_i32 + testSgnjF64Raw(a, b) + testSgnjnF64Raw(a, b) + testSgnjxF64Raw(a, b) + } + + + def testTransferF32() : Unit = { + val (a,b,r,f) = f32.transfer.RAW.f32_f32_i32 + testTransferF32Raw(a, Random.nextBoolean(), Random.nextBoolean()) + } + + def testTransferF64() : Unit = { + val (a,b,r,f) = f64.transfer.RAW.f64_f64_i32 + testTransferF64Raw(a) + } + + def testTransferF64F32() : Unit = { + val (a,b,r,f) = f64.f32.RAW.f64_f64_i32 + testTransferF64F32Raw(a, Random.nextBoolean()) + } + def testTransferF32F64() : Unit = { + val (a,b,r,f) = f32.f64.RAW.f32_f32_i32 + testTransferF32F64Raw(a, Random.nextBoolean()) + } + + def testCvtF32F64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f32.cvt64(rounding).f32_f64_i32 + testCvtF32F64Raw(a, r, f, rounding) + } + def testCvtF64F32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,r,f) = f64.cvt32(rounding).f64_f32_i32 + testCvtF64F32Raw(a, r, f, rounding) + } + + def testClassF32() : Unit = { + val (a,b,r,f) = f32.fclass.RAW.f32_f32_i32 + testClassRaw(a) + } + + def testMinF32() : Unit = { + val (a,b,r,f) = f32.min.RAW.f32_f32_f32 + testMinExact(a,b) + } + def testMaxF32() : Unit = { + val (a,b,r,f) = f32.max.RAW.f32_f32_f32 + testMaxExact(a,b) + } + + def testClassF64() : Unit = { + val (a,b,r,f) = f64.fclass.RAW.f64_f64_i32 + testClassF64Raw(a) + } + + def testMinF64() : Unit = { + val (a,b,r,f) = f64.min.RAW.f64_f64_f64 + testMinF64Exact(a,b) + } + def testMaxF64() : Unit = { + val (a,b,r,f) = f64.max.RAW.f64_f64_f64 + testMaxF64Exact(a,b) + } + + + def testUI2f32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.i2f(rounding).i32_f32 + testI2fExact(a,b,f, true, rounding) + } + + def testI2f32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f32.ui2f(rounding).i32_f32 + testI2fExact(a,b,f, false, rounding) + } + + def testUI2f64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.i2f(rounding).i32_f64 + testI2f64Exact(a,b,f, true, rounding) + } + + def testI2f64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,f) = f64.ui2f(rounding).i32_f64 + testI2f64Exact(a,b,f, false, rounding) + } + + def testMulF32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 + testBinaryOp(mul,a,b,c,f, rounding,"mul") + } + + def testAddF32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.add(rounding).f32_f32_f32 + testBinaryOp(add,a,b,c,f, rounding,"add") + } + + def testSubF32() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f32.sub(rounding).f32_f32_f32 + testBinaryOp(sub,a,b,c,f, rounding,"sub") + } + + + def testMulF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f64.mul(rounding).f64_f64_f64 + testBinaryOpF64(mul,a,b,c,f, rounding,"mul") + } + + def testAddF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f64.add(rounding).f64_f64_f64 + testBinaryOpF64(add,a,b,c,f, rounding,"add") + } + + def testSubF64() : Unit = { + val rounding = FpuRoundMode.elements.randomPick() + val (a,b,c,f) = f64.sub(rounding).f64_f64_f64 + testBinaryOpF64(sub,a,b,c,f, rounding,"sub") + } + + + val f32Tests = List[() => Unit](testSubF32, testAddF32, testMulF32, testI2f32, testUI2f32, testMinF32, testMaxF32, testSgnjF32, testTransferF32, testDiv, testSqrt, testF2iF32, testF2uiF32, testLeF32, testEqF32, testLtF32, testClassF32, testFmaF32) + val f64Tests = List[() => Unit](testSubF64, testAddF64, testMulF64, testI2f64, testUI2f64, testMinF64, testMaxF64, testSgnjF64, testTransferF64, testDiv, testSqrt, testF2iF64, testF2uiF64, testLeF64, testEqF64, testLtF64, testClassF64, testFmaF64, testCvtF32F64, testCvtF64F32) + + var fxxTests = f32Tests + if(p.withDouble) fxxTests ++= f64Tests + +//5071920 5225560 +// for(v <- List(-1.17549435082e-38f, 1.17549435082e-38f); +// rounding <- FpuRoundMode.elements) { +// for (i <- 0 until 2048) { +// val b = d2b(v)// 0x0010000000000000l //d2b(1.17549435082e-38) +// val s = (b - (i.toLong << 21)).toLong +// val d = b2d(s) +//// val rounding = FpuRoundMode.RNE +// testCvtF64F32Raw(d, Clib.math.d2f(d, rounding.position), Clib.math.d2fFlag(d, rounding.position), rounding) +// } +// } +// +// +// testCvtF64F32Raw(-1.1754943508051483E-38, -1.17549435E-38f, 1, FpuRoundMode.RNE) +// testCvtF64F32Raw( 1.1754943157898258E-38, 1.17549435E-38f , 3, FpuRoundMode.RMM) +// testCvtF64F32Raw( 1.1754942807573643E-38, 1.17549435E-38f , 3, FpuRoundMode.RMM) +// testCvtF64F32Raw(-1.1754943508051483E-38, -1.17549435E-38f, 1, FpuRoundMode.RMM) + + //-1.1754943508051483E-38 -1.17549435E-38 1 RNE @ 592770 + // 1.1754943157898258E-38 1.17549435E-38 3 RMM @ 2697440 + // 1.1754942807573643E-38 1.17549435E-38 3 RMM +// for(_ <- 0 until 1000000) testCvtF64F32() // 1 did not equal 3 Flag missmatch dut=1 ref=3 testCvtF64F32Raw 1.1754942807573643E-38 1.17549435E-38 RMM +// println("FCVT_D_S done") + +// testBinaryOpF64(div, -2.2250738564511294E-308, 4.294967296003891E9, -5.180654E-318, 1, FpuRoundMode.RDN,"div") // ??? wtf + +// testBinaryOp(add,b2f(0x7F800000),b2f(0x1FD << 23),b2f(0x7F800000),0, FpuRoundMode.RNE,"add") + + + +// testBinaryOp(mul,1.1753509E-38f, 1.0001221f ,1.17549435E-38f,1, FpuRoundMode.RNE,"mul") +// +// for(i <- 0 until 10000000){ +// val rounding = FpuRoundMode.elements.randomPick() +// val (a,b,c,f) = f32.mul(rounding).f32_f32_f32 +// testBinaryOp(mul,a,b,c,f, rounding,"mul") +// } +// +// testBinaryOpF64(mul,2.781342323134002E-309, 7.999999999999999, 2.2250738585072014E-308, 3, FpuRoundMode.RNE,"mul") +//// for(i <- 0 until 10000000){ +//// val rounding = FpuRoundMode.RNE +//// val (a,b,c,f) = f64.mul(rounding).f64_f64_f64 +//// testBinaryOpF64(mul,a,b,c,f, rounding,"mul") +//// } +// for(_ <- 0 until 100000000) testMulF64() +// println("f64 Mul done") +// +// for(_ <- 0 until 10000) testDivF64() +// println("f64 div done") +// +// +// for(_ <- 0 until 10000) testDiv() +// println("f32 div done") +// +// for(_ <- 0 until 10000) testAddF32() +// for(_ <- 0 until 10000) testSubF32() +// +// println("Add done") +// +// +// for(_ <- 0 until 10000) testSqrt() +// println("f32 sqrt done") + + + + + + + //TODO test boxing + //TODO double <-> simple convertions + if(p.withDouble) { + + testSqrtF64Exact(1.25*1.25, 1.25, 0, FpuRoundMode.RNE) + testSqrtF64Exact(1.5*1.5, 1.5, 0, FpuRoundMode.RNE) + + for(_ <- 0 until 10000) testSqrtF64() + println("f64 sqrt done") + +// testDivF64Exact(1.0, 8.0, 0.125, 0, FpuRoundMode.RNE) +// testDivF64Exact(4.0, 8.0, 0.5, 0, FpuRoundMode.RNE) +// testDivF64Exact(8.0, 8.0, 1.0, 0, FpuRoundMode.RNE) +// testDivF64Exact(1.5, 2.0, 0.75, 0, FpuRoundMode.RNE) +// testDivF64Exact(1.875, 1.5, 1.25, 0, FpuRoundMode.RNE) + + for(_ <- 0 until 10000) testDivF64() + println("f64 div done") + + for(_ <- 0 until 10000) testSgnjF64() + println("f64 sgnj done") + + for(_ <- 0 until 10000) testSgnjF32() + println("f32 sgnj done") + + //380000000001ffef 5fffffffffff9ff 8000000000100000 +// testBinaryOpF64(mul,-5.877471754282472E-39, 8.814425663400984E-280, -5.180654E-318 ,1, FpuRoundMode.RMM,"mul") +// 5.877471754282472E-39 8.814425663400984E-280 -5.180654E-318 RMM + + for(_ <- 0 until 10000) testCvtF64F32() // 1 did not equal 3 Flag missmatch dut=1 ref=3 testCvtF64F32Raw 1.1754942807573643E-38 1.17549435E-38 RMM + println("FCVT_D_S done") + for(_ <- 0 until 10000) testCvtF32F64() + println("FCVT_S_D done") + + for(_ <- 0 until 10000) testF2iF64() + println("f64 f2i done") + for(_ <- 0 until 10000) testF2uiF64() + println("f64 f2ui done") + + + + + + for(_ <- 0 until 10000) testMinF64() + for(_ <- 0 until 10000) testMaxF64() + println("f64 minMax done") + + + + for(i <- 0 until 1000) testFmaF64() + flagClear() + println("f64 fma done") //TODO + + + for(_ <- 0 until 10000) testLeF64() + for(_ <- 0 until 10000) testLtF64() + for(_ <- 0 until 10000) testEqF64() + println("f64 Cmp done") + + + for(_ <- 0 until 10000) testClassF64() + println("f64 class done") +// + + + + + + + + + for(_ <- 0 until 10000) testAddF64() + for(_ <- 0 until 10000) testSubF64() + println("f64 Add done") + + + // testI2f64Exact(0x7FFFFFF5, 0x7FFFFFF5, 0, true, FpuRoundMode.RNE) + for(_ <- 0 until 10000) testUI2f64() + for(_ <- 0 until 10000) testI2f64() + println("f64 i2f done") + + + +// testF2iExact(1.0f,1, 0, false, FpuRoundMode.RTZ) +// testF2iExact(2.0f,2, 0, false, FpuRoundMode.RTZ) +// testF2iExact(2.5f,2, 1, false, FpuRoundMode.RTZ) + + + + + testBinaryOpF64(mul,1.0, 1.0, 1.0,0 , FpuRoundMode.RNE,"mul") + testBinaryOpF64(mul,1.0, 2.0, 2.0,0 , FpuRoundMode.RNE,"mul") + testBinaryOpF64(mul,2.5, 2.0, 5.0,0 , FpuRoundMode.RNE,"mul") + + for(_ <- 0 until 10000) testMulF64() + println("f64 Mul done") + + testTransferF64Raw(1.0) + testTransferF64Raw(2.0) + testTransferF64Raw(2.5) + testTransferF64Raw(6.97949770801e-39) + testTransferF64Raw(8.72437213501e-40) + testTransferF64Raw(5.6E-45) + + testTransferF32F64Raw(b2f(0xFFFF1234), false) + testTransferF64F32Raw(b2d(0xFFF123498765463l << 4), false) + testTransferF32F64Raw(b2f(0xFFFF1234), true) + testTransferF64F32Raw(b2d(0xFFF123498765463l << 4), true) + + for (_ <- 0 until 10000) testTransferF64() + println("f64 load/store/rf transfer done") + + for (_ <- 0 until 10000) testTransferF64F32() + println("f64 -> f32 load/store/rf transfer done") + + for (_ <- 0 until 10000) testTransferF32F64() + println("f32 -> f64 load/store/rf transfer done") + + } + + for(_ <- 0 until 10000) testTransferF32() + println("f32 load/store/rf transfer done") + + for(_ <- 0 until 10000) testMulF32() + println("Mul done") + + + for(_ <- 0 until 10000) testUI2f32() + for(_ <- 0 until 10000) testI2f32() + println("i2f done") + + + testF2iExact(1.0f,1, 0, false, FpuRoundMode.RTZ) + testF2iExact(2.0f,2, 0, false, FpuRoundMode.RTZ) + testF2iExact(2.5f,2, 1, false, FpuRoundMode.RTZ) + + + + + + for(_ <- 0 until 10000) testF2uiF32() + for(_ <- 0 until 10000) testF2iF32() + println("f2i done") + + + +// waitUntil(cmdQueue.isEmpty) +// dut.clockDomain.waitSampling(1000) +// simSuccess() + + + + for(i <- 0 until 1000) testFmaF32() + flagClear() + println("fma done") //TODO + + + testF2iExact(-2.14748365E9f, -2147483648, 0, true, FpuRoundMode.RDN) + + testEqRaw(Float.PositiveInfinity,Float.PositiveInfinity,1, 0) + testEqRaw(0f, 0f,1, 0) + + for(_ <- 0 until 10000) testLeF32() + for(_ <- 0 until 10000) testLtF32() + for(_ <- 0 until 10000) testEqF32() + println("Cmp done") + + + for(_ <- 0 until 10000) testDiv() + println("f32 div done") + + for(_ <- 0 until 10000) testSqrt() + println("f32 sqrt done") + + for(_ <- 0 until 10000) testSgnjF32() + println("f32 sgnj done") + + + for(_ <- 0 until 10000) testClassF32() + println("f32 class done") + + + for(_ <- 0 until 10000) testMinF32() + for(_ <- 0 until 10000) testMaxF32() + println("minMax done") + + + + testBinaryOp(mul,1.469368E-39f, 7.9999995f, 1.17549435E-38f,3, FpuRoundMode.RUP,"mul") + testBinaryOp(mul,1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") + testBinaryOp(mul, 1.1754942E-38f, -1.0000001f, -1.17549435E-38f,1, FpuRoundMode.RNE,"mul") + testBinaryOp(mul, 1.1754942E-38f, -1.0000001f, -1.17549435E-38f,1, FpuRoundMode.RDN,"mul") + testBinaryOp(mul, 1.1754942E-38f, -1.0000001f, -1.17549435E-38f,1, FpuRoundMode.RMM,"mul") + + testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + testBinaryOp(mul, 1.1754945E-38f, -0.9999998f, -1.17549435E-38f, 3, FpuRoundMode.RDN, "mul") + testBinaryOp(mul, 1.1754946E-38f, 0.9999997f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + testBinaryOp(mul, 1.1754946E-38f, -0.9999997f, -1.17549435E-38f, 3, FpuRoundMode.RDN, "mul") + testBinaryOp(mul, 1.1754949E-38f, 0.99999946f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + testBinaryOp(mul, 1.1754949E-38f, -0.99999946f, -1.17549435E-38f, 3, FpuRoundMode.RDN, "mul") + testBinaryOp(mul, 1.1754955E-38f, 0.999999f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") + + + + + + + for(_ <- 0 until 10000) testAddF32() + for(_ <- 0 until 10000) testSubF32() + + println("Add done") + + + + + + + + + + +// waitUntil(cmdQueue.isEmpty) +// dut.clockDomain.waitSampling(1000) +// simSuccess() + + for(i <- 0 until 100000) fxxTests.randomPick()() + waitUntil(cpu.rspQueue.isEmpty) + } + + + + + stim.foreach(_.join()) + dut.clockDomain.waitSampling(100) + } + } +} + + +//object Clib { +// val java_home = System.getProperty("java.home") +// assert(java_home != "" && java_home != null, "JAVA_HOME need to be set") +// val jdk = java_home.replace("/jre","").replace("\\jre","") +// val jdkIncludes = jdk + "/include" +// val flags = List("-fPIC", "-m64", "-shared", "-Wno-attributes") //-Wl,--whole-archive +// val os = new File("/media/data/open/SaxonSoc/berkeley-softfloat-3/build/Linux-x86_64-GCC").listFiles().map(_.getAbsolutePath).filter(_.toString.endsWith(".o")) +// val cmd = s"gcc -I/media/data/open/SaxonSoc/berkeley-softfloat-3/source/include -I$jdkIncludes -I$jdkIncludes/linux ${flags.mkString(" ")} -o src/test/cpp/fpu/math/fpu_math.so src/test/cpp/fpu/math/fpu_math.c src/test/cpp/fpu/math/softfloat.a" // src/test/cpp/fpu/math/softfloat.a +// DoCmd.doCmd(cmd) +// val math = new FpuMath +//} +// cd /media/data/open/SaxonSoc/testFloatBuild/berkeley-softfloat-3/build/Linux-x86_64-GCC +// make clean && SPECIALIZE_TYPE=RISCV make -j$(nproc) && cp softfloat.a /media/data/open/SaxonSoc/artyA7SmpUpdate/SaxonSoc/ext/VexRiscv/src/test/cpp/fpu/math +//object FpuCompileSo extends App{ +// +//// val b2f = lang.Float.intBitsToFloat(_) +//// for(e <- FpuRoundMode.elements) { +//// println(e) +//// for (i <- -2 until 50) println(i + " => " + Clib.math.addF32(b2f(0x7f000000), b2f(0x7f000000 + i), e.position)) +//// println("") +//// } +// //1 did not equal 3 Flag missmatch dut=1 ref=3 ## mul 0.9994812 -1.1754988E-38 -1.174889E-38 RMM +// // println(Clib.math.mulF32(0.9994812f, -1.1754988E-38f, FpuRoundMode.RMM.position)) +//// miaou ffffffff 7fffffe0 7f +//// miaou 0 3ffffff0 70 = 0 +// +// val b2f = lang.Float.intBitsToFloat(_) +// val b2d = lang.Double.longBitsToDouble(_) +// val f2b = lang.Float.floatToRawIntBits(_) +// val d2bOffset = BigInt("10000000000000000",16) +// def d2b(that : Double) = { +// val l = lang.Double.doubleToRawLongBits(that) +// var a = BigInt(l) +// if(l < 0) { +// a = d2bOffset + a +// } +// a +// } +// val builder =new StringBuilder() +// for(i <- 0 until 256){ +//// builder ++= (Clib.math.mulF32(1.17548538251e-38f, b2f(f2b(1.0f)+i),0)).toString + "\n" +// val b = d2b(1.17549435082e-38) +// val s = (b-(i.toLong << 25)).toLong +// val d = b2d(s) +// builder ++= f"$b $s $d => " +// builder ++= f"${d2b(d)}%x " + (Clib.math.d2fFlag(d,0)).toString + " " + d + " => " + (Clib.math.d2f(d,FpuRoundMode.RMM.position)).toString + "\n" +// } +// +// Thread.sleep(400) +// println(builder.toString) +// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.1754945E-38f, 0.9999998f, FpuRoundMode.RUP.position)) +// testBinaryOp(mul, 1.1753509E-38f, 1.0001221f, 1.17549435E-38f ,1, FpuRoundMode.RUP,"mul") +// testBinaryOp(mul, 1.1754945E-38f, 0.9999998f, 1.17549435E-38f, 3, FpuRoundMode.RUP, "mul") +// miaou ffffffff 7fffffe0 7f +// miaou 0 3ffffff0 70 = 0 +// miaou ffffffff 7fffff7e 7f +// miaou 1 3fffffbf 3f = 1 + +// println(Clib.math.mulF32( 1.1753509E-38f, 1.0001221f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.469368E-39f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1.40129846432e-45f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 2.93873587706e-39f, 7.9999995f, FpuRoundMode.RUP.position)) +// println(Clib.math.mulF32( 1f, 7.9999995f, FpuRoundMode.RUP.position)) + + +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RNE.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RTZ.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RDN.position)) +// println(Clib.math.addF32(1.00000011921f, 4.0f, FpuRoundMode.RUP.position)) +//} + +class ProcessStream(cmd : String){ + import sys.process._ + + val buf = mutable.Queue[() => String]() + val p = Process(cmd).run(new ProcessLogger { + override def out(s: => String): Unit = { + while(buf.size > 10000) Thread.sleep(10) + buf.enqueue(() => s) + } + override def err(s: => String): Unit = {} + override def buffer[T](f: => T): T = f + }) + + def kill = p.destroy() + def next = { + while(buf.isEmpty) { Thread.sleep(10) } + buf.dequeue()() + } +} + diff --git a/VexRiscv/src/test/scala/vexriscv/ip/fpu/Playground.scala b/VexRiscv/src/test/scala/vexriscv/ip/fpu/Playground.scala new file mode 100644 index 0000000..a155210 --- /dev/null +++ b/VexRiscv/src/test/scala/vexriscv/ip/fpu/Playground.scala @@ -0,0 +1,47 @@ +package vexriscv.ip.fpu + +object MiaouDiv extends App{ + val input = 2.5 + var output = 1/(input*0.95) + + def y = output + def x = input + + for(i <- 0 until 10) { + output = 2 * y - x * y * y + println(output) + } + + + //output = x*output + println(1/input) +} + +object MiaouSqrt extends App{ + val input = 2.0 + var output = 1/Math.sqrt(input*0.95) + // def x = output + // def y = input + + def y = output + def x = input + + for(i <- 0 until 10) { + output = y * (1.5 - x * y * y / 2) + println(output) + } + + output = x*output + println(output) + println(s"ref ${Math.sqrt(input)}") +} + + +object MiaouNan extends App{ + println(Float.NaN + 3.0f) + println(3.0f + Float.NaN ) + println(0.0f*Float.PositiveInfinity ) + println(1.0f/0.0f ) + println(Float.MaxValue -1 ) + println(Float.PositiveInfinity - Float.PositiveInfinity) +}
\ No newline at end of file |