Skip to content

Commit

Permalink
add mixed-hdl/blink
Browse files Browse the repository at this point in the history
  • Loading branch information
umarcor committed Oct 12, 2020
1 parent da3c13e commit 18c236d
Show file tree
Hide file tree
Showing 9 changed files with 412 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ The contents of this workshop is published at [workshop.fomu.im](https://worksho
of the workshop](https://workshop.fomu.im/en/latest/verilog.html).
- [vhdl](./vhdl) - The files required for the [VHDL on Fomu section
of the workshop](https://workshop.fomu.im/en/latest/vhdl.html).
- [mixed-hdl](./mixed-hdl) - The files required for the [Mixed HDL on Fomu section
of the workshop](https://workshop.fomu.im/en/latest/mixedhdl.html).

# Development

Expand Down
1 change: 1 addition & 0 deletions docs/hdl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ Languages and generators

verilog
vhdl
mixed-hdl
migen
89 changes: 89 additions & 0 deletions docs/mixed-hdl.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
.. _HDLs:mixed:

Mixed HDL on Fomu
-----------------

.. IMPORTANT:: The pre-built toolchain we publish does not include `GHDL <https://github.com/ghdl>`_
yet. These examples use `open-tool-forge/fpga-toolchain <https://github.com/open-tool-forge/fpga-toolchain>`_
instead. The installation procedure does not change: retrieve the package
for your platform, extract it, and add it to the PATH.
Note that the set of tools used for synthesis and P&R is the same: Yosys
and nextpnr. It's just a different packaging which includes GHDL too.
There is work in progress for including *fpga-toolchain* in *Fomu toolchain*
(see `im-tomu/fomu-toolchain#20 <https://github.com/im-tomu/fomu-toolchain/pull/20>`_).

.. HINT:: It is strongly suggested to get familiar with :ref:`HDLs:Verilog` and :ref:`HDLs:VHDL`
examples before tinkering with these mixed language use cases.


“Hello world!” - Blink a LED
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The canonical “Hello, world!” of hardware is to blink a LED. The
directory ``mixedhdl/blink`` contains a VHDL + Verilog example of a blink
project. This takes the 48 MHz clock and divides it down by a large
number so you get an on/off pattern.

Enter the ``mixedhdl/blink`` directory and build the demo by using ``make``:

.. session:: shell-session

$ make FOMU_REV=$FOMU_REV
...
Info: Max frequency for clock 'clk_generator.clko': 73.26 MHz (PASS at 12.00 MHz)

Info: Max delay posedge clk_generator.clko -> <async>: 3.15 ns

Info: Slack histogram:
Info: legend: * represents 1 endpoint(s)
Info: + represents [1,1) endpoint(s)
Info: [ 69683, 70208) |**
Info: [ 70208, 70733) |
Info: [ 70733, 71258) |**
Info: [ 71258, 71783) |**
Info: [ 71783, 72308) |**
Info: [ 72308, 72833) |**
Info: [ 72833, 73358) |
Info: [ 73358, 73883) |**
Info: [ 73883, 74408) |*
Info: [ 74408, 74933) |**
Info: [ 74933, 75458) |**
Info: [ 75458, 75983) |*
Info: [ 75983, 76508) |*
Info: [ 76508, 77033) |**
Info: [ 77033, 77558) |**
Info: [ 77558, 78083) |*
Info: [ 78083, 78608) |
Info: [ 78608, 79133) |*************************
Info: [ 79133, 79658) |**
Info: [ 79658, 80183) |***
22 warnings, 0 errors
icepack blink.asc blink.bit
cp blink.bit blink.dfu
dfu-suffix -v 1209 -p 70b1 -a blink.dfu
dfu-suffix (dfu-util) 0.9
Copyright 2011-2012 Stefan Schmidt, 2013-2014 Tormod Volden
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

Suffix successfully added to file
$

You can then load ``blink.dfu`` onto Fomu by using ``make load`` or the same
``dfu-util -D`` command we’ve been using so far. You should see a blinking pattern of
varying color on your Fomu, indicating your bitstream was successfully loaded.

If you take a closer look at the sources in ``mixedhdl/blink``, you will find that
modules/components ``blink`` and ``clkgen`` are written both in VHDL and Verilog.
The Makefile uses ``blink.vhd`` and ``clkgen.v`` by default. However, any of the
following cases produce the same result:

- ``blink.vhd`` + ``clkgen.v``
- ``blink.v`` + ``clkgen.vhdl``
- ``blink.vhd`` + ``clkgen.vhdl``
- ``blink.v`` + ``clkgen.v``

You can modify variables `VHDL_SYN_FILES` and ``VERILOG_SYN_FILES`` in the Makefile
for trying other combinations. For a better understanding, it is suggested to compare
these modules with the single file solutions in :ref:`HDLs:Verilog` and :ref:`HDLs:VHDL`.
84 changes: 84 additions & 0 deletions mixed-hdl/blink/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Different Fomu hardware revisions are wired differently and thus
# require different configurations for yosys and nextpnr.
# Configuration is performed by setting the environment variable FOMU_REV accordingly.
ifeq ($(FOMU_REV),evt1)
YOSYSFLAGS?= -D EVT=1
PNRFLAGS ?= --up5k --package sg48 --pcf ../../pcf/fomu-evt2.pcf
else ifeq ($(FOMU_REV),evt2)
YOSYSFLAGS?= -D EVT=1
PNRFLAGS ?= --up5k --package sg48 --pcf ../../pcf/fomu-evt2.pcf
else ifeq ($(FOMU_REV),evt3)
YOSYSFLAGS?= -D EVT=1
PNRFLAGS ?= --up5k --package sg48 --pcf ../../pcf/fomu-evt3.pcf
else ifeq ($(FOMU_REV),hacker)
YOSYSFLAGS?= -D HACKER=1
PNRFLAGS ?= --up5k --package uwg30 --pcf ../../pcf/fomu-hacker.pcf
else ifeq ($(FOMU_REV),pvt)
YOSYSFLAGS?= -D PVT=1
PNRFLAGS ?= --up5k --package uwg30 --pcf ../../pcf/fomu-pvt.pcf
else
$(error Unrecognized FOMU_REV value. must be "evt1", "evt2", "evt3", "pvt", or "hacker")
endif

GHDL ?= ghdl
GHDL_FLAGS += --std=08

# VHDL top with instantiated Verilog
VHDL_SYN_FILES = ../../vhdl/sb_ice40_components.vhd blink.vhd
VERILOG_SYN_FILES = clkgen.v

# Verilog top with instantiated VHDL
#VHDL_SYN_FILES = ../../vhdl/sb_ice40_components.vhd clkgen.vhd
#VERILOG_SYN_FILES = blink.v

GHDL = ghdl
GHDLSYNTH = ghdl
YOSYS = yosys
NEXTPNR = nextpnr-ice40
ICEPACK = icepack

# Default target: run all required targets to build the DFU image.
all: blink.dfu
@true

.DEFAULT: all

## Use *Yosys* to generate the synthesized netlist.
## This is called the **synthesis** and **tech mapping** step.
blink.json: $(VHDL_SYN_FILES) $(VERILOG_SYN_FILES)
$(YOSYS) $(YOSYSFLAGS) \
-p \
"$(GHDLSYNTH) $(GHDL_FLAGS) $(VHDL_SYN_FILES) -e; \
synth_ice40 \
-top Fomu_Blink \
-json $@" -q $(VERILOG_SYN_FILES) 2>&1 | tee yosys-report.txt

# Use **nextpnr** to generate the FPGA configuration.
# This is called the **place** and **route** step.
blink.asc: blink.json
$(NEXTPNR) \
$(PNRFLAGS) \
--json $< \
--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) $< $@

# Use dfu-suffix to generate the DFU image from the FPGA bitstream.
blink.dfu: blink.bit
cp $< $@
dfu-suffix -v 1209 -p 70b1 -a $@

# Use df-util to load the DFU image onto the Fomu.
load: blink.dfu
dfu-util -D $<

.PHONY: load

# Cleanup the generated files.
clean:
rm -fr *.cf *.json *-report.txt *.asc *.bit *.dfu

.PHONY: clean
22 changes: 22 additions & 0 deletions mixed-hdl/blink/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Minimal Mixed HDL Example (VHDL and Verilog)

A minimal mixed HDL example which simply blinks the RGB LEDs at different
frequencies.

This example contains equivalent sources in VHDL and Verilog, which can be
combined freely:

- `blink.vhd` + `clkgen.v`
- `blink.v` + `clkgen.vhdl`
- `blink.vhd` + `clkgen.vhdl`
- `blink.v` + `clkgen.v`

All four cases produce exactly the same result, because the same design is
described regardless of the HDL language used. In the makefile, the first
case is built by default.

## Using

Type `make` to build the DFU image.
Type `make load` to load the DFU image onto the Fomu board.
Type `make clean` to remove all the generated files.
77 changes: 77 additions & 0 deletions mixed-hdl/blink/blink.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Simple tri-colour LED blink example.

// Correctly map pins for the iCE40UP5K SB_RGBA_DRV hard macro.
// The variables EVT, PVT and HACKER are set from the Makefile.
`ifdef EVT
`define BLUEPWM RGB0PWM
`define REDPWM RGB1PWM
`define GREENPWM RGB2PWM
`elsif HACKER
`define BLUEPWM RGB0PWM
`define GREENPWM RGB1PWM
`define REDPWM RGB2PWM
`elsif PVT
`define GREENPWM RGB0PWM
`define REDPWM RGB1PWM
`define BLUEPWM RGB2PWM
`else
`error_board_not_supported
`endif

module Fomu_Blink (
// 48MHz Clock input
// --------
input clki,
// LED outputs
// --------
output rgb0,
output rgb1,
output rgb2,
// USB Pins (which should be statically driven if not being used).
// --------
output usb_dp,
output usb_dn,
output usb_dp_pu
);

// Assign USB pins to "0" so as to disconnect Fomu from
// the host system. Otherwise it would try to talk to
// us over USB, which wouldn't work since we have no stack.
assign usb_dp = 1'b0;
assign usb_dn = 1'b0;
assign usb_dp_pu = 1'b0;

wire [2:0] color;

// Instantiate clkgen for reducing the system clock
clkgen clk_generator (
.clk(clki),
.cnt(color)
);

// Instantiate iCE40 LED driver hard logic, connecting up
// counter state and LEDs.
//
// Note that it's possible to drive the LEDs directly,
// however that is not current-limited and results in
// overvolting the red LED.
//
// See also:
// https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/IK/ICE40LEDDriverUsageGuide.ashx?document_id=50668
SB_RGBA_DRV #(
.CURRENT_MODE("0b1"), // half current
.RGB0_CURRENT("0b000011"), // 4 mA
.RGB1_CURRENT("0b000011"), // 4 mA
.RGB2_CURRENT("0b000011") // 4 mA
) RGBA_DRIVER (
.CURREN(1'b1),
.RGBLEDEN(1'b1),
.`BLUEPWM(color[2]), // Blue
.`REDPWM(color[1]), // Red
.`GREENPWM(color[0]), // Green
.RGB0(rgb0),
.RGB1(rgb1),
.RGB2(rgb2)
);

endmodule
78 changes: 78 additions & 0 deletions mixed-hdl/blink/blink.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
library ieee;
context ieee.ieee_std_context;

use work.components.all;

entity Fomu_Blink is
port (
-- 48MHz Clock input
clki: in std_logic;

-- LED outputs
rgb0: out std_logic;
rgb1: out std_logic;
rgb2: out std_logic;

-- USB Pins (which should be statically driven if not being used)
usb_dp: out std_logic;
usb_dn: out std_logic;
usb_dp_pu: out std_logic
);
end;

architecture arch of Fomu_Blink is

signal clk: std_logic;
signal color: std_logic_vector(2 downto 0) := (others=>'0');

component clkgen
port (
clk: in std_logic;
cnt: out std_logic_vector(2 downto 0)
);
end component;

begin

-- Assign USB pins to "0" so as to disconnect Fomu from
-- the host system. Otherwise it would try to talk to
-- us over USB, which wouldn't work since we have no stack.
usb_dp <= '0';
usb_dn <= '0';
usb_dp_pu <= '0';

-- Instantiate clkgen for reducing the system clock
clk_generator: component clkgen
port map (
clk => clki,
cnt => color
);

-- Instantiate iCE40 LED driver hard logic, connecting up
-- counter state and LEDs.
--
-- Note that it's possible to drive the LEDs directly,
-- however that is not current-limited and results in
-- overvolting the red LED.
--
-- See also:
-- https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/IK/ICE40LEDDriverUsageGuide.ashx?document_id=50668
rgba_driver: SB_RGBA_DRV
generic map (
CURRENT_MODE => "0b1", -- half current
RGB0_CURRENT => "0b000011", -- 4 mA
RGB1_CURRENT => "0b000011", -- 4 mA
RGB2_CURRENT => "0b000011" -- 4 mA
)
port map (
CURREN => '1',
RGBLEDEN => '1',
RGB0PWM => color(2),
RGB1PWM => color(1),
RGB2PWM => color(0),
RGB0 => rgb0,
RGB1 => rgb1,
RGB2 => rgb2
);

end;
21 changes: 21 additions & 0 deletions mixed-hdl/blink/clkgen.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module clkgen (
input wire clk,
output wire [2:0] cnt
);

// Connect to system clock (with buffering)
wire clko;
SB_GB clk_gb (
.USER_SIGNAL_TO_GLOBAL_BUFFER(clk),
.GLOBAL_BUFFER_OUTPUT(clko)
);

// Use counter logic to divide system clock. The clock is 48 MHz,
// so we divide it down by 2^28.
reg [28:0] counter = 0;
always @(posedge clko) begin
counter <= counter + 1;
end
assign cnt = counter[25:23];

endmodule
Loading

0 comments on commit 18c236d

Please sign in to comment.