2021年5月23日 星期日

HBLbits_Verilog Procedures

HBLbits_Verilog Procedures 

Procedures

Procedures include always, initial, task, and function blocks. Procedures allow sequential statements (which cannot be used outside of a procedure) to be used to describe the behaviour of a circuit.

·        Always blocks (combinational)

·        Always blocks (clocked)

·        If statement

·        If statement latches

·        Case statement

·        Priority encoder

·        Priority encoder with casez

·        Avoiding latches

Alwaysblock1

For synthesizing hardware, two types of always blocks are relevant:

·        Combinational: always @(*)

·        Clocked: always @(posedge clk)

·        assign out1 = a & b | c ^ d;

·        always @(*) out2 = a & b | c ^ d;


·        For combinational always blocks, always use a sensitivity list of (*)

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

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

 

 

Alwaysblock2

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

·        Combinational: always @(*)

·        Clocked: always @(posedge clk)

Blocking vs. Non-Blocking Assignment

There are three types of assignments in Verilog:

Continuous assignments (assign x = y;)

Procedural blocking assignment: (x = y;).

In a combinational always block, use blocking assignments. 

Procedural non-blocking assignment: (x <= y;).

      In a clocked always block, use non-blocking assignments.

 

Build an XOR gate three ways, using an assign statement, a combinational always block, and a clocked always block.


// 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@(*) begin

          out_always_comb  =  a^b;

    end

   

    always@(posedge clk) begin

          out_always_ff  <= a^b;

    end  

endmodule

 

 

Always if

 

 



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;

 

 

Build a 2-to-1 mux that chooses between a and b

sel_b1

sel_b2

out_assign
out_always

0

0

a

0

1

a

0

0

a

1

1

b

 

// 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==0 && sel_b2==0)?a:(sel_b1==0 && sel_b2==1)?a:

        (sel_b1==1 && sel_b2==0)? a: b;

   

always@(*) begin

        if (sel_b1==0 && sel_b2==0) begin

                    out_always=a;

        end

        else if (sel_b1==0 && sel_b2==1) begin

                    out_always=a;

        end

        else if (sel_b1==1 && sel_b2==0) begin

                    out_always=a;

        end  else

                    out_always=b;

    end

   

endmodule

 

 

Always if2

A common source of errors: How to avoid making 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

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

Always if2.png

 

修改前

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

    end

 

    always @(*) begin

        if (~arrived)

           keep_driving = ~gas_tank_empty;

    end

 

endmodule

修改後

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

           shut_off_computer = 1;

        end

        else begin

           shut_off_computer = 0;

        end

           

    end

 

    always @(*) begin

        if (~arrived) begin

           keep_driving = ~gas_tank_empty;

        end else

          keep_driving = ~arrived;

    end

 

endmodule

Always case

 

Case statements in Verilog are nearly equivalent to a sequence of if-elseif-else that compares one expression to a list of others. 

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

 

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. 

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

Always case2

Build a 4-bit priority encoder.



// synthesis verilog_input_version verilog_2001

module top_module (

    input [3:0] in,

    output reg [1:0] pos  );

        always @(*) begin                  // Combinational always block

                case (in)

                        4'h0: pos = 2'h0;     // hexadecimal

                        4'h1: pos = 2'h0;

                        4'h2: pos = 2'h1;

                        4'h3: pos = 2'h0;

                        4'h4: pos = 2'h2;

                        4'h5: pos = 2'h0;

                        4'h6: pos = 2'h1;

                        4'h7: pos = 2'h0;

                        4'h8: pos = 2'h3;

                        4'h9: pos = 2'h0;

                        4'ha: pos = 2'h1;

                        4'hb: pos = 2'h0;

                        4'hc: pos = 2'h2;

                        4'hd: pos = 2'h0;

                        4'he: pos = 2'h1;

                        4'hf: pos = 2'h0;

                        default: pos = 2'b0;        // Default case.

                endcase

        end

 

endmodule

Always casez

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

 

Build a priority encoder for 8-bit inputs. 

// synthesis verilog_input_version verilog_2001

module top_module (

    input [7:0] in,

    output reg [2:0] pos  );

      always @(*) begin

        casez (in)

           8'bzzzz_zzz1: pos = 3'd0;   // in[3:1] can be anything

           8'bzzzz_zz1z: pos = 3'd1;

          8'bzzzz_z1zz: pos = 3'd2;

           8'bzzzz_1zzz: pos = 3'd3;

          8'bzzz1_zzzz: pos = 3'd4;

          8'bzz1z_zzzz: pos = 3'd5;

          8'bz1zz_zzzz: pos = 3'd6;           

          8'b1zzz_zzzz: pos = 3'd7;           

           default: pos = 3'd0;

         endcase

      end

endmodule

 

Always nolatches

 

Suppose you're building a circuit to process scancodes from a PS/2 keyboard for a game. Given the last two bytes of scancodes received, you need to indicate whether one of the arrow keys on the keyboard have been pressed. This involves a fairly simple mapping, which can be implemented as a case statement (or if-elseif) with four cases.

Scancode [15:0]

Arrow key

16'he06b

left arrow

16'he072

down arrow

16'he074

right arrow

16'he075

up arrow

Anything else

none

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

always @(*) begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    case (scancode)
        ... // Set to 1 as necessary.
    endcase
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

        case (scancode)

           16'he06b: begin 

                             left=1;

                             down=0;

                             right=0;

                             up=0;  

                          end

           16'he072:begin 

                             left=0;

                             down=1;

                             right=0;

                             up=0;  

                          end 

           16'he074:begin 

                             left=0;

                             down=0;

                             right=1;

                             up=0;  

                          end  

           16'he075:begin 

                             left=0;

                             down=0;

                             right=0;

                             up=1;  

                          end

            default: begin

                left=0;

                down=0;

                right=0;

                up=0;

            end

        endcase

    end

endmodule

 

 


沒有留言:

張貼留言

2024_09 作業3 以Node-Red 為主

 2024_09 作業3  (以Node-Red 為主  Arduino 可能需要配合修改 ) Arduino 可能需要修改的部分 1)mqtt broker  2) 主題Topic (發行 接收) 3) WIFI ssid , password const char br...