verilog语法1

1.可综合/不可综合

可综合的代码最终会被映射为组合逻辑或时序逻辑。

不可综合这些关键字和结构在真实的硅片或 FPGA 里是没有对应的物理电路的,综合工具看到它们会直接报错或忽略。

初始化与时间控制 (initial块, $display, $finish 等系统任务):

循环语句(部分不可综合):

延时控制 (#):

2.模块/例化/参数化模块

module adder8 (

input wire [7:0] a,

input wire [7:0] b,

input wire cin,

output wire [7:0] sum,

output wire cout

);

assign {cout, sum} = a + b + cin;

Endmodule

module counter #(

parameter WIDTH = 8, // 位宽,可被覆盖

parameter MAX = 199 // 计数上限,可被覆盖

)(

input wire clk,

input wire rst_n, // 低电平复位

input wire en,

output reg [WIDTH-1:0] cnt,

output wire tick

);

localparam ZERO = {WIDTH{1'b0}}; // 内部常量,不可覆盖,parameter 与 localparam,这两个是常量,不是信号,不占硬件资源,只在编译期起作用。

always @(posedge clk or negedge rst_n) begin

if (!rst_n)

cnt <= ZERO;

else if (en) begin

if (cnt >= MAX)

cnt <= ZERO;

else

cnt <= cnt + 1'b1;

end

end

assign tick = (cnt == MAX); // 计满时输出一个周期脉冲

Endmodule

counter #( //模块名

.WIDTH(16), //修改

.MAX(49999)

) u_cnt_big (//实例名,必须注意可以多次例化,但是实例名是唯一的,

.clk (clk), //左侧是模块里面的信号(子),右侧是连接的信号(本)

.rst_n(rst_n),

.en (en),

.cnt (),

.tick (tick_big)

);

模块名 #(参数覆盖) 实例名 (

.端口名(连接的信号),

.端口名(连接的信号)

);

//========== 第 1 次例化 ==========

adder8 u_add1 (

.a (a1),

.b (b1),

.y (y1)

);

//========== 第 2 次例化(同一个模块) ==========

adder8 u_add2 (

.a (a2),

.b (b2),

.y (y2)

);

3.数据类型

Wire表示一根导线,它自己不存储任何值,必须由外部持续驱动:

用 assign 驱动

或者由模块的输出端口驱动

或者由实例的输出端口驱动

x是不定态,z是高阻

reg 是变量,可以在 always 块里被赋值,能保存值。但注意:

reg ≠ 寄存器! 它只是"能在 always 里被赋值的变量",综合出来可能是组合逻辑,也可能是时序逻辑,取决于 always 块的写法。

有符号数 signed

Verilog 默认所有信号都是无符号。要做有符号运算(比如负数加法)要显式声明:

verilog

wire signed [7:0] a = -8'sd5; // 有符号

wire signed [7:0] b = 8'sd3;

wire signed [8:0] s = a + b; // 需要多一位防溢出

<位宽>'<进制><数值>

verilog

8'd255 // 8 位十进制 255

// 省略位宽时默认 32 位

'hFF // 等价于 32'h000000FF

255 // 等价于 32'd255

integer(整数型)

verilog

integer i; // 默认 32 位有符号整数

// 最典型用法:for 循环变量(仿真、generate 里)

integer j;

initial begin

for (j = 0; j < 8; j = j + 1)

mem[j] = 0;

End

Verilog 没有真正的"二维数组",但支持"多位宽的寄存器数组",就是存储器:

verilog

// 256 个 8 位宽的存储单元,就是一块 256×8 的 RAM

reg [7:0] mem [0:255];

不能整体赋值,只能逐元素赋值

四运算符

算术

wire [7:0] a = 8'd10, b = 8'd3;

wire [7:0] sum = a + b; // 13

wire [7:0] diff = a - b; // 7

wire [7:0] prod = a * b; // 30

wire [7:0] quot = a / b; // 3(整数除法,截断)

wire [7:0] rem = a % b; // 1(取模)

wire [7:0] pow = a ** 2; // 100(仅部分工具支持常量指数)

但是要注意这个位宽,

// 加法:结果位宽 = max(位宽) + 1

wire [8:0] sum9 = {1'b0,a} + {1'b0,b};

// 乘法:结果位宽 = 两个操作数位宽之和

wire [15:0] prod16 = a * b; // 8×8 → 16 位

// 无符号和有符号混用,整个表达式按无符号处理,负数会变成大正数!

wire signed [7:0] sa = -8'sd5;

wire [7:0] ub = 8'd3;

wire signed [8:0] r = sa + ub; // ❌ 结果错误,sa 被当成无符号 2,只要有负数,就全链路都用 signed,不要混用。

关系运算符

关系运算结果是 1 位,即使比较的是 8 位数

== 和 === 的区别(常考)

==:只要有一边是 x 或 z,结果就是 x(不定态)。

===:把 x、z 当成具体值比较,结果一定是 0 或 1。只在仿真/建模时用,不可综合。

逻辑运算符和位运算符

wire [3:0] a = 4'b1010;

wire [3:0] b = 4'b1100;

// 位运算:逐位操作,结果 4 位

wire [3:0] and_bit = a & b; // 4'b1000

wire [3:0] or_bit = a | b; // 4'b1110

wire [3:0] xor_bit = a ^ b; // 4'b0110

wire [3:0] not_bit = ~a; // 4'b0101

// 逻辑运算:整数值是否非零,结果 1 位

wire and_log = a && b; // 1(a、b 都非零)

wire or_log = a || b; // 1(至少一个非零)

wire not_log = !a; // 0(a 非零)

归约运算符(一元位运算)

把向量的所有位"归约"成 1 位,是位运算的一元形式:

运算符

含义

a = 4'b1010 时结果

&a

所有位相与

0(有 0 就是 0)

~&a

与非归约

1

|a

所有位相或

1(有 1 就是 1)

~|a

或非归约

0

^a

所有位异或(奇偶校验)

0(偶数个 1)

~^a

同或归约

1

移位运算符

运算符

名称

空位补什么

<<

逻辑左移

补 0

>>

逻辑右移

补 0

<<<

算术左移

补 0(和 << 相同)

>>>

算术右移

补符号位(无符号时补 0)

同步和异步

异步:@(posedge clk or negedge rst_n) —— rst_n 变化立即触发 always 块。

同步:@(posedge clk) —— rst_n 变化不触发,只有时钟沿才检查它

异步复位最大的坑在"释放"时刻,不在"拉低"时刻。

拉低(assert):随时拉低都安全,立刻复位,没问题。

释放(deassert,rst_n 从 0 变 1):如果这个跳变恰好发生在时钟上升沿附近,触发器的复位撤除和时钟采样"撞车",可能进入亚稳态(输出既不是 0 也不是 1,而是中间电平,持续一段时间才稳定)

复位拉低用异步(快),释放用同步(安全)。做法是把复位信号先经过两级触发器同步到时钟域,再用它的输出做复位。

时钟/CDC 相关

多 bit 信号:多个 bit 到达时间不同,采到"半新半旧",必须用异步 FIFO 或格雷码。

单 bit 脉冲直接打两拍:脉冲可能比目的时钟周期还窄,被完全漏掉,要先展宽再同步。

If/case

If有优先级,case是并行,没有优先级

If得写else,case得写default,防止生成锁存器,最后前面写上默认值

always @(*) begin

y = 8'd0; // 默认值兜底

if (en) y = a;

End

case (表达式)

值1: 语句;

值2: 语句;

值3, 值4: 语句; // 多个值共享一个分支,逗号分隔

default: 语句; // 兜底

endcase

Case每个值必须不用,但值的位宽必须相同

posted @ 2026-10-27 22:46  juzzz55  阅读(5)  评论(0)    收藏  举报