From 74a37475bafbe911604d163eb198171aa0918a21 Mon Sep 17 00:00:00 2001 From: Friedrich Beckmann Date: Sat, 28 Mar 2026 12:55:16 +0100 Subject: add quartus synthesis for top_simple --- README.md | 59 ++++++++++++++++++++++- build.mill | 61 +++++++++++++++++++++-- scripts/create_quartus_project_settings.tcl | 75 +++++++++++++++++++++++++++++ top_simple/pnr/top_simple.sdc | 1 + top_simple/pnr/top_simple_pins.tcl | 30 ++++++++++++ top_simple/src/Config.scala | 2 +- top_simple/src/top_simple.scala | 4 +- 7 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 scripts/create_quartus_project_settings.tcl create mode 100644 top_simple/pnr/top_simple.sdc create mode 100644 top_simple/pnr/top_simple_pins.tcl diff --git a/README.md b/README.md index 73a5267..28cecef 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,60 @@ # SoC Lab -This lab uses [SpinalHDL](https://spinalhdl.github.io/SpinalDoc-RTD/master/index.html) for the System-on-Chip course. \ No newline at end of file +This lab uses [SpinalHDL](https://spinalhdl.github.io/SpinalDoc-RTD/master/index.html) for the System-on-Chip course. The build system is based on [mill](https://mill-build.org). + +## How to use this + +The getting started module is "top_simple". The Scala source code is in "top_simple/src/top_simple.scala". The module directly uses the toplevel FPGA pins, i.e. no module hierachy. + +### Generate VHDL from Scala + +``` +mill top_simple.generateVhdl +``` + +This generates the VHDL file from top_simple.scala. As the VHDL file is generated, mill stores it +in "out/top_simple/generateVhdl.dest/top_simple.vhd". + +### Generate a Quartus project file and open Quartus GUI + +The Quartus project file "top_simple.qpf" contains the project definitions for synthesis +like the vhdl source file, pin definitions, FPGA device and some other settings. + +``` +mill top_simple.quartusgui +``` +This will + + * Generate the VHDL file from the scala file + * Build a Quartus Project File (top_simple.qpf) + * Open the Quartus GUI with that project file + +The quartus project directory is generated and located at "out/top_simple/qproject.dest" and contains the "top_simple.qpf" file. + +### Run the Quartus synthesis and create the .sof file + +The .sof file is the "SRAM-object file" which contains the FPGA configuration for the Intel/Altera FPGA. That will then be downloaded to the FPGA with the USB-Blaster programmer. + +``` +mill top_simple.synthesis +``` + +This will take the following files + + * Generated VHDL file + * Generated Quartus Project file "top_simple.qpf" + * SDC file in "top_simple/pnr/top_simple.sdc" + * Pin Configuration file in "top_simple/pnr/top_simple_pins.tcl" + +and produce the top_simple.sof file in "out/top_simple/qproject.dest" + +### Program the FPGA with USB-Blaster + +``` +mill top_simple.prog +``` + +This will take the .sof file and download it to the FPGA. You need to attach the USB cable +to the FPGA board for this to work. Make sure that the usb device is visible inside your +virtual machine if you run this in a virtual machine. + diff --git a/build.mill b/build.mill index 4b60b5f..5ccce1d 100644 --- a/build.mill +++ b/build.mill @@ -3,15 +3,70 @@ import mill._ import mill.scalalib._ -object top_simple extends ScalaModule { +trait SpinalModule extends ScalaModule { def scalaVersion = "2.13.14" - //override def sources = Task.Sources(moduleDir / os.up / "src") - override def mvnDeps = Seq( mvn"com.github.spinalhdl::spinalhdl-core:1.12.3", mvn"com.github.spinalhdl::spinalhdl-lib:1.12.3" ) override def scalacPluginMvnDeps = Seq(mvn"com.github.spinalhdl::spinalhdl-idsl-plugin:1.12.3") + + def generateVhdl: T[PathRef] = Task { + val name = moduleDir.last + val cp = runClasspath().map(_.path).mkString(java.io.File.pathSeparator) + os.proc("java", s"-DspinalTargetDir=${Task.dest}", "-cp", cp, s"$name.genvhdl") + .call(cwd = moduleDir / os.up, stdout = os.Inherit, stderr = os.Inherit) + PathRef(Task.dest / s"$name.vhd") + } + + def pinsFile: T[PathRef] = Task.Source(moduleDir / "pnr" / s"${moduleDir.last}_pins.tcl") + def sdcFile: T[PathRef] = Task.Source(moduleDir / "pnr" / s"${moduleDir.last}.sdc") + def qprojectScript: T[PathRef] = Task.Source(moduleDir / os.up / "scripts" / "create_quartus_project_settings.tcl") + + def qproject: T[PathRef] = Task { + val name = moduleDir.last + val vhdl = generateVhdl() + val pins = pinsFile() + val sdc = sdcFile() + val script = qprojectScript() + assert(os.exists(sdc.path), s"SDC file not found: ${sdc.path}") + os.proc("quartus_sh", + "--64bit", + "-t", script.path, + "-projectname", name, + "-vhdlfile", vhdl.path, + "-pinfile", pins.path, + "-sdcfile", sdc.path) + .call(cwd = Task.dest, stdout = os.Inherit, stderr = os.Inherit) + PathRef(Task.dest) + } + + def quartusgui() = Task.Command { + val name = moduleDir.last + val projectDir = qproject().path + os.proc("quartus", "--64bit", projectDir / s"$name.qpf") + .call(cwd = projectDir, stdout = os.Inherit, stderr = os.Inherit) + } + + def prog() = Task.Command { + val sof = synthesis().path + os.proc("quartus_pgm", + "--64bit", + "-c", "USB-Blaster", + "--mode", "jtag", + s"--operation=p;$sof") + .call(stdout = os.Inherit, stderr = os.Inherit) + } + + def synthesis: T[PathRef] = Task { + val name = moduleDir.last + val projectDir = qproject().path + os.proc("quartus_sh", "--64bit", "--flow", "compile", projectDir / s"$name.qpf") + .call(cwd = projectDir, stdout = os.Inherit, stderr = os.Inherit) + PathRef(projectDir / s"$name.sof") + } } + +object top_simple extends SpinalModule diff --git a/scripts/create_quartus_project_settings.tcl b/scripts/create_quartus_project_settings.tcl new file mode 100644 index 0000000..2f3b00f --- /dev/null +++ b/scripts/create_quartus_project_settings.tcl @@ -0,0 +1,75 @@ +## ---------------------------------------------------------------------------- +## Script : create_quartus_project_settings.tcl +## ---------------------------------------------------------------------------- +## Author : Johann Faerber, F. Beckmann +## Company : University of Applied Sciences Augsburg +## ---------------------------------------------------------------------------- +## Description: create a quartus project with default settings for device, +## unused pins, ... +## expects project name as command line parameter +## e.g. +## quartus_sh -t create_quartus_project_settings.tcl -projectname de1_mux2to1 +## --vhdlfile top_simple.vhd --pinfile top_simple.pins + +package require cmdline +# Load Quartus II Tcl Project package +package require ::quartus::project + +# ---------------------------------------------------------------------------- +# Declare command line parameters +# ---------------------------------------------------------------------------- +set parameters { + {projectname.arg "" "Project Name"} + {vhdlfile.arg "" "VHDL source file"} + {pinfile.arg "" "Pin Configuration File"} + {sdcfile.arg "" "Synopsys Designconstraints File"} +} +array set arg [::cmdline::getoptions argv $parameters] + +# ---------------------------------------------------------------------------- +# Verify required paramters +# ---------------------------------------------------------------------------- +set requiredParameters {projectname vhdlfile pinfile sdcfile} +foreach parameter $requiredParameters { + if {$arg($parameter) == ""} { + puts stderr "Missing required parameter: -$parameter" + exit 1 + } +} + + + # ---------------------------------------------------------------------------- + # Create project + # ---------------------------------------------------------------------------- + project_new $arg(projectname) -overwrite + + # ---------------------------------------------------------------------------- + # Assign family, device, and top-level file + # ---------------------------------------------------------------------------- + set_global_assignment -name FAMILY "Cyclone II" + set_global_assignment -name DEVICE EP2C20F484C7 + set_global_assignment -name SDC_FILE $arg(sdcfile) + + # ---------------------------------------------------------------------------- + # Default settings + # ---------------------------------------------------------------------------- + set_global_assignment -name USE_CONFIGURATION_DEVICE ON + set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" + set_global_assignment -name VHDL_INPUT_VERSION VHDL_2008 + + # ---------------------------------------------------------------------------- + # Design files + # ---------------------------------------------------------------------------- + #set_global_assignment -name VHDL_FILE ../src/e_cntdnmodm.vhd + set_global_assignment -name VHDL_FILE $arg(vhdlfile) + + # ---------------------------------------------------------------------------- + # Pin Assignments + # ---------------------------------------------------------------------------- + # set_location_assignment PIN_L1 -to CLOCK_50 + source $arg(pinfile) + + # ---------------------------------------------------------------------------- + # Close project + # ---------------------------------------------------------------------------- + project_close diff --git a/top_simple/pnr/top_simple.sdc b/top_simple/pnr/top_simple.sdc new file mode 100644 index 0000000..5ac173d --- /dev/null +++ b/top_simple/pnr/top_simple.sdc @@ -0,0 +1 @@ +create_clock -period 20.000 -name CLOCK_50 CLOCK_50 \ No newline at end of file diff --git a/top_simple/pnr/top_simple_pins.tcl b/top_simple/pnr/top_simple_pins.tcl new file mode 100644 index 0000000..2cad3cf --- /dev/null +++ b/top_simple/pnr/top_simple_pins.tcl @@ -0,0 +1,30 @@ +# assign pin locations to a quartus project + +set_location_assignment PIN_L22 -to SW[0] +set_location_assignment PIN_L21 -to SW[1] +set_location_assignment PIN_M22 -to SW[2] +set_location_assignment PIN_V12 -to SW[3] +set_location_assignment PIN_W12 -to SW[4] +set_location_assignment PIN_U12 -to SW[5] +set_location_assignment PIN_U11 -to SW[6] +set_location_assignment PIN_M2 -to SW[7] +set_location_assignment PIN_M1 -to SW[8] +set_location_assignment PIN_L2 -to SW[9] +set_location_assignment PIN_R20 -to LEDR[0] +set_location_assignment PIN_R19 -to LEDR[1] +set_location_assignment PIN_U19 -to LEDR[2] +set_location_assignment PIN_Y19 -to LEDR[3] +set_location_assignment PIN_T18 -to LEDR[4] +set_location_assignment PIN_V19 -to LEDR[5] +set_location_assignment PIN_Y18 -to LEDR[6] +set_location_assignment PIN_U18 -to LEDR[7] +set_location_assignment PIN_R18 -to LEDR[8] +set_location_assignment PIN_R17 -to LEDR[9] +set_location_assignment PIN_U22 -to LEDG[0] +set_location_assignment PIN_U21 -to LEDG[1] +set_location_assignment PIN_V22 -to LEDG[2] +set_location_assignment PIN_V21 -to LEDG[3] +set_location_assignment PIN_W22 -to LEDG[4] +set_location_assignment PIN_W21 -to LEDG[5] +set_location_assignment PIN_Y22 -to LEDG[6] +set_location_assignment PIN_Y21 -to LEDG[7] diff --git a/top_simple/src/Config.scala b/top_simple/src/Config.scala index dbfe54b..682d463 100644 --- a/top_simple/src/Config.scala +++ b/top_simple/src/Config.scala @@ -5,7 +5,7 @@ import spinal.core.sim._ object Config { def spinal = SpinalConfig( - targetDirectory = "top_simple/gen", + targetDirectory = sys.props.getOrElse("spinalTargetDir", "top_simple/gen"), defaultConfigForClockDomains = ClockDomainConfig( resetActiveLevel = HIGH ), diff --git a/top_simple/src/top_simple.scala b/top_simple/src/top_simple.scala index ec43fe8..1f8756f 100644 --- a/top_simple/src/top_simple.scala +++ b/top_simple/src/top_simple.scala @@ -18,10 +18,10 @@ case class top_simple() extends Component { } // The following defines the vhdl and verilog code generation -object verilog extends App { +object genverilog extends App { Config.spinal.generateVerilog(top_simple()) } -object vhdl extends App { +object genvhdl extends App { Config.spinal.generateVhdl(top_simple()) } -- cgit v1.2.3