verilog学习——building block
(六)verilog 串联(concatenation)
串联运算符” { }”,必须知道每个操作数的大小。
1.复制操作
当同一个表达式必须重复多次时,使用复制常量,该常量必须是非负数,不能是 X、Z 或任何变量。此常数也与原始串联运算符一起括在大括号内,并表示表达式将重复的总次数。
wire a;
wire [6:0] res;
assign res = {7{a}};
复制表达式不能出现在任何赋值的左侧,也不能连接到output或inout端口;
2.嵌套复制
允许在正则串联表达式中使用复制表达式,
$display("a=%b b=%b res=%b", a, b, {a, b, 3'b000, {{2{a}}, {3{b}}}});
a=10 b=100 res=101000001010100100100
3.verilog符号扩展
符号扩展是一种通过复制符号位将具有较少位的有符号数字扩展到较宽的有符号数字的方法。通常,对具有不同的位宽的数字执行算数或逻辑运算时使用。
(七)Verilog always 块
Always块是verilog中的程序块之一,always块中的语句按顺序执行;
1.always语法
always @ (event)
[statement]
always @ (event) begin
[multiple statements]
end
always块在某个特定事件中执行,该事件由敏感度列表定义。
2.敏感度列表
敏感度列表是定义何时应执行always块的表达式,在@运算符后面的()括号内定义。此列表可能包含一个或一组信号,其值更改将执行always块。
3.always块的作用
Always块可用来实现组合或顺序元件。将块 always 制作为一个连续过程,当灵敏度列表中的信号变为活动状态时,该过程会被触发并执行某些操作。
always @ (posedge clk) begin
[statements]
end
always 模块中的所有语句都在信号 clk 的每个正边沿执行。
4.没有敏感度列表时:
灵敏度列表带来了一定的时间感,即每当灵敏度列表中的任何信号发生变化时,都会触发always块。如果always块中没有时序控制语句,则仿真将因零延迟无限循环而挂起。
即使敏感度列表为空,也应该存在其他形式的时间延迟。
always #10 clk = ~clk;
时钟反转将在每10 个时间单位之后完成。
显式延迟不能合成为逻辑门。
(八)Verilog initial块
一组verilog语句通常在模拟中按顺序执行。这些语句被放置在程序块中,verilog中主要有两种类型的程序块——initial和always。
1.verilog initial语法
initial
[single statement]
initial begin
[multiple statements]
end
2.initial块的用途
Initial块不可合成,因此无法转换为具有数字原件的硬件原理图。该模块主要用于初始化变量和驱动具有特定值的设计端口。
3.initial块的开始和结束
Initial在模拟开始时,在时间0处就启动模块,在整个模拟过程中,仅执行一次,initial块内的语句执行完毕之后,initial块的执行就结束了。
4.一个模块中允许有多少个initial块
模块中可以定义的initial块数是没有限制的。Initial块同时启动并并行运行,结束的时间可能会有所不同。
$finish 是 Verilog 系统任务,它告诉仿真器终止当前仿真。
initial begin
#30 $finish;
end
如果最后一个块有 30 个时间单位的延迟,则模拟将在 30 个时间单位结束,从而杀死当时处于活动状态的所有其他 initial 块。
(九)Verilog总结
1.模块
所有行为代码都写在module和endmodule中;有空模块和非空模块;
2.数据类型
Verilog中有两中主要的数据类型用于硬件合成,reg和wire;
reg 数据类型用于保存变量等值,而wire 只是类似于必须连续驱动的电线。所以通常 wire 用于连接多个模块和其他信号。
3.assignment
Verilog有三个基本块:
always@(condition):始终在满足条件时执行;
Initial :在模拟开始时仅执行一次;
assign [LHS]=[RHS]:每当RHS发生变化时,LHS的值都会发生变化。
规则:
① Reg只能分配给initial和always块;
② Wire只能通过assign语句赋值;
③ 如果initial/always块中有多个语句,则应将它们包含在begin…end中;
#用于表示时间延迟;
(十)Verilog generate block
Generate块允许对模块实例进行乘法或对任何模块执行条件实例化,当同一操作或模块实例需要多次重复,或者必须根据给定的Verilog参数有条件地包含某些代码时,这些语句特别方便。
Generate块不能包含端口、参数、 specparam 声明或 specify 块。但是,允许使用其他模块项和其他生成块。所有生成的实例都编码都在module 内,并且在关键字 generate 和 endgenerate 之间。
生成的实例可以具有模块、连续赋值或 always、 initial 块和用户定义的基元。有两种类型的生成结构 - 循环和条件。
1.generate for循环
循环变量必须使用genvar关键字声明,该关键字告诉工具该变量将在生成块的详细说明期间专门使用。
// Design for a half-adder
module ha ( input a, b,
output sum, cout);
assign sum = a ^ b;
assign cout = a & b;
endmodule
// A top level design that contains N instances of half adder
module my_design
#(parameter N=4)
( input [N-1:0] a, b,
output [N-1:0] sum, cout);
// Declare a temporary loop variable to be used during
// generation and won't be available during simulation
genvar i;
// Generate for loop to instantiate N times
generate
for (i = 0; i < N; i = i + 1) begin
ha u0 (a[i], b[i], sum[i], cout[i]);
end
endgenerate
endmodule
2.generate if
// Design #1: Multiplexer design uses an "assign" statement to assign
// out signal
module mux_assign ( input a, b, sel,
output out);
assign out = sel ? a : b;
// The initial display statement is used so that
// we know which design got instantiated from simulation
// logs
initial
$display ("mux_assign is instantiated");
endmodule
// Design #2: Multiplexer design uses a "case" statement to drive
// out signal
module mux_case (input a, b, sel,
output reg out);
always @ (a or b or sel) begin
case (sel)
0 : out = a;
1 : out = b;
endcase
end
// The initial display statement is used so that
// we know which design got instantiated from simulation
// logs
initial
$display ("mux_case is instantiated");
endmodule
// Top Level Design: Use a parameter to choose either one
module my_design ( input a, b, sel,
output out);
parameter USE_CASE = 0;
// Use a "generate" block to instantiate either mux_case
// or mux_assign using an if else construct with generate
generate
if (USE_CASE)
mux_case mc (.a(a), .b(b), .sel(sel), .out(out));
else
mux_assign ma (.a(a), .b(b), .sel(sel), .out(out));
endgenerate
endmodule