HDLbits question brushing series 2-Verilog/Procedure & More features

Posted by Skyphoxx on Mon, 20 Sep 2021 08:37:55 +0200

  •   summary

This section mainly exercises the basic grammar of verilog.

  • Schematic diagram + code + simulation screenshot

  • Alwaysblock1

There are two types of composite awlays modules that can be integrated:

  1. always @(*); The variable processed inside is reg, and the overall function is equivalent to the assign statement. The assign statement cannot be used inside; You can use if then, case and other syntax. As long as the input changes, the output changes:
    1. assign out1 = a & b | c ^ d; // Out1 to the left of the equal sign must be a wire type variable,
    2. always @(*) out2 = a & b | c ^ d;    // Out2 to the left of the equal sign must be a variable of type reg.
    3. The functions of the above two codes are the same.
  2. always @(posedge clk)

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

  •  Alwaysblock2

  Let's continue to practice using always:

  • Combinational: always @(*):
    1. Equivalent to Assign to realize combined circuit
    2. Only blocking assignments (a=b) can be used.
    3. blocking
  • Clocked: always @(posedge clk) :
    1. It can also achieve the combinational circuit function of always @ (*), but it can also realize the trigger (register) function,
    2. This means that only the edge of the clock can output values.
    3. Only non blocking assignments (a < = b) can be used.
    4. non-blocking.
  • assign:
    1. Continuous replication,
    2. Key values cannot appear in the 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 @(*)
        out_always_comb = a ^ b;
    
    always @(posedge clk)
        out_always_ff <= a ^ b;
endmodule

  •  Always if

The if statement is used in the always block, which is similar to the c language. Try to take else scenarios into account. If else scenario is not considered, it is necessary to initialize the output signal.

// 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 == 1 && sel_b2 == 1) ? b : a;
    
    always @(*) begin
            if(sel_b1 == 1 && sel_b2 == 1) begin
    			out_always = b;            
            end
        	else begin
               out_always = a; 
            end 
    end
endmodule

  •  Always if2

  Be sure to take else scenarios into account. If else scenario is not considered, it is necessary to initialize the output signal. For this problem, the initial practice has gone far, and the state machine is actually used. In fact, the original intention of this topic is to describe the else scene.

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

    reg shut_off_state,shut_off_state_ns;
	reg drive_state, drive_ns;
    
    always @(*) begin
        shut_off_state = shut_off_state_ns;
    end
    
    always @(*) begin
    	if (cpu_overheated)
       		shut_off_state_ns = 1; 
  		else
            shut_off_state_ns = 0;     
    end

    always @(*) begin
    	if (shut_off_state)
       		shut_off_computer = 1; 
  		else
            shut_off_computer = 0;     
    end
    

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

endmodule

Method 2:  

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

  •  Always case

  Different from C syntax, there is no Switch keyword. Like if, the else scenario must be considered. There must be a default scenario. Unlike the C language, each case project is executed only once, so the Break keyword is not required.

// 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)
            0: out = data0;
            1: out = data1;
            2: out = data2;
            3: out = data3;
            4: out = data4;
            5: out = data5;
            default: out = 0;
        endcase
    end

endmodule

  •  Always case2

About this question, I mainly practice the other two variants of Case: casez and casex

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

    always @(*) begin 
        casex(in)
            4'bxxx1: pos = 0;
            4'bxx10: pos = 1;
            4'bx100: pos = 2;
            4'b1000: pos = 3;
            default: pos = 0;
        endcase
    end
endmodule
  •  Always casez
// 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

  •  Always nolatches

This problem is mainly to prevent the latch problem. When default cannot cover all possible, the output value should be initialized in advance.

// 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'b1;
            16'he072: down = 1'b1;
            16'he074: right = 1'b1;
            16'he075: up = 1'b1;
        endcase
    end

endmodule

 

  •  Conditional

This topic mainly exercises three conditional operations: (condition)  ? if_true  : if_false)

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//

    // assign intermediate_result1 = compare? true: false;
    assign min = (a<b && a<c && a<d) ? a:((b<c && b<d) ? b : (c<d)?c:d);

endmodule
  •  Reduction &Gates100

Reduce the syntax for continuous bit logic operations:

& a[3:0]     // AND: a[3]&a[2]&a[1]&a[0]. Equivalent to (a[3:0] == 4'hf)
| b[3:0]     // OR:  b[3]|b[2]|b[1]|b[0]. Equivalent to (b[3:0] != 4'h0)
^ c[2:0]     // XOR: c[2]^c[1]^c[0]
//Reduction
module top_module (
    input [7:0] in,
    output parity); 
	
    assign parity = ^in[7:0];
endmodule
//Gates100
module top_module( 
    input [99:0] in,
    output out_and,
    output out_or,
    output out_xor 
);

    assign out_and = & in[99:0];
    assign out_or = | in[99:0];
    assign out_xor = ^ in[99:0];
endmodule
  •  Vector100r
module top_module( 
    input [99:0] in,
    output [99:0] out
);

    int i;
    always @(*) begin
        for(i=0; i<=99;i++)begin
            out[i] = in[99-i]; 
        end
    end
endmodule

  • Popcount255  
//Method 1
module top_module( 
    input [254:0] in,
    output [7:0] out );

    integer i;
    
    always @(*) begin
        out = 0;
        for(i=0; i <= 254; i=i+1)
            if(((in>>i) & 1'b1) == 1'b1)
            out = out + 1;
    end

endmodule
//Method 2
module top_module( 
    input [254:0] in,
    output [7:0] out );

    integer i;
    
    always @(*) begin
        out = 0;
        for(i=0; i <= 254; i=i+1)
            out = out + in[i];
    end

endmodule

  • adder100i

Create a 100bit adder directly instead of instantiating it.

module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );

    integer i;
    always @(*) begin
        {cout[0],sum[0]} = a[0]+b[0]+ cin;
       for(i=1;i<=99;i=i+1) begin
           {cout[i],sum[i]} = a[i]+b[i]+ cout[i-1];
           end
    end
    
endmodule

  • Bcdadd100

This question is different from the previous one. The main exercise of this question is: generate         endgenerate

module top_module( 
    input [399:0] a, b,
    input cin,
    output cout,
    output [399:0] sum );

    
    
    wire[99:0] cout_temp;
    
    generate
		genvar i;
        for(i=0; i<=99; i=i+1)begin:add_400
            if(i == 0)begin
                bcd_fadd  inst(
                    .a(a[3:0]),
                    .b(b[3:0]),
                    .cin(cin),
                    .cout(cout_temp[0]),
                    .sum(sum[3:0])
                );
            end
            else begin
                 bcd_fadd  insts(
      				.a(a[i*4+3 : i*4]),
                    .b(b[i*4+3 : i*4]),
                    .cin(cout_temp[i-1]),
                    .cout(cout_temp[i]),
                    .sum(sum[i*4+3 : i*4])
            );    
            end
        end
		assign cout=cout_temp[99];
    endgenerate
endmodule
  • summary

Up to now, all the grammar knowledge of Verilog has been basically practiced. The key is to do the topic with the idea of circuit, not like C language.

Topics: Verilog ASIC