diff --git a/chisel/blink/.gitignore b/chisel/blink/.gitignore new file mode 100644 index 0000000..b44c6b1 --- /dev/null +++ b/chisel/blink/.gitignore @@ -0,0 +1,17 @@ +# Verilog/SystemVerilog generated from src/Blink.scala +/Blink.sv +/Blink.v +# Annotations for the firrtl compiler, also generated from src/Blink.scala +/Blink.anno.json +# Intermediate representation of the circuit generated from src/Blink.scala +/Blink.fir +# IntelliJ IDE folder +/.idea/ +# Scala build artifacts +target/ + +# same as for the verilog example +blink.json +blink.asc +blink.bit +blink.dfu diff --git a/chisel/blink/Makefile b/chisel/blink/Makefile new file mode 100644 index 0000000..5fa2271 --- /dev/null +++ b/chisel/blink/Makefile @@ -0,0 +1,63 @@ +# Simple Fomu Makefile +# -------------------- +# This Makefile shows the steps to generate a DFU loadable image onto +# Fomu hacker board. + +include ../../board.mk + +# Default target: run all required targets to build the DFU image. +all: blink.dfu + @true + +.DEFAULT: all + +# Call sbt to generate the Blink.sv from Chisel. +# Please note that in general, it is a lot faster to +# start `sbt` once and then to run `run` on the `sbt` +# command line every time you want to rebuild the verilog. +# Unfortunately `sbt` start up times are notoriously bad :( +Blink.sv: src/Blink.scala build.sbt + sbt "run $(FOMU_REV)" + +# Use *Yosys* to generate the synthesized netlist. +# This is called the **synthesis** and **tech mapping** step. +blink.json: Blink.sv + yosys \ + $(YOSYSFLAGS) \ + -p 'synth_ice40 -top Blink -json blink.json' Blink.sv + +# Use **nextpnr** to generate the FPGA configuration. +# This is called the **place** and **route** step. +blink.asc: blink.json + nextpnr-ice40 \ + $(PNRFLAGS) \ + --json blink.json \ + --asc blink.asc + +# Use icepack to convert the FPGA configuration into a "bitstream" loadable onto the FPGA. +# This is called the bitstream generation step. +blink.bit: blink.asc + icepack blink.asc blink.bit + +# Use dfu-suffix to generate the DFU image from the FPGA bitstream. +blink.dfu: blink.bit + cp blink.bit blink.dfu + dfu-suffix -v 1209 -p 70b1 -a blink.dfu + +# Use df-util to load the DFU image onto the Fomu. +load: blink.dfu + dfu-util -D blink.dfu + +.PHONY: load + +# Cleanup the generated files. +clean: + -rm -f Blink.fir + -rm -f Blink.anno.json + -rm -f Blink.sv + -rm -f blink.json # Generate netlist + -rm -f blink.asc # FPGA configuration + -rm -f blink.bit # FPGA bitstream + -rm -f blink.dfu # DFU image loadable onto the Fomu + +.PHONY: clean diff --git a/chisel/blink/build.sbt b/chisel/blink/build.sbt new file mode 100644 index 0000000..c782a1b --- /dev/null +++ b/chisel/blink/build.sbt @@ -0,0 +1,6 @@ +name := "fomu-blink" +version := "0.1" +scalaVersion := "2.12.8" +libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.4.0" +scalaSource in Compile := baseDirectory.value / "src" +scalaSource in Test := baseDirectory.value / "test" diff --git a/chisel/blink/project/build.properties b/chisel/blink/project/build.properties new file mode 100644 index 0000000..0837f7a --- /dev/null +++ b/chisel/blink/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.3.13 diff --git a/chisel/blink/src/Blink.scala b/chisel/blink/src/Blink.scala new file mode 100644 index 0000000..c1e5ddd --- /dev/null +++ b/chisel/blink/src/Blink.scala @@ -0,0 +1,83 @@ +import chisel3._ +import chisel3.experimental._ +import chisel3.stage.ChiselStage +import firrtl.annotations.PresetAnnotation + +class Blink(rev: String) extends RawModule { + val clki = IO(Input(Clock())) + + val rgb0 = IO(Output(Bool())) + val rgb1 = IO(Output(Bool())) + val rgb2 = IO(Output(Bool())) + + val usb_dp = IO(Output(Bool())) + val usb_dn = IO(Output(Bool())) + val usb_dp_pu = IO(Output(Bool())) + usb_dp := false.B + usb_dn := false.B + usb_dp_pu := false.B + + // initialize registers to their reset value when the bitstream is programmed since there is no reset wire + val reset = IO(Input(AsyncReset())) + annotate(new ChiselAnnotation { + override def toFirrtl = PresetAnnotation(reset.toTarget) + }) + + // clock buffer + val clk_gb = Module(new SB_GB) + clk_gb.USER_SIGNAL_TO_GLOBAL_BUFFER := clki + val clk = clk_gb.GLOBAL_BUFFER_OUTPUT + + // led driver + val leds = Module(new SB_RGBA_DRV) + leds.CURREN := true.B + leds.RGBLEDEN := true.B + rgb0 := leds.RGB0 + rgb1 := leds.RGB1 + rgb2 := leds.RGB2 + + + // Now that we have set up the clock and reset, we define a scope + // in which all registers and modules will automatically use it. + chisel3.withClockAndReset(clk, reset) { + val (red, green, blue) = rev.toLowerCase match { + case "hacker" => (leds.RGB2PWM, leds.RGB1PWM, leds.RGB0PWM) + case "pvt" => (leds.RGB1PWM, leds.RGB0PWM, leds.RGB2PWM) + case other => throw new RuntimeException(s"Unsupported device: $other") + } + + val counter = RegInit(0.U(26.W)) + counter := counter + 1.U + + red := counter(24) + green := counter(23) + blue := counter(25) + } +} + +class SB_GB extends ExtModule { + val USER_SIGNAL_TO_GLOBAL_BUFFER = IO(Input(Clock())) + val GLOBAL_BUFFER_OUTPUT = IO(Output(Clock())) +} + +class SB_RGBA_DRV extends ExtModule(Map( + "CURRENT_MODE" -> "0b0", + "RGB0_CURRENT" -> "0b000011", + "RGB1_CURRENT" -> "0b000011", + "RGB2_CURRENT" -> "0b000011", +)) { + val CURREN = IO(Input(Bool())) + val RGBLEDEN = IO(Input(Bool())) + val RGB0PWM = IO(Input(Bool())) + val RGB1PWM = IO(Input(Bool())) + val RGB2PWM = IO(Input(Bool())) + val RGB0 = IO(Output(Bool())) + val RGB1 = IO(Output(Bool())) + val RGB2 = IO(Output(Bool())) +} + +// This main function reads in the version (pvt or hacker) and generates SystemVerilog from our Chisel design. +object VerilogGenerator extends App { + val rev = args.headOption.getOrElse("pvt") + (new ChiselStage).emitSystemVerilog(new Blink(rev)) +} \ No newline at end of file