【Verilog--Procedures】

Verilog--Procedures

    • 1.4 Procedures
      • 1.4.0 Comb VS Clocked
      • 1.4.1 always-if
        • 1.4.1.1 Avoid latches
      • 1.4.2 case

【博客首发于微信公众号《漫谈芯片与编程》,欢迎大家关注,多谢大家】
电路模块是由通过导线连接的逻辑门组成,任何电路都可以表示为模块和赋值语句的某种组合。但有时候这不是描述电路的方便方法。过程(其中always是一个例子)提供了另一种描述电路的语法。
circuits are composed of logic gates connected with wires, any circuit can be expressed as some combination of modules and assign statements. Sometimes It is not the convenient way to describe the circuit.Procedures (of which always blocks are one example) provide an alternative syntax for describing circuits.
For synthesizing hardware:
* Combinational: always @(*) ; //equivalent to assign statements
* Clocked: always @(posedge clk)

1.4 Procedures

1.4.0 Comb VS Clocked

  1. Combinational: always @(*)
    Procedural blocks have a richer set of statements (e.g., if-then, case), cannot contain continuous assignment;
    【Verilog--Procedures】_第1张图片

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. 赋值语句的左侧必须是网络类型(例如,wire),而过程赋值的左侧(在always块中)必须是变量类型(例如,reg)。这些类型(wire 与 reg)与合成的硬件无关,只是 Verilog 作为硬件模拟编译语言使用时遗留下来的语法。

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

2.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;
时钟always块创建一个组合逻辑块,就像组合always块一样,而且还在组合逻辑块的输出处创建一组触发器(或“寄存器”)。逻辑块的输出不是立即改变,而是仅在下一个 (posege clk) 之后改变。

Ways to set value:

  • 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.
    为什么有上述赋值:充分理解对于硬件设计来说并不是特别有用,需要理解对 Verilog 模拟器如何跟踪事件更有帮助。不遵循此规则会导致极难发现错误,这些错误既不确定又在仿真和合成硬件之间存在差异。

Practice:
【Verilog--Procedures】_第2张图片

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

1.4.1 always-if

//--another demo
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 ==1'b1) ? 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
1.4.1.1 Avoid latches

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.
语法正确的代码不一定会产生合理的电路(组合逻辑+触发器)。通常的原因是:“除了指定的情况之外,会发生什么情况?”。 Verilog 的答案是:保持输出不变。
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.
Solution: 这通常意味着您始终需要 else 子句或为输出分配默认值。

示例:在组合逻辑中,输出必须要有赋值,且不能是自己本身;


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

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

  //====keep_driving logic
    always @(*) begin
        if(arrived==1'b1) begin
        	keep_driving = 1'b0;
        end else if((~arrived) && (~gas_tank_empty)) begin
            keep_driving = 1'b1;
        end else begin
            keep_driving = 1'b0; 
        end
    end

endmodule

1.4.2 case

  1. demo case
    在好多种情况下,case语句非常的方便;
    示例:
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

//==6-to-1 multiplexer
// 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   );//

    //==6-to-1 multiplexer
    always@(*) begin  // This is a combinational circuit
        case(sel) 
            0: out = data0;
            1: out = data1;
            2: out = data2;
            3: out = data3;
            4: out = data4;
            5: out = data5;
            default: out = 4'b0;
        endcase
    end
	
endmodule

2.priority encoder

// synthesis verilog_input_version verilog_2001
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
	
    always @(*) begin
        casez(in[3:0])
            4'b???1: pos = 2'b00;
            4'b??10: pos = 2'b01;
            4'b?100: pos = 2'b10;
            4'b1???: pos = 2'b11;
            default: pos = 2'b00;
        endcase
    end
    
endmodule

// synthesis verilog_input_version verilog_2001
module top_module (
    input [7:0] in,
    output reg [2:0] pos );
	
    always @(*) begin
        casez(in[7:0])
            8'bzzzz_zzz1: pos = 3'b000;
            8'bzzzz_zz10: pos = 3'b001;
            8'bzzzz_z100: pos = 3'b010;
            8'bzzzz_1000: pos = 3'b011;
            8'bzzz1_0000: pos = 3'b100;
            8'bzz10_0000: pos = 3'b101;
            8'bz100_0000: pos = 3'b110;
            8'b1000_0000: pos = 3'b111;
            default: pos = 3'b000;
    	endcase
    end
    
endmodule

3.Avoid latches : set value to outputs
在赋值的时候,必须为所有的输出进行赋值;

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[15:0])
            16'he06b: left = 1'b1;
            16'he072: down = 1'b1;
            16'he074: right= 1'b1;
            16'he075: up = 1'b1;
        endcase
    end
endmodule

你可能感兴趣的:(HDL,HDL)