Verilog 学习之路

循环 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
相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
ZPC82104 天前
docker 镜像备份
人工智能·算法·fpga开发·机器人
ZPC82104 天前
docker 使用GUI ROS2
人工智能·算法·fpga开发·机器人
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习