HDLBits note03-Procedures

文章介绍了Verilog中用于硬件描述的always块的不同类型,包括组合逻辑的always块(相当于assign语句)和时钟驱动的always块(含寄存器)。强调了在不同类型的always块中使用阻塞和非阻塞赋值的区别,并通过示例展示了如何构建AND门、XOR门以及2-to-1多路选择器和优先编码器。还讨论了如何避免创建意外的锁存器并确保所有条件下的输出都有定义值。
摘要由CSDN通过智能技术生成

1. Alwaysblock1

note

Since digital circuits are composed of logic gates connected with wires, any circuit can be expressed as some combination of modules and assign statements. However, sometimes this is not the most convenient way to describe the circuit. Procedures (of which always blocks are one example) provide an alternative syntax for describing circuits.
For synthesizing hardware, two types of always blocks are relevant:

  • Combinational: always @(*)
  • Clocked: always @(posedge clk)

Combinational always blocks are equivalent to assign statements, thus there is always a way to express a combinational circuit both ways. The choice between which to use is mainly an issue of which syntax is more convenient. The syntax for code inside a procedural block is different from code that is outside. Procedural blocks have a richer set of statements (e.g., if-then, case), cannot contain continuous assignments*, but also introduces many new non-intuitive ways of making errors. (*Procedural continuous assignments do exist, but are somewhat different from continuous assignments, and are not synthesizable.)
For example, the assign and combinational always block describe the same circuit. Both create the same blob of combinational logic. Both will recompute the output whenever any of the inputs (right side) changes value.
assign out1 = a & b | c ^ d;
always @(*) out2 = a & b | c ^ d;

在这里插入图片描述

problem statement

Build an AND gate using both an assign statement and a combinational always block.
answer

// 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 @(*) out_alwaysblock=a&b;
endmodule

2. Alwaysblock2

note

For hardware synthesis, there are two types of always blocks that are relevant:

  • Combinational: always @(*)
  • Clocked: always @(posedge clk)

Clocked always blocks create a blob of combinational logic just like combinational always blocks, but also creates a set of flip-flops (or “registers”) at the output of the blob of combinational logic. Instead of the outputs of the blob of logic being visible immediately, the outputs are visible only immediately after the next (posedge clk).
Blocking vs. Non-Blocking Assignment
There are three types of assignments in Verilog:

  • Continuous assignments (assign x = y;). Can only be used when not inside a procedure (“always block”).
  • Procedural blocking assignment: (x = y;). Can only be used inside a procedure.
  • Procedural non-blocking assignment: (x <= y;). Can only be used inside a procedure.

In a combinational always block, use blocking assignments. In a clocked always block, use non-blocking assignments. A full understanding of why is not particularly useful for hardware design and requires a good understanding of how Verilog simulators keep track of events. Not following this rule results in extremely hard to find errors that are both non-deterministic and differ between simulation and synthesized hardware.

peoblem statement

Build an XOR gate three ways, using an assign statement, a combinational always block, and a clocked always block. Note that the clocked always block produces a different circuit from the other two: There is a flip-flop so the output is delayed.
在这里插入图片描述
answer

// 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 @(*) out_always_comb=a^b;
    always @(posedge clk) out_always_ff=a^b;
endmodule

3. Always if

note

An if statement usually creates a 2-to-1 multiplexer, selecting one input if the condition is true, and the other input if the condition is false.

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

This is equivalent to using a continuous assignment with a conditional operator:

assign out = (condition) ? x : y;

problem statement

Build a 2-to-1 mux that chooses between a and b. Choose b if both sel_b1 and sel_b2 are true. Otherwise, choose a. Do the same twice, once using assign statements and once using a procedural if statement.
answer

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&&sel_b2==1) begin
            out_always=b;
        end
        else begin
            out_always=a;
        end
    end
endmodule

4.Always if2

note

A common source of errors: How to avoid making latches(锁存器)
Syntactically-correct code does not necessarily result in a reasonable circuit (combinational logic + flip-flops). The usual reason is: “What happens in the cases other than those you specified?”. Verilog’s answer is: Keep the outputs unchanged.

This behaviour of “keep outputs unchanged” means the current state needs to be remembered, and thus produces a latch. Combinational logic (e.g., logic gates) cannot remember any state. Watch out for Warning (10240): … inferring latch(es)" messages. Unless the latch was intentional, it almost always indicates a bug. Combinational circuits must have a value assigned to all outputs under all conditions. This usually means you always need else clauses or a default value assigned to the outputs.

problem statement

The following code contains incorrect behaviour that creates a latch. Fix the bugs so that you will shut off the computer only if it’s really overheated, and stop driving if you’ve arrived at your destination or you need to refuel.

always @(*) begin
    if (cpu_overheated)
       shut_off_computer = 1;
end

always @(*) begin
    if (~arrived)
       keep_driving = ~gas_tank_empty;
end

在这里插入图片描述
answer

module top_module (
    input      cpu_overheated,
    output reg shut_off_computer,
    input      arrived,
    input      gas_tank_empty,
    output reg keep_driving  ); //

    always @(*) begin
        if (cpu_overheated)begin
           shut_off_computer = 1;
        end
        else shut_off_computer = 0;
    end

    always @(*) begin
        if (~arrived) begin
           keep_driving = ~gas_tank_empty;
        end
        else keep_driving = 0;
    end

endmodule

5.Always case

note

always @(*) begin     // This is a combinational circuit
    case (in)
      1'b1: begin 
               out = 1'b1;  // begin-end if >1 statement
            end
      1'b0: out = 1'b0;
      default: out = 1'bx;
    endcase
end

problem statement

Case statements are more convenient than if statements if there are a large number of cases. So, in this exercise, create a 6-to-1 multiplexer. When sel is between 0 and 5, choose the corresponding data input. Otherwise, output 0. The data inputs and outputs are all 4 bits wide.
answer

module top_module ( 
    input [2:0] sel, 
    input [3:0] data0,
    input [3:0] data1,
    input [3:0] data2,
    input [3:0] data3,
    input [3:0] data4,
    input [3:0] data5,
    output reg [3:0] out   );//

    always@(*) begin  // This is a combinational circuit
        case(sel)
            3'b000:begin
                	out=data0;
            end
            3'b001:begin
                out=data1;
            end
            3'b010:begin
                out=data2;
            end
            3'b011:begin
                out=data3;
            end
            3'b100:begin
                out=data4;
            end
            3'b101:begin
                out=data5;
            end
            default:out=0;
      
        endcase
    end

endmodule

tip: be careful of the location of endcase and end


6. Always case2

problem statement

A priority encoder is a combinational circuit that, when given an input bit vector, outputs the position of the first 1 bit in the vector. For example, a 8-bit priority encoder given the input 8’b10010000 would output 3’d4, because bit[4] is first bit that is high.

Build a 4-bit priority encoder. For this problem, if none of the input bits are high (i.e., input is zero), output zero. Note that a 4-bit number has 16 possible combinations.
answer

module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always @(*)begin
        case(1)
            in[0]:pos=0;
            in[1]:pos=1;
            in[2]:pos=2;
            in[3]:pos=3;
            default:pos=0;
        endcase
    end
endmodule

7. Always casez

note

From the previous exercise (always_case2), there would be 256 cases in the case statement. We can reduce this (down to 9 cases) if the case items in the case statement supported don’t-care bits. This is what casez is for: It treats bits that have the value z as don’t-care in the comparison.

For example, this would implement the 4-input priority encoder from the previous exercise:

always @(*) begin
    casez (in[3:0])
        4'bzzz1: out = 0;   // in[3:1] can be anything
        4'bzz1z: out = 1;
        4'bz1zz: out = 2;
        4'b1zzz: out = 3;
        default: out = 0;
    endcase
end

problem statement

Build a priority encoder for 8-bit inputs. Given an 8-bit vector, the output should report the first (least significant) bit in the vector that is 1. Report zero if the input vector has no bits that are high. For example, the input 8’b10010000 should output 3’d4, because bit[4] is first bit that is high.
answer

module top_module (
    input [7:0] in,
    output reg [2:0] pos );
    always @(*)begin
        casez(in[7:0])
            8'bzzzzzzz1:pos=0;
            8'bzzzzzz1z:pos=1;
            8'bzzzzz1zz:pos=2;
            8'bzzzz1zzz:pos=3;
            8'bzzz1zzzz:pos=4;
            8'bzz1zzzzz:pos=5;
            8'bz1zzzzzz:pos=6;
            8'b1zzzzzzz:pos=7;
            default:pos=0;
        endcase
    end
endmodule

8.Always nolatches

note

To avoid creating latches, all outputs must be assigned a value in all possible conditions (See also always_if2). Simply having a default case is not enough. You must assign a value to all four outputs in all four cases and the default case. This can involve a lot of unnecessary typing. One easy way around this is to assign a “default value” to the outputs before the case statement:

always @(*) begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    case (scancode)
        ... // Set to 1 as necessary.
    endcase
end

This style of code ensures the outputs are assigned a value (of 0) in all possible cases unless the case statement overrides the assignment. This also means that a default: case item becomes unnecessary.

problem statement

Your circuit has one 16-bit input, and four outputs. Build this circuit that recognizes these four scancodes and asserts the correct output.
solution

module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  ); 
    always @(*)begin
        left=0;down=0;right=0;up=0;
        case(scancode)
            16'he06b:left=1;
            16'he072: down=1;
            16'he074:right=1;
            16'he075: up=1;
        endcase
    end
endmodule
### 回答1: 《有限元程序-第二版》是一本关于有限元方法的教材。有限元方法是一种用于求解工程问题的数值方法,广泛应用于力学、结构、流体力学等领域。本书的第二版相比第一版做了一些更新和补充。 这本书首先介绍了有限元分析的基本原理和步骤。通过将连续问题离散化为有限个子域单元,然后构建节点间的连接关系,可以得到线性方程组。接着,介绍了单元的选取方法和常用的插值函数,这些是构建有限元模型的基础。 在模型建立完成后,本书介绍了求解线性方程组的方法,包括矩阵求逆、高斯消元、共轭梯度等。同时,也介绍了非线性方程组的求解方法,如牛顿法和弧长法。这些方法可以用于求解各种不同类型的工程问题。 在第二版中,也增加了对多物理场耦合问题的讨论。多物理场耦合是指不同物理量之间相互影响的情况,如结构与流体的耦合、热传导与机械变形的耦合等。通过有限元方法,可以模拟和分析这些复杂的耦合问题,并得到准确的结果。 此外,本书还介绍了有限元后处理的技术,包括结果的可视化和分析。通过绘制等值线图、云图等图形,可以更好地理解和解释有限元计算结果。 总之,《有限元程序-第二版》是一本全面介绍有限元方法的教材,从理论到实践都有详细的讲解。无论是学习有限元方法的初学者还是从事有限元分析工作的工程师,都可以从本书中获得帮助。 ### 回答2: 《有限元程序 - 第二版》是一本与有限元分析相关的重要参考书。有限元方法是一种数值分析技术,用于求解结构力学、流体力学、电磁场、热传导等领域中的物理问题。该书覆盖了有限元方法的基础理论、数值计算方法以及工程应用等方面的内容。 第二版相对于第一版进行了更新和改进。首先,书中对有限元理论进行了更加详细和系统的介绍,包括有限元的基本原理、离散化方法、形函数的选择以及误差估计等。此外,书中还介绍了不同类型的有限元、有限元网格划分技术以及常用的数值积分方法等。 《有限元程序 - 第二版》还提供了丰富的示例和案例,以帮助读者理解和掌握有限元方法的实际应用。书中给出了具体的算法和代码,并通过计算机仿真实验来验证有限元方法的有效性和准确性。 此外,该书还介绍了一些常用的有限元软件和工具,如ANSYS、ABAQUS等,以及如何使用这些软件进行结构分析和优化设计。 总的来说,《有限元程序 - 第二版》是一本非常有价值的专业书籍,对于从事结构力学、流体力学、电磁场、热传导等领域研究的工程师和学者来说是一本不可或缺的参考资料。无论是初学者还是有经验的专业人士都可以从中获得有关有限元分析的理论知识和实际应用方面的宝贵信息。 ### 回答3: 《有限元程序-第二版》是一本非常重要的书籍,它涵盖了有限元程序的基本原理和方法。有限元分析是一种广泛应用于工程领域的数值方法,用于解决结构力学、热力学和流体力学等问题。 本书首先介绍了有限元方法的基本概念,包括离散化、插值函数和加权残差方法等。其次,书中详细介绍了有限元分析的基本步骤,包括建立有限元模型、确定系统边界条件、选择适当的数学模型和求解技术等。这些步骤使读者能够了解如何从实际工程问题出发,建立相应的数学模型,并通过有限元分析得出准确的结果。 此外,本书还介绍了有限元方法的进阶内容,包括非线性和动态分析、优化设计和不确定性分析等。这些内容对于解决复杂的工程问题非常重要,能够帮助工程师们提高设计效率和准确性。 本书第二版在第一版的基础上进行了更新和完善。它包含了最新的研究成果和工程实践经验,丰富了实例和案例分析,使读者能够更好地理解和应用有限元程序。此外,第二版还对一些问题进行了补充和改进,使其更贴近实际工程应用。 总之,《有限元程序-第二版》是一本全面介绍有限元分析方法和技术的重要参考书,对于从事工程分析和设计的人员来说,具有很高的参考价值。它不仅能够帮助读者掌握有限元方法的基本原理和操作技巧,还能够提供解决复杂工程问题的思路和方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值