【verilog学习12】HDLBits:Procedures (Always block/case+Avoiding latches)

I. Always blocks(combinational)

1.代码编写

// 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.提交结果

在这里插入图片描述

3.题目分析

Combinational always blocks are equivalent to assign statements.
组合逻辑always块等同于assign。
A note on wire vs. reg: The left-hand-side of an assign statement must be a net type (e.g., wire), while the left-hand-side of a procedural assignment (in an always block) must be a variable type (e.g., reg). These types (wire vs. reg) have nothing to do with what hardware is synthesized, and is just syntax left over from Verilog’s use as a hardware simulation language.
关于连线与reg的注释:赋值语句assign的左侧必须是网络类型(例如,wire),而过程赋值的左侧(在过程块中)必须是变量类型(例如reg)。 这些类型(wire vs. reg)与硬件合成无关,只是Verilog用作硬件模拟语言时遗留下来的语法。

II. Always blocks(clocked)

1.代码编写

// 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

2.提交结果

在这里插入图片描述

3.题目分析

分别用assign、always(combinational)、always(clocked)来实现赋值。

III. Always if (if statement)

1.代码编写

// synthesis verilog_input_version verilog_2001
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&sel_b2) out_always=b;
        else out_always=a;
    end
endmodule

2.提交结果

在这里插入图片描述

3.题目分析

两种方法(assign_if,always_if)分别实现if语句。

IV. Always if2 (if statement latches)

1.代码编写

// synthesis verilog_input_version verilog_2001
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)
           shut_off_computer = 1;
        else shut_off_computer = 0;
    end

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

endmodule

2.提交结果

在这里插入图片描述

3.题目分析

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.
应确保if(case)分支中包含了所有情况,否则会生成锁存器。
题目要求: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.

V. Always case(Case statement)

1.代码编写

// synthesis verilog_input_version verilog_2001
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: out=data0;
            3'b001: out=data1;
            3'b010: out=data2;
            3'b011: out=data3;
            3'b100: out=data4;
            3'b101: out=data5;
            default:out=4'b0000;
        endcase
    end

endmodule

2.提交结果

在这里插入图片描述

3.题目分析

  • The case statement begins with case and each “case item” ends with a colon. There is no “switch”.
    分支语句后为冒号,不用switch。
  • Each case item can execute exactly one statement. This makes the “break” used in C unnecessary. But this means that if you need more than one statement, you must use begin … end.
  • Duplicate (and partially overlapping) case items are permitted. The first one that matches is used. C does not allow duplicate case items.
    允许分支表达式重复(或部分重叠),会采用首个匹配的分支。(在C中不允许重复)

VI.Always case2 (Priority encoder)

1.代码编写

// synthesis verilog_input_version verilog_2001
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always@(*) begin
    case(in)
        4'h0: pos=2'd0;
        4'h1: pos=2'd0;
        4'h2: pos=2'd1;
        4'h3: pos=2'd0;
        
        4'h4: pos=2'd2;
        4'h5: pos=2'd0;
        4'h6: pos=2'd1;
        4'h7: pos=2'd0;
        
        4'h8: pos=2'd3;
        4'h9: pos=2'd0;
        4'hA: pos=2'd1;
        4'hB: pos=2'd0;
        
        4'hC: pos=2'd2;
        4'hD: pos=2'd0;
        4'hE: pos=2'd1;
        4'hF: pos=2'd0;
        
    endcase
    end
endmodule

2.提交结果

在这里插入图片描述

3.题目分析

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.
输出首个“高位”。

Hint: Using hexadecimal (4’hb) or decimal (4’d11) number literals would save typing vs. binary (4’b1011) literals.
同样是4bit长的数值,用16进制/10进制表示,就比用2进制表示更节省空间。

4'hC: pos=2'd2;
4'hC表示4bit宽的十进制12(二进制1100),右侧表示2bit宽的十进制2(二进制10)。

VII. Always casez (Priority encoder with casez)

1.代码编写

// synthesis verilog_input_version verilog_2001
module top_module (
    input [7:0] in,
    output reg [2:0] pos  );
    always@(*) begin
        casez(in)
            8'bzzzzzzz1: pos=3'd0;
            8'bzzzzzz10: pos=3'd1;
            8'bzzzzz100: pos=3'd2;
            8'bzzzz1000: pos=3'd3;
            8'bzzz10000: pos=3'd4;
            8'bzz100000: pos=3'd5;
            8'bz1000000: pos=3'd6;
            8'b10000000: pos=3'd7;
            default: pos=3'd0;
        endcase
    end
endmodule

2.提交结果

在这里插入图片描述

3.题目分析

case、casez、casex的真值表:
在这里插入图片描述
可见:

  • 使用case时,需区分x,z。
  • 使用casez时,z可实现全匹配,需区分x。
  • 使用casex时,x,z均可实现全匹配。
  • 但一般使用casez而不用casex,前者还可以表示don‘t care的值。
  • 电路中可以用?代替 z。
  • e.g. 对于分支表达式2’b1?
    在case中,可匹配2’b1z;在casez中,可匹配2’b11、2’b10、2’b1x、2’b1z;在casex中,可匹配2’b11、2’b10、2’b1x、2’b1z。

VIII. Always nolatches(Avoiding latches)

1.代码编写

// synthesis verilog_input_version verilog_2001
module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  ); 
    always@(*) begin
        left=1'b0;down=1'b0;right=1'b0;up=1'b0; //别写在case里第一句了!!!
        case(scancode)
            16'he06b: left=1'b1;
            16'he072: down=1'b1;
            16'he074: right=1'b1;
            16'he075: up=1'b1;
        endcase
    end
endmodule

2.提交结果

在这里插入图片描述

3.题目分析

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.
用default value 代替default case,节省unecessary typing(从前每个分支即default分支都需要规定四个信号的装填,现在只需要规定一个)。

### 关于HDLBits平台上的Verilog学习资源 对于希望在线上通过实践来掌握Verilog硬件描述语言的学习者而言,HDLBits提供了一个理想的环境[^3]。该平台不仅包含了丰富的练习题目,而且覆盖了从基础到高级的各种概念和技术要点。 #### 练习题目的范围 HDLBits中的问题集涵盖了多个方面,包括但不限于基本语法、算术运算、条件语句以及更复杂的主题比如状态机的设计等。这些问题被精心设计成逐步引导用户深入理解Verilog的功能特性及其应用领域。 #### 学习路径建议 为了有效地利用这个平台进行自学,可以从简单的位操作和布尔表达式开始尝试解决一些入门级挑战[^1]。随着技能的增长,可以逐渐过渡到处理更加复杂的情况,例如编写测试平台(TB)[^2]或是实现有限状态机(FSM)。 #### 示例代码片段展示如何创建一个简单的组合逻辑电路 下面是一个非常基础的例子,展示了怎样定义两个输入信号`a`和`b`并计算它们之间的按位与(`&`)的结果: ```verilog // 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 ``` 此模块实现了两种不同的方式来进行相同的逻辑运算——一种是直接赋值给wire类型的输出端口;另一种则是使用always块更新reg类型的寄存器变量[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值