aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFriedrich Beckmann <friedrich.beckmann@tha.de>2026-03-28 12:55:16 +0100
committerFriedrich Beckmann <friedrich.beckmann@tha.de>2026-03-28 13:00:23 +0100
commit74a37475bafbe911604d163eb198171aa0918a21 (patch)
tree3625965e90ed703449492690b294532ea69f9950
parent9d8b7ca4eaf712a3251f985fd1e93a0f0e568c16 (diff)
add quartus synthesis for top_simple
-rw-r--r--README.md59
-rw-r--r--build.mill61
-rw-r--r--scripts/create_quartus_project_settings.tcl75
-rw-r--r--top_simple/pnr/top_simple.sdc1
-rw-r--r--top_simple/pnr/top_simple_pins.tcl30
-rw-r--r--top_simple/src/Config.scala2
-rw-r--r--top_simple/src/top_simple.scala4
7 files changed, 225 insertions, 7 deletions
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())
}