aboutsummaryrefslogtreecommitdiff
path: root/VexRiscv/src/main/scala/spinal/lib
diff options
context:
space:
mode:
Diffstat (limited to 'VexRiscv/src/main/scala/spinal/lib')
-rw-r--r--VexRiscv/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala213
1 files changed, 213 insertions, 0 deletions
diff --git a/VexRiscv/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala b/VexRiscv/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala
new file mode 100644
index 0000000..6ef8d08
--- /dev/null
+++ b/VexRiscv/src/main/scala/spinal/lib/eda/icestorm/IcestormFlow.scala
@@ -0,0 +1,213 @@
+package spinal.lib.eda.icestorm
+import spinal.lib.eda._
+import spinal.lib.eda.bench.{Report, Rtl, Target}
+
+import scala.collection.mutable.ArrayBuffer
+import java.io.File
+import java.nio.file.Paths
+
+import org.apache.commons.io.FileUtils
+import spinal.core._
+import spinal.lib.StreamFifo
+import spinal.lib.eda.bench.Report
+
+import scala.sys.process._
+
+import scala.collection.Seq
+
+object IcestormFlow {
+ def doCmd(cmd : Seq[String], path : String): String ={
+ println(cmd)
+ val str = new StringBuilder()
+ val log = new ProcessLogger {
+ override def err(s: => String): Unit = {
+ str ++= s
+ stderr.println(s)
+ }
+
+ override def out(s: => String): Unit = {
+ str ++= s
+ stdout.println(s)
+ }
+
+ override def buffer[T](f: => T) = f
+ }
+ if(isWindows)
+ Process("cmd /C " + cmd, new java.io.File(path)) !(log)
+ else
+ Process.apply(cmd, new java.io.File(path)) !(log)
+
+ return str.toString()
+ }
+
+ val isWindows = System.getProperty("os.name").toLowerCase().contains("win")
+
+ def apply(workspacePath : String,toplevelPath : String,family : String,device : String, pack : String) : Report = {
+ val projectName = toplevelPath.split("/").last.split("[.]").head
+
+//ifeq ($(NEXTPNR),yes)
+//%.json: ${VERILOGS}
+// rm -f ${TOPLEVEL}.v*.bin
+// cp -f ${ROOT}/hardware/netlist/${TOPLEVEL}.v*.bin . | true
+// yosys -p 'synth_ice40 -top $(TOPLEVEL) -json $@' $<
+//
+//%.asc: $(PIN_DEF) %.json constraint.py
+// nextpnr-ice40 --$(DEVICE) --json $(TOPLEVEL).json --pcf $(PIN_DEF) --asc $(TOPLEVEL).asc --pre-pack constraint.py $(NEXTPNR_ARG)
+//else
+//%.blif: ${VERILOGS}
+// rm -f ${TOPLEVEL}.v*.bin
+// cp -f ${ROOT}/hardware/netlist/${TOPLEVEL}.v*.bin . | true
+// yosys -p 'synth_ice40 -top ${TOPLEVEL} -blif $@' $<
+//
+//%.asc: $(PIN_DEF) %.blif
+// arachne-pnr -d $(subst up,,$(subst hx,,$(subst lp,,$(DEVICE)))) -o $@ -p $^
+//endif
+
+ val workspacePathFile = new File(workspacePath)
+ FileUtils.deleteDirectory(workspacePathFile)
+ workspacePathFile.mkdir()
+ FileUtils.copyFileToDirectory(new File(toplevelPath), workspacePathFile)
+ doCmd(List("yosys", "-v3", "-p", s"synth_ice40 -top $projectName -json ${projectName}.json", s"$projectName.v" ), workspacePath)
+ val arachne = doCmd(List("nextpnr-ice40", s"--$device", "--json", s"${projectName}.json","--asc", s"$projectName.asc"), workspacePath)
+ doCmd(List("icepack", s"$projectName.asc", s"$projectName.bin"), workspacePath)
+ val icetime = doCmd(List("icetime", "-tmd", device, s"${projectName}.asc"), workspacePath)
+ new Report{
+ val intFind = "(\\d+,?)+".r
+ val fMaxReg = """[-+]?(\d*[.])?\d+""".r
+ override def getFMax() = {
+ try {
+ fMaxReg.findAllMatchIn("Total path delay: [^\\n]* MHz".r.findFirstIn(icetime).get).drop(1).next.toString().toDouble * 1e6
+ } catch {
+ case e : Throwable => -1
+ }
+ }
+ override def getArea() = {
+ try {
+ intFind.findFirstIn("ICESTORM_LC\\:[^\\n]*\\/".r.findFirstIn(arachne).get).get.toString() + " LC"
+ } catch {
+ case e : Throwable => "error"
+ }
+ }
+ }
+// mkdir -p bin
+// rm -f Murax.v*.bin
+// cp ../../../Murax.v*.bin . | true
+// yosys -v3 -p "synth_ice40 -top toplevel -blif bin/toplevel.blif" ${VERILOG}
+//
+// val isVhdl = toplevelPath.endsWith(".vhd") || toplevelPath.endsWith(".vhdl")
+//
+// val tcl = new java.io.FileWriter(Paths.get(workspacePath,"doit.tcl").toFile)
+// tcl.write(
+// s"""read_${if(isVhdl) "vhdl" else "verilog"} $toplevelPath
+//read_xdc doit.xdc
+//
+//synth_design -part $device -top ${toplevelPath.split("\\.").head}
+//opt_design
+//place_design
+//route_design
+//
+//report_utilization
+//report_timing"""
+// )
+//
+// tcl.flush();
+// tcl.close();
+//
+//
+// val xdc = new java.io.FileWriter(Paths.get(workspacePath,"doit.xdc").toFile)
+// xdc.write(s"""create_clock -period ${(targetPeriod*1e9) toBigDecimal} [get_ports clk]""")
+//
+// xdc.flush();
+// xdc.close();
+//
+// doCmd(s"$vivadoPath/vivado -nojournal -log doit.log -mode batch -source doit.tcl", workspacePath)
+//
+// new Report{
+// override def getFMax(): Double = {
+// import scala.io.Source
+// val report = Source.fromFile(Paths.get(workspacePath,"doit.log").toFile).getLines.mkString
+// val intFind = "-?(\\d+\\.?)+".r
+// val slack = try {
+// (family match {
+// case "Artix 7" =>
+// intFind.findFirstIn("-?(\\d+.?)+ns \\(required time - arrival time\\)".r.findFirstIn(report).get).get
+// }).toDouble
+// }catch{
+// case e : Exception => -1.0
+// }
+// return 1.0/(targetPeriod.toDouble-slack*1e-9)
+// }
+// override def getArea(): String = {
+// import scala.io.Source
+// val report = Source.fromFile(Paths.get(workspacePath,"doit.log").toFile).getLines.mkString
+// val intFind = "(\\d+,?)+".r
+// val leArea = try {
+// family match {
+// case "Artix 7" =>
+// intFind.findFirstIn("Slice LUTs[ ]*\\|[ ]*(\\d+,?)+".r.findFirstIn(report).get).get + " LUT " +
+// intFind.findFirstIn("Slice Registers[ ]*\\|[ ]*(\\d+,?)+".r.findFirstIn(report).get).get + " FF "
+// }
+// }catch{
+// case e : Exception => "???"
+// }
+// return leArea
+// }
+// }
+ }
+
+ def main(args: Array[String]) {
+// SpinalVerilog(StreamFifo(Bits(8 bits), 64))
+// val report = IcestormFlow(
+// workspacePath="/home/spinalvm/tmp",
+// toplevelPath="StreamFifo.v",
+// family="iCE40",
+// device="hx8k",
+// pack = "ct256"
+// )
+// println(report.getArea())
+// println(report.getFMax())
+// }
+ SpinalVerilog(StreamFifo(Bits(8 bits), 64))
+ val report = IcestormFlow(
+ workspacePath="/media/miaou/HD/linux/tmp",
+ toplevelPath="StreamFifo.v",
+ family="iCE40",
+ device="up5k",
+ pack = "sg48"
+ )
+ println(report.getArea())
+ println(report.getFMax())
+ }
+}
+
+object IcestormStdTargets {
+ def apply(): Seq[Target] = {
+ val targets = ArrayBuffer[Target]()
+ targets += new Target {
+ override def getFamilyName(): String = "iCE40"
+ override def synthesise(rtl: Rtl, workspace: String): Report = {
+ IcestormFlow(
+ workspacePath=workspace,
+ toplevelPath=rtl.getRtlPath(),
+ family=getFamilyName(),
+ device="hx8k",
+ pack = "ct256"
+ )
+ }
+ }
+
+ targets += new Target {
+ override def getFamilyName(): String = "iCE40Ultra"
+ override def synthesise(rtl: Rtl, workspace: String): Report = {
+ IcestormFlow(
+ workspacePath=workspace,
+ toplevelPath=rtl.getRtlPath(),
+ family=getFamilyName(),
+ device="up5k",
+ pack = "sg48"
+ )
+ }
+ }
+ targets
+ }
+} \ No newline at end of file