Procedures

Always blocks(combinational)-Alwaysblock1

题目描述:分别用assign连续赋值和always过程块描述 逻辑与门

 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.

 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;

 solution

// synthesis verilog_input_version verilog_2001
module top_module(
    input a, 
    input b,
    output wire out_assign,
    output reg out_alwaysblock
);//注意assign必须用wire声明,always必须用reg声明
   
    assign out_assign = a & b;
    always @(*) out_alwaysblock = a & b;            //加不加begin-end都可以

endmodule

Always blocks(clocked)-Alwaysblock2

题目描述: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.

solution

// synthesis verilog_input_version verilog_2001
module top_module(
    input clk,
    input a,
    input b,
    output wire out_assign,       //用wire声明
    output reg out_always_comb,
    output reg out_always_ff   ); //用reg声明
    
    assign out_assign = a ^ b;
    always @(*) out_always_comb = a ^ b;
    always @(posedge clk) out_always_ff <= a ^ b;    //非阻塞赋值,加不加begin-end都可以

endmodule

If statement(Always if)

题目描述: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.

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 if mux.png

always @(*) begin
    if (condition) begin      //begin可以不加,对应的end也要去掉
        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;

However, the procedural if statement provides a new way to make mistakes. The circuit is combinational only if out is always assigned a value.

 solution

// 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) begin
            out_always = b;
        end
        else begin
            out_always = a;
        end
    end

endmodule

If statement latches(Always if2)

题目描述:

 为避免出现锁存器,组合电路必须为所有输出赋值,这时需要用到else语句或给输出端口赋默认值。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.

 solution

// 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                 //This is a combinational circuit组合电路
        if (cpu_overheated) begin     //这里加begin,且一共有3个begin,3个end;如果不加也可以
           shut_off_computer = 1;
    end
    else begin
        shut_off_computer = 0;
    end
    end                               //注意加end的个数
    
    always @(*) begin
        if (~arrived) begin
           keep_driving = ~gas_tank_empty;
    end
    else begin
        keep_driving = 0;
    end
    end
    
endmodule

Case statement(Always case1)

题目描述:

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.

Be careful of inferring latches(需要加default)

 always @ (a, b, c, sel) begin
    case(sel)
      2'b00    : out = a;         // If sel=0, output is a
      2'b01    : out = b;         // If sel=1, output is b
      2'b10    : out = c;         // If sel=2, output is c
      default  : out = 0;         // If sel is anything else, out is always 0
    endcase
  end
endmodule
————————————————
版权声明:本文为CSDN博主「李锐博恩」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Reborn_Lee/article/details/107446020

 solution 1   纯case块

// 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 = 3'b000;
        endcase
    end

endmodule

solution 2    begin-end

// 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: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:begin
                out = 3'b000;
            end
        endcase
    end

endmodule

solution 3     default用case语句表示,其他用begin语句表示

// 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: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 = 3'b000;   //也可以直接写成default:out = 3'b0;其中3'b必须写出来 
        endcase
    end

endmodule

Priority encoder(Always case2)

题目描述:

优先编码器:

HDLbits中举例的8位优先编码器其实是3位优先编码器(可能是中英文说法不同,中文说3位编码器是指3位输出代码,8位编码器是指8位输入信号,其实是指同一个编码器),作用是输出3位二进制代码,则有2^3个输出代码,必须对应有至少8个输入信号,如果是普通编码器则必须是8位输入信号,因为输入信号中不能同时有两个及以上的1,此时输入信号必须有约束条件。

而优先编码器则不需要约束,8个输出代码,可以有2^8个输入信号(但是可以分为8类),一个信号中可以有若干个1,输出代码取决于输入信号中第一个1出现的位置(注意右起第一位的位置为0,第2位为1,因为I7I6I5...I1I0)。

solution 1   纯case块,注意pos=可以用十进制'd表示,也可以用二进制'b表示,即2'd0或2'b00都可以,verilog都可以识别。

// synthesis verilog_input_version verilog_2001
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
  always @(*)begin
    case(in)        
        4'b0001:pos = 2'd0;
        4'b0010:pos = 2'd1;
        4'b0011:pos = 2'd1;
        4'b0100:pos = 2'd2;
        4'b0101:pos = 2'd0;
        4'b0110:pos = 2'd1;
        4'b0111:pos = 2'd0;
        4'b1000:pos = 2'd3;
        4'b1001:pos = 2'd0;
        4'b1010:pos = 2'd1;
        4'b1011:pos = 2'd0;
        4'b1100:pos = 2'd2;
        4'b1101:pos = 2'd0;
        4'b1110:pos = 2'd1;
        4'b1111:pos = 2'd0;
        default: pos = 2'd0;
    endcase 
  end

endmodule

solution 2

case语句以case开始,每个case的选项以分号结束。
每个case的选项中只能执行一个statement,所以就无需break语句。但如果我们想在一个case选项中执行多个statement,就需要使用begin...end
case中可以有重复的case item,首次匹配的将会被执行
————————————————
版权声明:本文为CSDN博主「日拱一卒_未来可期」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42334072/article/details/108296660

// synthesis verilog_input_version verilog_2001
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );

  always @(*)begin
      case(1)        
          in[0]:pos = 2'd0;    //in[0]  代表in的第1位数据,必须用[],而不是()
          in[1]:pos = 2'd1;
          in[2]:pos = 2'd2;
          in[3]:pos = 2'd3;
        default: pos = 2'd0;
    endcase 
  end

endmodule

根据上面所说的case的性质,case中可以有重复的case item,但首次匹配的才会被执行。再看上面的case语句,case(1),in[0]:pos = 2'd0;即从低到高位去比较in中是否有数据位为1,下面即使有重复为1的也只会执行首次匹配的操作。如此,N位优先编码器只需要N个case分支即可,大大简化代码量。

Priority encoder with casez(Always casez)

题目描述:

casez用法

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

 注意:4'b1111如何选择?仍然按顺序选择

Notice how there are certain inputs (e.g., 4'b1111) that will match more than one case item. The first match is chosen (so 4'b1111 matches the first item, out = 0, but not any of the later ones).

 z可以用x或者?代替,如2'bz0就是2’b?0,作用是一样的

  • There is also a similar casex that treats both x and z as don't-care. I don't see much purpose to using it over casez.
  • The digit ? is a synonym for z. so 2'bz0 is the same as 2'b?0

 solution

// synthesis verilog_input_version verilog_2001
module top_module (
    input [7:0] in,
    output reg [2:0] pos  );
    always @(*) begin
        casez(in)              //如果in=8'b.......
        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

solution 2

// synthesis verilog_input_version verilog_2001
module top_module (
    input [7:0] in,
    output reg [2:0] pos  );
    
    always@(*)begin
        casez(in)
            8'bzzzzzzz1:begin    //另一种写法;相对于之前的只是加了begin-end,其余完全不变
                pos = 3'd0;
            end
            8'bzzzzzz10:begin
                pos = 3'd1;
            end
            8'bzzzzz100:begin
                pos = 3'd2;
            end
            8'bzzzz1000:begin
                pos = 3'd3;
            end
            8'bzzz10000:begin
                pos = 3'd4;
            end
            8'bzz100000:begin
                pos = 3'd5;
            end
            8'bz1000000:begin
                pos = 3'd6;
            end
            8'b10000000:begin
                pos = 3'd7;
            end
            default:begin
                pos = 3'd0;
            end
        endcase
    end
            
endmodule

另一种写法;相对于之前的只是加了begin-end,其余完全不变。

Avoiding latches(Always nolatches)

solution 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之前提前给输出端赋值0,在case判定中      
        case (scancode)                        //覆盖,可以避免锁存器的出现且不写default赋值。
           16'he06b: left = 1'b1;
           16'he072: down = 1'b1;
           16'he074: right = 1'b1;
           16'he075: up = 1'b1;
        endcase
    end     
    
endmodule

Reminder:

为避免生成锁存器,所有的输入情况必须要被考虑到。但仅有一个简单的default是不够的,我们必须在case item和default中为4个输出进行赋值,这会导致很多不必要的代码编写。

一种简单的方式就是对输出先进行赋初值的操作,这种类型的代码确保在所有可能的情况下输出都被赋值,除非case语句覆盖了赋值。这也意味着不再需要case语句中的default项。
————————————————
版权声明:本文为CSDN博主「日拱一卒_未来可期」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42334072/article/details/108296660

 solution 2: 另一个博主的习惯,在case语句中加入begin-end

// 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 (scancode)
           16'he06b: begin
               left = 1'b1;
           end
           16'he072: begin
               down = 1'b1;
           end
           16'he074: begin
               right = 1'b1;
           end
           16'he075: begin
               up = 1'b1;
        
               end
        endcase
    end     
    
endmodule

 总结:

  • 学习了组合时序两种always块,并知晓了两种类型的always块中变量的类型即赋值方式。何时使用wire与reg,何时用阻塞=非阻塞<=赋值。always两种语句中的begin-end写不写不影响verilog运行。
  • 学习了如何在使用if和case语句时避免生成锁存器:将所有状态均考虑到并为其输出赋值,考虑不全可用else/default。
  • 在case之前为所有输出赋初值,这样可以不用使用default,除非满足case item进行覆盖赋值,否则仍保持初值。
  • 学习了case语句的妙用,以及使用casez忽略无关位,更简便的实现优先编码器。

————————————————
版权声明:本文为CSDN博主「日拱一卒_未来可期」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42334072/article/details/108296660

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值