0
点赞
收藏
分享

微信扫一扫

HDLBits_Verilog学习笔记(to be continued)

年夜雪 2022-04-15 阅读 51

HDLBits_Verilog学习笔记(to be continued)


文章目录


There are some HDLBits practices.


Verilog Language

Procedures

Alwaysblock1


由于数字电路由导线连接的逻辑门组成,任何电路都可以表示为一些模块的组合和赋值语句。然而,有时这并不是描述电路最方便的方式。过程(always块就是一个例子)提供了描述电路的另一种语法。
对于硬件综合,两种类型的always块是相关的:

  • 组合电路:always @(*)
  • 时序电路:always @(posedge clk)

组合always块等价于赋值语句,因此总有一种方法可以用这两种方式来表示组合电路。选择使用哪一种主要是哪一种语法更方便的问题。== 注意:过程块内部的代码语法与外部的代码不同。== 过程块有更丰富的语句集(例如,if-then, case),不能包含连续赋值,但也引入了许多新的非直观的出错方式。(程序性连续作业确实存在,但与连续作业有所不同)。
例如,赋值和组合always块描述同一电路。两者都创造了相同的组合逻辑。当任何一个输入(右边)改变值时,两者都会重新计算输出。

	assgin out1 = a & b | c^ d;
	always @(*)
		out2 = a & b | c ^ d;

对于组合的always块,始终使用(*)的敏感信号列表。显式地列出信号很容易出错(如果漏掉一个),并且在硬件综合时被忽略。如果你显式地指定了灵敏度列表,但漏了一个信号,综合硬件仍然会像(*)被指定一样工作,但是仿真模拟将不会也不匹配硬件的行为。(在SystemVerilog中,使用always_comb)。
关于wire和reg的注释: assign语句的左侧必须是net类型(例如wire),而过程赋值语句(在always块中)的左侧必须是变量类型(例如reg)。这些类型(wire vs. reg)与所综合的硬件没有任何关系,只是Verilog作为硬件模拟语言使用时留下的语法。

练习

使用赋值语句和组合的always块构建AND门。(由于赋值语句和组合块总是相同的功能,没有办法强制你使用这两个方法。但你是来练习的,对吧?(让你都是实现一遍))。

// synthesis verilog_input_version verilog_2001
module top_module(
    input a, 
    input b,
    output wire out_assign,
    output reg out_alwaysblock
);
		assign out_assign = a & b;
    always @(*)
        begin
            out_alwaysblock = a & b;
        end
endmodule

assign,连续赋值,就是无条件全等,对象为wire类型;alyways 就是敏感赋值,有条件相等,对象为reg,敏感信号列表,电平触发时,综合为组合电路,边沿触发时,才综合为时序电路。

Alwaysblock2


对于综合电路,两种类型always模块总是相关联的:


  • 组合电路:always @(*)
  • 时序电路:always @(posedge clk)

时序always块创建一团组合逻辑,就像组合always块一样,但也在一团组合逻辑的输出上创建一组触发器(或“寄存器”)。一团逻辑块的输出不能立即可见,而是只在下一个(posedge clk)之后的输出可见。(a blob of :一系列,团,块;不能详细定义形容的整体)。

阻塞 VS 非阻塞 赋值语句

Verilog中存在的三种赋值语句:


  • 连续赋值(assign x = y;):只能用在always块外
  • 阻塞性赋值(x = y;):用于(initial or always)程序语句内部,在赋值时,先计算等号右手部分的值,再赋值给左边变量,直到该语句赋值完成,后面的语句才能执行,会阻塞后面的语句。(顺序执行)
  • 非阻塞性赋值(x <= y;): 用于(initial or always)程序语句内部,执行赋值语句右边,然后将begin-end之间的所有赋值语句同时赋值到赋值语句的左边,但是左边的变量的值不会立即更新,直到always块所有语句执行完,才将左边变量的值更新。

注意


  • 在描述组合逻辑的always 块中用阻塞赋值,则综合成组合逻辑的电路结构。
  • 在描述时序逻辑的always 块中用非阻塞赋值,则综合成时序逻辑的电路结构。

在一个组合always块中,使用阻塞赋值。在时序always块中,使用非阻塞赋值。充分理解Verilog模拟器如何跟踪事件对硬件设计是特别有用的。如果不遵循这一规则,将很难找到仿真和合成硬件之间的不确定性和不同的错误。

练习

用三种方法构建异或门,使用赋值语句、组合always块和时序always块。请注意,时钟always块产生一个不同于其他两个的电路:有一个触发器,所以输出延迟。

// synthesis verilog_input_version verilog_2001
module top_module(
    input clk,
    input a,
    input b,
    output wire out_assign,
    output reg out_always_comb,
    output reg out_always_ff  );
    
	assign out_assign = a ^ b;
    
    always @(*)
        begin
            out_always_comb = a ^ b;
        end
    
    always @(posedge clk )
        begin 
            out_always_ff <= a ^ b;
        end
endmodule

Always if


if条件语句相当于一个二选一选择器,eg:

always @(*) begin
    if (condition) begin
        out = x;
    end
    else begin
        out = y;
    end
end

如果条件为真输出if下的,为假输出其他的;这相当于条件预算符下的连续赋值:

	assign out = (condition) ? x : y;

然而,过程赋值if条件语句中有新的一种错误,只有输出有赋值的时候才能综合成组合电路。

练习

构建一个2-to-1多路选择器,在a和b之间进行选择。如果sel_b1和sel_b2都为true,则选择b。否则,选择a。重复同样的操作两次,一次使用assign语句,一次使用过程性if语句。

module top_module(
    input a,
    input b,
    input sel_b1,
    input sel_b2,
    output wire out_assign,
    output reg out_always   ); 
    
    assign out_assign = (sel_b1 & sel_b2)? b : a;
    
    always @(*)
        begin
            if (sel_b1 == 1'b1 & sel_b2 == 1'b1)
            begin 
                out_always = b;
            end
    	else
            begin
                out_always = a;
            end
        end
endmodule
always = b;
            end
    	else
            begin
                out_always = a;
            end
        end
endmodule
举报

相关推荐

0 条评论