-
Notifications
You must be signed in to change notification settings - Fork 56
Example: Blink LEDs
This is an in depth break down of a blinking LED example design to show the PipelineC tool flow.
This example is from a series of examples designed for the Arty Board.
// Use the switches to control LED blink rate
#include "uintN_t.h"
// Each main function is a clock domain
// Only one clock in the design for now 'sys_clk' @ 100MHz
#pragma MAIN_MHZ sys_clk_main 100.0
#pragma PART "xc7a35ticsg324-1l" // xc7a35ticsg324-1l = Arty, xcvu9p-flgb2104-2-i = AWS F1
// Make structs that wrap up the inputs and outputs
typedef struct sys_clk_main_inputs_t
{
// The switches
uint4_t sw;
} sys_clk_main_inputs_t;
typedef struct sys_clk_main_outputs_t
{
// The LEDs
uint1_t led[4];
} sys_clk_main_outputs_t;
// Blinking means turn on LED for some amount of time, and then turn off
// How much time?
#define BLINK_CLK_CYCLES 10000000
// The switch value, ex. sw[3:0] = 0b1101 = 13
// multiplies the above constant to determine actual blink rate
// Ex. 10000000*13 = 130000000 cycles, 100MHz = 10ns per clock, 130000000 * 10ns = 1.3 sec
// We need to count up to whatever sw*BLINK_CLK_CYCLES equals
uint28_t counter; // Inits to zero
// And we need to remember if the LEDs are on or not - so we know what to do next
uint1_t leds_on;
// The sys_clk_main function
sys_clk_main_outputs_t sys_clk_main(sys_clk_main_inputs_t inputs)
{
// Do what counters do, increment
counter = counter + 1;
// If the counter equals or greater then
// time to toggle the led and reset counter
if(counter >= (inputs.sw * BLINK_CLK_CYCLES))
{
leds_on = !leds_on;
counter = 0;
}
// Drive output leds (all 4)
sys_clk_main_outputs_t outputs;
outputs.led[0] = leds_on;
outputs.led[1] = leds_on;
outputs.led[2] = leds_on;
outputs.led[3] = leds_on;
return outputs;
}The compiler produces a text representation of what operations occur at which point during the pipeline (i.e. how long each operation takes and when). Inputs flow from top to bottom. Functions listed on the same lines are occurring in parallel.
Synthesizing function: sys_clk_main
Pipeline Map:
0: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
1: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
2: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
3: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
4: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
5: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
6: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
7: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
8: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
9: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
10: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
11: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]', 'UNARY_OP_NOT[blink_c_l44_c20_f44b]']
12: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
13: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
14: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
15: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
16: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
17: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
18: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
19: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
20: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
21: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
22: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
23: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
24: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
25: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
26: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
27: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
28: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
29: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
30: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
31: ['BIN_OP_MULT[blink_c_l42_c20_ea96]', 'BIN_OP_PLUS[blink_c_l38_c15_6a92]']
32: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
33: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
34: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
35: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
36: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
37: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
38: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
39: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
40: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
41: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
42: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
43: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
44: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
45: ['BIN_OP_MULT[blink_c_l42_c20_ea96]']
46: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
47: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
48: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
49: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
50: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
51: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
52: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
53: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
54: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
55: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
56: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
57: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
58: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
59: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
60: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
61: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
62: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
63: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
64: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
65: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
66: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
67: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
68: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
69: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
70: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
71: ['BIN_OP_GTE[blink_c_l42_c8_03a9]']
72: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
73: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
74: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
75: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
76: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
77: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
78: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
79: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
80: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
81: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
82: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
83: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
84: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
85: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
86: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
87: ['counter_MUX[blink_c_l42_c5_41ed]', 'leds_on_MUX[blink_c_l42_c5_41ed]']
In more advanced examples you will want to use the auto-pipelining features of PipelineC. This example is a single global-variable-using main function. It cannot be further pipelined, no further latency can be traded off for throughput. Luckily as-written it is expected to run at a maximum of ~139Mhz, plenty of margin to meet timing on the 100MHz system clock, no further pipelining or design changes are needed.
================== Beginning Throughput Sweep ================================
Function: sys_clk_main Target MHz: 100.0
Starting with blank sweep state...
...determining slicing information for each main function...
sys_clk_main : currently is 0 clocks latency...
sys_clk_main current slices: []
Running: /media/1TB/Programs/Linux/Xilinx/Vivado/2019.2/bin/vivado -journal /home/julian/pipelinec_syn_output/top/vivado.jou -log /home/julian/pipelinec_syn_output/top/vivado_d751.log -mode batch -source "/home/julian/pipelinec_syn_output/top/top_d751.tcl"
Path from input register to pipeline logic...
MHz: 139.37282229965157
Found maximum pipeline latency...
================== Writing Results of Throughput Sweep ================================
Done.
-- Top level file connecting to PipelineC generated code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
-- PipelineC packages
use work.c_structs_pkg.all;
entity board is
port (
CLK100MHZ : in std_logic;
sw : in std_logic_vector(3 downto 0);
led : out std_logic_vector(3 downto 0)
);
end board;
architecture arch of board is
-- Sync inputs to CLK100MHZ
signal sw_r, sw_rr : std_logic_vector(3 downto 0);
-- IO type conversion
signal sys_clk_main_inputs : sys_clk_main_inputs_t;
signal sys_clk_main_outputs : sys_clk_main_outputs_t;
begin
-- Sync inputs to CLK100MHZ
process(CLK100MHZ) begin
if rising_edge(CLK100MHZ) then
sw_r <= sw;
sw_rr <= sw_r;
end if;
end process;
-- IO type conversion
process(
-- Inputs to module
sw_rr,
-- Outputs from PipelineC
sys_clk_main_outputs
) begin
-- Input
sys_clk_main_inputs.sw(0) <= sw_rr(0);
sys_clk_main_inputs.sw(1) <= sw_rr(1);
sys_clk_main_inputs.sw(2) <= sw_rr(2);
sys_clk_main_inputs.sw(3) <= sw_rr(3);
-- Outputs
led(0) <= sys_clk_main_outputs.led(0)(0);
led(1) <= sys_clk_main_outputs.led(1)(0);
led(2) <= sys_clk_main_outputs.led(2)(0);
led(3) <= sys_clk_main_outputs.led(3)(0);
end process;
-- The PipelineC generated entity
top_inst : entity work.top port map (
clk_sys_clk_main => CLK100MHZ,
sys_clk_main_inputs => sys_clk_main_inputs,
sys_clk_main_return_output => sys_clk_main_outputs
);
end arch;Function elaboration to combinatorial logic:
Resource usage:

