这是本文档旧的修订版!
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.
Consider the initial condition a = 1 and b = 2, if blocking assignment is used,
a = b; b = a;
will get the result that a = 2 and b = 2, since the value of a has been updated before the phrase b = a;.
The non-blocking assignment
a <= b; b <= a;
can swap them nicely that a = 2 and b = 1.
For beginner, it is good to keep all sequential logic with non-blocking assignment ⇐, and combinational logic in blocking assignment =.
Counting
The ypcb-00338 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.
- top.v
- 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
- top.v
- 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.
- top.xdc
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.
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.
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

