add vhdl/blink

This commit is contained in:
umarcor 2020-10-05 08:38:33 +02:00
parent 2776953012
commit 21bcde2bd3
9 changed files with 309 additions and 27 deletions

10
.github/tests.sh vendored
View File

@ -7,6 +7,16 @@ echo "TOOLCHAIN_PATH: $TOOLCHAIN_PATH"
export PATH=$TOOLCHAIN_PATH/bin:$PATH
echo '::group::VHDL Blink example'
(
set -x
cd vhdl/blink
make FOMU_REV=pvt
file blink.dfu
)
echo '::endgroup::'
echo '::group::RISC-V C Example'
(
set -x

View File

@ -42,6 +42,8 @@ The contents of this workshop is published at [workshop.fomu.im](https://worksho
CPU section of the workshop](https://workshop.fomu.im/en/latest/riscv.html).
- [verilog](./verilog) - The files required for the [Verilog on Fomu section
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).
# Development

View File

@ -5,10 +5,40 @@ The two most common **H**\ ardware **D**\ escription **L**\ anguages are
Verilog and VHDL.
.. NOTE:: The pre-built toolchain we are releasing supports Verilog only.
However, `GHDL <https://github.com/ghdl>`_ might be used as a VHDL frontend
However, `GHDL <https://github.com/ghdl>`_ can be usable as a VHDL frontend
for Yosys. See `ghdl-yosys-plugin <https://github.com/ghdl/ghdl-yosys-plugin>`_.
When writing HDL, a tool called ``yosys`` is used to convert the
human readable verilog into a netlist representation, this is called
*synthesis*. Once we have the netlist representation, a tool called
``nextpnr`` performs an operation called *place and route* (P&R) which
makes it something that will actually run on the FPGA. This is all
done for you using the ``Makefiles`` in the subdirectories of ``verilog``
or ``vhdl``.
A big feature of ``nextpnr`` over its predecessor, is the fact that
it is timing-driven. This means that a design will be generated with
a given clock domain guaranteed to perform fast enough.
When the ``make`` command runs ``nextpnr-ice40`` you will see something
similar included in the output:
::
Info: Max frequency for clock 'clk': 73.26 MHz (PASS at 12.00 MHz)
This output example shows that we could run ``clk`` at up to 73.26
MHz and it would still be stable (even though we only requested 12.00
MHz). Note that there is some variation between designs depending on
how the placer and router decided to lay things out, so your exact
frequency numbers might be different from the ones shown in the code
blocks of this documentation.
Languages and generators
========================
.. toctree::
verilog
vhdl
migen

View File

@ -11,8 +11,7 @@ number so you get an on/off pattern.
Enter the ``verilog/blink`` directory and build the demo by using ``make``:
**Make sure you set the ``FOMU_REV`` value to match your hardware! See
the Required Hardware section.**
**Make sure you set the** ``FOMU_REV`` **value to match your hardware!** See :ref:`required-hardware`.
.. session:: shell-session
@ -62,30 +61,6 @@ You can then load ``blink.dfu`` onto Fomu by using the same ``dfu-util -D``
command weve been using so far. You should see a blinking pattern of
varying color on your Fomu, indicating your bitstream was successfully loaded.
When writing HDL, a tool called ``yosys`` is used to convert the
human readable verilog into a netlist representation, this is called
synthesis. Once we have the netlist representation a tool called
``nextpnr`` performs an operation called “place and route” which
makes it something that will actually run on the FPGA. This is all
done for you using the ``Makefile`` in the ``verilog/blink``
directory.
A big feature of ``nextpnr`` over its predecessor, is the fact that
it is timing-driven. This means that a design will be generated with
a given clock domain guaranteed to perform fast enough.
When the ``make`` command runs ``nextpnr-ice40`` you will see something
similar included in the output:
::
Info: Max frequency for clock 'clk': 73.26 MHz (PASS at 12.00 MHz)
This output example shows that we could run ``clk`` at up to 73.26
MHz and it would still be stable, even though we only requested 12.00
MHz. Note that there is some variation between designs depending on
how the placer and router decided to lay things out, so your exact
frequency numbers might be different.
Reading Input
^^^^^^^^^^^^^

67
docs/vhdl.rst Normal file
View File

@ -0,0 +1,67 @@
VHDL on Fomu
------------
.. HINT:: Component declarations for instantiating hard cores (such as the
ones in ``sb_ice40_components.vhd``) are found in the installation of
`iCEcube2 <http://www.latticesemi.com/iCEcube2>`_.
“Hello world!” - Blink a LED
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The canonical “Hello, world!” of hardware is to blink a LED. The
directory ``vhdl/blink`` contains a VHDL 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 ``vhdl/blink`` directory and build the demo by using ``make``:
**Make sure you set the** ``FOMU_REV`` **value to match your hardware!** See :ref:`required-hardware`.
.. session:: shell-session
$ make FOMU_REV=$FOMU_REV
...
Info: Max frequency for clock 'clk': 70.39 MHz (PASS at 12.00 MHz)
Info: Max delay posedge clk -> <async>: 3.15 ns
Info: Slack histogram:
Info: legend: * represents 1 endpoint(s)
Info: + represents [1,1) endpoint(s)
Info: [ 69127, 69680) |**
Info: [ 69680, 70233) |**
Info: [ 70233, 70786) |
Info: [ 70786, 71339) |**
Info: [ 71339, 71892) |**
Info: [ 71892, 72445) |**
Info: [ 72445, 72998) |**
Info: [ 72998, 73551) |
Info: [ 73551, 74104) |**
Info: [ 74104, 74657) |**
Info: [ 74657, 75210) |**
Info: [ 75210, 75763) |**
Info: [ 75763, 76316) |
Info: [ 76316, 76869) |**
Info: [ 76869, 77422) |**
Info: [ 77422, 77975) |**
Info: [ 77975, 78528) |
Info: [ 78528, 79081) |***************************
Info: [ 79081, 79634) |**
Info: [ 79634, 80187) |***
22 warnings, 0 errors
docker run --rm -v //t/fomu/fomu-workshop/vhdl/blink/../..://src -w //src/vhdl/blink ghdl/synth:icestorm 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 weve been using so far. You should see a blinking pattern of
varying color on your Fomu, indicating your bitstream was successfully loaded.

76
vhdl/blink/Makefile Normal file
View File

@ -0,0 +1,76 @@
# 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
VHDL_SYN_FILES = ../sb_ice40_components.vhd blink.vhd
GHDL_FLAGS += --std=08
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)
$(YOSYS) $(YOSYSFLAGS) \
-p \
"$(GHDLSYNTH) $(GHDL_FLAGS) $^ -e; \
synth_ice40 \
-top Fomu_Blink \
-json $@" 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

10
vhdl/blink/README.md Normal file
View File

@ -0,0 +1,10 @@
# Minimal VHDL Example
A minimal VHDL example which simply blinks the RGB LEDs at different
frequencies.
## 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.

80
vhdl/blink/blink.vhd Normal file
View File

@ -0,0 +1,80 @@
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 counter: unsigned(27 downto 0) := (others=>'0');
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';
-- Connect to system clock (with buffering)
clk_gb: SB_GB
port map (
USER_SIGNAL_TO_GLOBAL_BUFFER => clki,
GLOBAL_BUFFER_OUTPUT => clk
);
-- Use counter logic to divide system clock. The clock is 48 MHz,
-- so we divide it down by 2^28.
process(clk)
begin
if rising_edge(clk) then
counter <= counter + 1;
end if;
end process;
-- 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 => counter(counter'left),
RGB1PWM => counter(counter'left-1),
RGB2PWM => counter(counter'left-2),
RGB0 => rgb0,
RGB1 => rgb1,
RGB2 => rgb2
);
end;

View File

@ -0,0 +1,32 @@
library ieee ;
use ieee.std_logic_1164.all;
package components is
component SB_GB
port(
GLOBAL_BUFFER_OUTPUT : out std_logic;
USER_SIGNAL_TO_GLOBAL_BUFFER : in std_logic
);
end component;
component SB_RGBA_DRV
generic (
CURRENT_MODE : string := "0b0";
RGB0_CURRENT : string := "0b000000";
RGB1_CURRENT : string := "0b000000";
RGB2_CURRENT : string := "0b000000"
);
port (
RGB0PWM : in std_logic;
RGB1PWM : in std_logic;
RGB2PWM : in std_logic;
CURREN : in std_logic;
RGBLEDEN : in std_logic;
RGB0 : out std_logic;
RGB1 : out std_logic;
RGB2 : out std_logic
);
end component;
end components;