循环 7-10
- 代码段
verilog
generate
genvar i;
for (i=0; i<8; i = i+1) begin: my_block_name
assign out[i] = in[8-i-1];
end
endgenerate
- 解释
该代码使用了 S y s t e m V e r i l o g SystemVerilog SystemVerilog 中的 g e n e r a t e generate generate 构造,它允许在编译期间创建硬件结构。 g e n v a r genvar genvar 声明定义了一个生成变量 $ i$,可以用于索引。
在 g e n e r a t e generate generate 块内部, f o r for for 循环从0到7进行迭代( i i i < 8 8 8)。对于每次迭代, a s s i g n assign assign 语句将 i n [ 8 − i − 1 ] in[8 - i - 1] in[8−i−1] 的值赋给 o u t [ i ] out[i] out[i]。这将颠倒 i n in in 数组中的元素顺序,并将它们赋值给 o u t out out 数组中对应的元素。
请注意, g e n e r a t e generate generate 构造在硬件描述语言(如 S y s t e m V e r i l o g SystemVerilog SystemVerilog)中用于创建硬件结构,但它不是常规过程执行流程的一部分。因此,该代码必须放置在支持 g e n e r a t e generate generate构造的模块或其他适当的上下文中。
- 代码段
verilog
always @(*) begin
for (int i=0; i<8; i++) // int is a SystemVerilog type. Use integer for pure Verilog.
out[i] = in[8-i-1];
end
- 解释
always 块 7.14
对于硬件合成,有两类始终块是相关的:
组合式:always @(*)
时钟式:always @(posedge clk)
组合总是块等同于赋值语句,因此总有一种方法可以用两种方式来表达组合电路。选择哪种方式主要是看哪种语法更方便。程序块内部代码的语法与外部代码的语法不同。过程块有更丰富的语句集(如if-then、case),不能包含连续赋值*,但也引入了许多新的非直观的错误方式。(*程序连续赋值确实存在,但与连续赋值有些不同,而且不可合成)。
例如,(the assign and combinational always block )分配和组合总是块描述相同的电路。两者都创建了相同的组合逻辑。每当任何输入(右侧)的值发生变化时,两者都将重新计算输出。
在组合逻辑always块中使用敏感性列表的最佳实践。建议使用()作为敏感性列表,而不是显式列出所有信号,因为这样容易出错,并且在硬件综合过程中会被忽略。如果您显式指定了敏感性列表并漏掉了一个信号,则合成的硬件仍将像( )一样运行,但仿真不会匹配硬件的行为。(在SystemVerilog中,使用always_comb。)
Verilog中使用的两种不同的变量类型:wire和reg。
在Verilog中,wire类型用于表示连线或信号,它在描述硬件电路时用于连接不同的模块或元件。它通常用于assign语句中,用于在连续赋值中连接模块的输入和输出。
而reg类型则用于表示寄存器或存储器元素,它在描述硬件电路时用于存储数据或状态。它通常用于always块中的过程赋值语句,用于描述时序逻辑或状态机。
这两种类型的选择与硬件综合无关,只是Verilog作为硬件仿真语言时的语法约定。在实际综合成硬件时,这些变量类型都会被映射到适当的硬件元素。
<= 和 = 的区别 :
在 Verilog 中,<= 和 = 是赋值操作符,但在 always 块内的上下文中,它们具有不同的含义和行为。
<= 赋值操作符:
<= 被称为非阻塞赋值(non-blocking assignment)操作符。
在 always 块内部使用 <= 进行赋值时,该赋值是并发进行的。
当 always 块的敏感信号(敏感列表)发生变化时,所有的 <= 赋值同时生效,以并行的方式更新信号的值。
这种并发赋值模型可以用于描述多个并行操作,例如时序逻辑中的寄存器更新或多个线程之间的通信。
= 赋值操作符:
= 被称为阻塞赋值(blocking assignment)操作符。
在 always 块内部使用 = 进行赋值时,该赋值是顺序进行的。
当 always 块的执行到达 = 赋值时,它会阻塞(暂停)之后的语句,直到完成当前的赋值操作,然后再继续执行下一个语句。
这种顺序赋值模型可以用于描述时序逻辑中的组合逻辑操作,其中后续的语句可能依赖于当前赋值的结果。
在常见的用法中,通常在组合逻辑中使用 = 赋值操作符,而在时序逻辑(如 always @(posedge clk))中使用 <= 非阻塞赋值操作符。这样可以确保在时序逻辑中的多个并发赋值在时钟沿上并行执行,而在组合逻辑中的连续赋值按顺序进行。
$bits(in) 7.18
在Verilog中,$bits(in)是一种用于获取信号或变量的位宽的系统函数。它返回一个整数,表示给定信号或变量的位宽。
100位的全加器
verilog
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
always @(*) begin
{cout[0],sum[0]} = a[0] + b[0] + cin;
for (int i = 1;i < $bits(a);i ++)
{cout[i],sum[i]} = a[i] + b[i] + cout[i-1];
end
endmodule
BCD加法器
实例化100份bcd_fadd,创建一个100位的BCD纹波携带加法器。您的加法器应将两个100位BCD数(打包成400位向量)相加,再加上一个进位,以产生一个100位数的和并进行输出。
verilog
module top_module(
input [399:0] a, b,
input cin,
output cout,
output [399:0] sum );
wire [400:0] midcout;
assign cout = midcout[400];
bcd_fadd bcd_fadd_0(.a(a[3:0]), .b(b[3:0]), .cin(cin), .cout(midcout[4]), .sum(sum[3:0]));
generate//子模块不可在always模块内部调用,可以生成模块重复调用
genvar i;
for(i=4;i<$bits(a);i=i+4)
begin:Go
bcd_fadd bcd_fadd_i(.a(a[i+3:i]), .b(b[i+3:i]), .cin(midcout[i]), .cout(midcout[i+4]), .sum(sum[i+3:i]));
end
endgenerate
endmodule
部分切片 7.19
verilog
assign out = in[sel * 4 +: 4];
半加器
verilog
module top_module(
input a, b,
output cout, sum );
assign {cout,sum} = a+b;
endmodule