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
相关推荐
cuisidong199711 分钟前
5G学习笔记三之物理层、数据链路层、RRC层协议
笔记·学习·5g
上理考研周导师13 分钟前
第二章 虚拟仪器及其构成原理
fpga开发
南宫理的日知录19 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
数据与后端架构提升之路1 小时前
从神经元到神经网络:深度学习的进化之旅
人工智能·神经网络·学习
一行11 小时前
电脑蓝屏debug学习
学习·电脑
FPGA技术实战2 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
星LZX2 小时前
WireShark入门学习笔记
笔记·学习·wireshark
阑梦清川2 小时前
在鱼皮的模拟面试里面学习有感
学习·面试·职场和发展
qq_433099402 小时前
Isaac Gym学习笔记——概述
学习
秃头佛爷4 小时前
Python学习大纲总结及注意事项
开发语言·python·学习