Always blocks (combinational)

Solution

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

Always blocks (clocked)

Solution

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

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.

If statement

语法格式:

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

这等效于条件运算符的连续赋值:

assign out = (condition) ? x : y;

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

    always @(*) begin 
        if (sel_b1 == 1 && sel_b2 == 1) begin 
            // 注意:`=`是用于过程赋值的,而逻辑比较应该使用`==`
            out_always = b;
        end
        else begin 
            out_always = a;  
        end  
    end
    
    assign out_assign = (sel_b1 == 1 && sel_b2 == 1) ? b : a;
    
endmodule

If statement latches

When designing circuits, you _must_ think first in terms of circuits:

  • I want this logic gate
  • I want a _combinational_ blob of logic that has these inputs and produces these outputs
  • I want a combinational blob of logic followed by a set of flip-flops

What you _must not_ do is write the code first, then hope it generates a proper circuit.

  • If (cpu_overheated) then shut_off_computer = 1;
  • If (~arrived) then keep_driving = ~gas_tank_empty;

在不提供 else clauses or a default value 的情况下,Verilog 将会 keep the outputs unchanged,这不是我们想要的。(因为本应 Combinational logic (e.g., logic gates) cannot remember any state.) 所以,Combinational circuits must have a value assigned to all outputs under all conditions.

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
        if (cpu_overheated)
           shut_off_computer = 1;
        else   // 添加else
           shut_off_computer = 0;
    end

    always @(*) begin
        if (arrived || gas_tank_empty)
           keep_driving = 0;
        else   //添加else
           keep_driving = 1;
    end

endmodule

Tips:

  • error 是 “流程跑不通”(工具拒绝执行,因为代码 / 设计非法);
  • incorrect 是 “流程跑得通,但结果不对”(代码合法,但逻辑错误)。

Case statement

语法格式:

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
  • The case statement begins with case and each "case item" ends with a colon. There is no "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.

Solution

// 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)
            4'b0000: out = data0;
            4'b0001: out = data1;
            4'b0010: out = data2;
            4'b0011: out = data3;
            4'b0100: out = data4;
            4'b0101: out = data5;
            default: out = 4'b0000;
        endcase  // 勿忘 case 语句的结束关键字  
    end

endmodule

Priority encoder

Tips:

  • 'b:二进制(Binary)
  • 'o:八进制(Octal)
  • 'h:十六进制(Hexadecimal)
  • 'd:十进制(Decimal)
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always @(*) begin
        case(in)
            4'b0000: pos = 0;
            4'b0001: pos = 0;
            4'b0010: pos = 1;
            4'b0011: pos = 0;
            4'b0100: pos = 2;
            4'b0101: pos = 0;
            4'b0110: pos = 1;
            4'b0111: pos = 0;
            4'b1000: pos = 3;
            4'b1001: pos = 0;
            4'b1010: pos = 1;
            4'b1011: pos = 0;
            4'b1100: pos = 2;
            4'b1101: pos = 0;
            4'b1110: pos = 1;
            4'b1111: pos = 0;
            default: pos = 0;
        endcase
    end
endmodule

记录从右(低位)向左数第一个高位的位置。

Priority encoder with casez

It treats bits that have the value z as don't-care in the comparison.

语法格式:

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

Solution

// 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'bzzzzzzz1: pos = 3'b000;
            8'bzzzzzz1z: pos = 3'b001;
            8'bzzzzz1zz: pos = 3'b010;
            8'bzzzz1zzz: pos = 3'b011;
            8'bzzz1zzzz: pos = 3'b100;
            8'bzz1zzzzz: pos = 3'b101;
            8'bz1zzzzzz: pos = 3'b110;
            8'b1zzzzzzz: pos = 3'b111;
           default: pos = 3'b000;
        endcase
    end
                
endmodule

Avoiding latches

One easy way to assign a "default value":

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

Solution

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