适用于 XS7050 板卡 + Vivado 2021.2
1. 模块结构
module my_module (
input clk, // 时钟
input rst_n, // 复位(低有效)
input [3:0] data_in, // 4bit 输入
output [3:0] data_out, // 4bit 输出(组合)
output reg led // 1bit 输出(寄存器)
);
// ... 逻辑 ...
endmodule要点:
input默认是wireoutput若在always块中赋值,必须声明为output reg位宽用
[MSB:LSB],如[7:0]表示 8 位
2. 数据类型
类型 | 用途 | 典型场景 |
|---|---|---|
| 连线,不能存储 |
|
| 寄存器,可存储 |
|
注意:reg 不一定综合成寄存器!在 always @(*) 中用 reg 仍是组合逻辑。
3. 常量表示
4'b1010 // 4位二进制
8'hFF // 8位十六进制
32'd100 // 32位十进制
4'b0 // 4位,值为 0000格式:位宽'进制 值,进制:b(二进制) h(十六进制) d(十进制) o(八进制)
4. 赋值方式
连续赋值(组合逻辑)
assign data_out = data_in & 4'b1111;阻塞赋值 =(组合逻辑块)
always @(*) begin
if (sel)
y = a;
else
y = b; // ← 必须有 else,否则产生锁存器!
end非阻塞赋值 <=(时序逻辑块)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else
q <= d;
end阻塞 vs 非阻塞 铁律
场景 | 用 | 原因 |
|---|---|---|
|
| 并行更新,模拟真实 FF 行为 |
|
| 顺序求值,模拟组合电路 |
|
| 连续赋值,只能用 |
绝对不要在时序块里混用 = 和 <=。
5. 常用运算符
运算符 | 含义 | 示例 |
|---|---|---|
| 按位 与/或/异或/取反 |
|
| 逻辑 与/或/非 |
|
| 算术 |
|
| 相等/不等 |
|
| 比较 |
|
| 左移/右移 |
|
| 三目 |
|
| 拼接 |
|
| 重复 |
|
6. 组合逻辑 vs 时序逻辑
组合逻辑
// 方式1:assign
assign sum = a + b;
// 方式2:always(必须覆盖所有分支)
always @(*) begin
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
default: y = 4'b0; // ← 必须有 default!
endcase
end时序逻辑(带异步复位)
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 32'd0; // 异步复位
else if (cnt >= MAX - 1)
cnt <= 32'd0; // 溢出归零
else
cnt <= cnt + 1; // 正常计数
end7. 常用模板
计数器 + 分频
// 50MHz → 1Hz LED 闪烁
parameter CNT_MAX = 25_000_000 - 1; // 0.5s
reg [24:0] cnt;
reg led;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
led <= 1'b1; // LED 低有效,复位时灭
end else if (cnt >= CNT_MAX) begin
cnt <= 0;
led <= ~led;
end else begin
cnt <= cnt + 1;
end
end两级同步器(打两拍)
reg key_r1, key_r2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
key_r1 <= 1'b1; // 上拉默认高
key_r2 <= 1'b1;
end else begin
key_r1 <= key_n; // 第一拍
key_r2 <= key_r1; // 第二拍(安全使用此信号)
end
end按键消抖
parameter DEBOUNCE_MAX = 1_000_000; // 20ms @50MHz
reg [19:0] db_cnt;
reg key_stable;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
db_cnt <= 0;
key_stable <= 1'b1;
end else if (key_r2 != key_stable) begin
if (db_cnt >= DEBOUNCE_MAX - 1) begin
db_cnt <= 0;
key_stable <= key_r2; // 稳定了,更新
end else begin
db_cnt <= db_cnt + 1;
end
end else begin
db_cnt <= 0; // 一致则清零
end
end异步复位同步释放
reg rst_n_r1, rst_n_r2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rst_n_r1 <= 1'b0; // 异步复位立即生效
rst_n_r2 <= 1'b0;
end else begin
rst_n_r1 <= 1'b1; // 复位释放时同步到时钟域
rst_n_r2 <= rst_n_r1;
end
end
// 后续逻辑使用 rst_n_r2 作为复位信号简单状态机(三段式)
localparam IDLE = 2'd0,
S1 = 2'd1,
S2 = 2'd2;
reg [1:0] state, next_state;
// 第一段:状态寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= IDLE;
else
state <= next_state;
end
// 第二段:次态逻辑(组合)
always @(*) begin
next_state = state; // 默认保持(防锁存器)
case (state)
IDLE: if (start) next_state = S1;
S1: if (done) next_state = S2;
S2: next_state = IDLE;
default: next_state = IDLE;
endcase
end
// 第三段:输出逻辑(组合)
always @(*) begin
led = 1'b1; // 默认值(防锁存器)
case (state)
S1: led = 1'b0; // S1 状态亮灯
default: led = 1'b1;
endcase
end8. Testbench 模板
`timescale 1ns / 1ps
module tb_my_module;
reg clk;
reg rst_n;
reg [3:0] key_n;
wire [3:0] led;
// 实例化被测模块
my_module u_dut (
.clk (clk),
.rst_n (rst_n),
.key_n (key_n),
.led (led)
);
// 时钟生成:50MHz = 20ns 周期
initial clk = 0;
always #10 clk = ~clk;
// 激励
initial begin
// 初始化
rst_n = 0;
key_n = 4'b1111; // 按键默认高(未按)
#200; // 复位保持 200ns
// 释放复位
rst_n = 1;
#1000;
// 按下 KEY0
key_n[0] = 0;
#100_000; // 按住 100us
key_n[0] = 1;
#100_000;
$display("Simulation finished.");
$finish;
end
endmoduleVivado 仿真:右键 TB 文件 → Set as Top → Run Behavioral Simulation
9. Vivado 关键操作流程
新建工程:File → New Project → RTL → 选器件(XS7050 对应 xc7s50 系列)
添加源文件:Add Sources → Add or Create Design Sources
添加约束:Add Sources → Add or Create Constraints → 导入 .xdc
综合:Run Synthesis
实现:Run Implementation
生成 Bitstream:Generate Bitstream
下载:Open Hardware Manager → Auto Connect → Program Device
仿真:Run Behavioral Simulation(先设 TB 为顶层)
当修改了某个源代码或者约束,可以直接点击 Generate Bitstream 自动完成 综合、实现、生成 Bitstream。
10. 坑点速查
# | 问题 | 症状 | 解决 |
|---|---|---|---|
1 | 时序块用 | 仿真对、板子错 | 改用 |
2 | 端口未约束 | 报错或随机管脚 | .xdc 写全所有端口 |
3 | 端口名不匹配 | 约束无效 | Verilog 与 XDC 名一致 |
4 | 按键不同步 | 偶发逻辑错乱 | 两级 FF 同步 |
5 | 无消抖 | 按一次触发多次 | 计数器消抖 |
6 |
| 产生锁存器 | 加 |
7 | 组合 | 产生锁存器 | 覆盖所有分支 |
8 | 异步复位直接释放 | 释放时亚稳态 | 异步复位同步释放 |