====== LED Blink ======
Create an empty project like [[led_toggle]] did.
===== Clock =====
Sequential RTL usually describes behavior in terms of clock edges rather than absolute time. ''always @(posedge clk)'' reacts to each rising edge regardless of whether the clock is 50 MHz or 100 MHz. However, the physical circuit does care about the clock period, because the combinational logic between registers must settle before the next sampling edge.
For example,
always @(posedge clk) begin
counter1 <= counter1 + 1;
counter2 <= counter2 + 1;
end
This block is asking the FPGA to increase both ''counter1'' and ''counter2'' signals by 1 when at ''clk'' signal ''posedge'' (raising from ''0'' to ''1''). Take note that the change of both signals happen at the same time independently, as they are parallel in physical space. It will not like programming language to increase ''counter1'' first then increase ''counter2''.
===== Assignment =====
Here we use ''<='' (non-blocking assignment) instead of ''='' (blocking assignment), and they have different Verilog simulation semantics, which affects how a hardware description behaves and can cause simulation results to differ from the intended synchronous hardware behavior. In simulator, blocking assignment behaves like the programming language, the first line complete first (and blocking the next line to execute), then is the second line. While the the non-blocking assignment get ready all new values first, and then update all together. Refer to page [[assignment]] for more details.
For beginner, it is good to keep all sequential logic with non-blocking assignment ''<='', and combinational logic in blocking assignment ''=''.
===== Counting =====
The [[eee:fpga:board:ypcb-00338-1p1]] board have a crystal of 50 MHz (and also another 2 in 200 MHz). In order to toggle LED every 1 second, or 2 Hz, we need to count from 0 to 49,999,999, and then toggle ''led'' and reset counter.
if (counter >= 26'd49_999_999) begin
counter <= 0;
led <= ~led;
end
else begin
counter <= counter + 1;
end
We need the counter signal that is at least able to store 49,999,999. Since
$$
2^{25} = 33,554,432 < 50,000,000
\\
2^{26} = 67,108,864 > 50,000,000
$$
26-bit is enough. Thus the definition of counter should be
reg [25:0] counter;
where the MSB is bit 25 and LSB is bit 0.
===== Initialization =====
Before we combining everything together, we need to give initial values to our regs ''counter'' and ''led_state'', so that they are not starting from any random values that we are not expecting.
initial begin
counter = 0;
led_state = 0;
end
For this Xilinx 7-series FPGA using Vivado, synthesizable ''initial'' assignments can specify the configuration-time initial values of registers. The FPGA does not execute the ''initial'' block like software; Vivado maps the requested initial state into the device configuration.
===== Top Module =====
The top module will be
module top (
input wire clk,
output wire led
);
reg [25:0] counter;
reg led_state;
initial begin
counter = 0;
led_state = 0;
end
always @(posedge clk) begin
if (counter >= 26'd49_999_999) begin
counter <= 0;
led_state <= ~led_state;
end
else begin
counter <= counter + 1;
end
end
assign led = led_state;
endmodule
===== Constraint =====
Similarly, we need to attach ports to physical pins.
set_property PACKAGE_PIN AA28 [get_ports clk]
set_property IOSTANDARD LVCMOS18 [get_ports clk]
set_property PACKAGE_PIN P30 [get_ports led]
set_property IOSTANDARD LVCMOS18 [get_ports led]
create_clock -period 20.000 [get_ports clk]
One additional line ''create_clock -period 20.000 [get_ports clk]'' is telling Vivado that the ''clk'' signal have a period of 20 ns, to asking analyzer that the logic must be completed within this period.
===== Result =====
It is expected that the red LED in sequence that lights up one second and blows down one second.
===== Register-Transfer Level (RTL) Schematic =====
Open left side menu - analysis - open elaborated design - schematic, you will see the electronic diagram from the Verilog code.
{{.:pasted:20260815-084711.png}}
The ''counter0_i'' adds up ''counter0_i.I0[25:0]'', which is the current value of register ''counter_reg[25:0]'' (''counter_reg[25:0].Q''), and ''counter0_i.I1'', which is connected to high level directly. The value is temporarily kept at ''counter0_i.O[25:0]'', or ''counter_reg[25:0].D''. When the ''clk'' at posedge, ''counter_reg[25:0]'' will be updated from ''counter_reg[25:0].D''. This is how the sentence
counter <= counter + 1;
works.
The ''counter0_i__0'' compares ''counter0_i__0.I0[25:0]'' (''counter_reg[25:0].Q'') and a fixed value at ''counter0_i__0.I1[25:0]'', ''0x2FAF07F'', or 49,999,999. The output ''counter0_i__0.O'' goes to two places, one is ''counter_reg[25:0].RST'', which will reset the value, and the other is ''led_state_reg.CE''. This corresponds to the block
if (counter >= 26'd49_999_999) begin
counter <= 0;
led_state ...
end
The ''led_state_reg'' is another register similar to ''couter_reg[25:0]''. It will only take action when ''led_state_reg.CE'' (clock enable) is high. When ''led_state_reg.CE'' is high and ''led_state_reg.C'' is at posedge, it will update its value from ''led_state_reg.D'', which is operated from ''led_state_reg.Q'' using an inverter ''led_state0_i''. This correcponds the phrase
led_state <= ~led_state;
When ''led_state_reg.CE'' is low, ''led_state_reg.Q'' remains the same regardless of ''led_state_reg.C'', and nothing will be changed.
===== Synthesized Schematic =====
From left side menu - synthesis - open synthesized design - schematic, how the FPGA actually plan the resources will be shown.
{{.:pasted:20260815-091250.png}}
The input ''clk'' signal will go through input buffer ''IBUF'' and global clock buffer ''BUFG'' before it can be used. And the output signal ''led'' must be processed via output buffer ''OBUF''. The ''RTL_REG_SYNC'' ''counter_reg[25:0]'' and ''RTL_REG'' ''led_state_reg'' from RTL schematic is expanded to multiple ''FDRE'' (D-type Flip-Flop primitive), the ''RTL_ADD'' ''counter0_i'' is also replaced with multiple ''CARRY4'' dedicated fast carry-chain primitive used to implement arithmetic and comparison logic. ''RTL_GEQ'' ''counter0_i__0'' and ''RTL_INV'' ''led_state0_i'' are formed using multiple ''LUT'' (look-up table) unit, which stores the truth table of different blocks.
===== Mental Model =====
Verilog is not a sequence of instructions executed by the FPGA. Clocked registers store the current state. Combinational logic continuously computes values from the current signals. At a clock edge, registers sample their inputs and establish the next state. Vivado progressively transforms:
RTL description → elaborated logic → FPGA primitives → placed and routed hardware → bitstream