HDLBits Chapter 5 exercises and answers

Keywords: Verilog

1. Ternary conditional operator

verilog has a ternary conditional operator (?:), just like C.

(condition ? if_true : if_false)

This can be used to select one of two values based on the condition on a line (multiplexer!) without using if then in the combined always block.

For example:

(0 ? 3 : 5)     // This is 5 because the condition is false.
(sel ? b : a)   // A 2-to-1 multiplexer between a and b selected by sel.

always @(posedge clk)         // A T-flip-flop.
  q <= toggle ? ~q : q;

always @(*)                   // State transition logic for a one-input FSM
  case (state)
    A: next = w ? B : A;
    B: next = w ? A : B;
  endcase

assign out = ena ? q : 1'bz;  // A tri-state buffer

((sel[1:0] == 2'h0) ? a :     // A 3-to-1 mux
 (sel[1:0] == 2'h1) ? b :
                      c )

practice:

Given four unsigned numbers, find the minimum. Unsigned numbers can be compared with standard comparison operators (a < b). Use the conditional operator to create a two-way minimum circuit, and then combine some of them to create a four-way minimum circuit. You may need some vectors for intermediate results.

Code implementation:

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

    wire [7:0]min1,min2;
    assign min1 = (a > b)? b : a;
    assign min2 = (c > d)? d : c;
    assign min = (min1 > min2)? min2 : min1;

endmodule

Verification results:

2. Reduction operator

You are already familiar with bitwise operations between two values, such as a & B or a ^ b. Sometimes, you want to create a wide gate and operate all bits of a vector, such as (a [0] & A [1] & A [2] & A [3]...). If the vector is very long, it will become very boring.
The reduction operator can perform "and", "or" and "XOR" operations on the bits of the vector to produce a bit output.

& 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]

These are unary operators with only one operand (similar to the NOT operators! And ~).
You can also reverse the output of these gates to create NAND, NOR and XNOR gates, for example (~& d [7:0]).

practice:

Parity is often used as a simple method to detect errors when transmitting data over imperfect channels. Create a circuit that will calculate an 8-bit byte parity bit (the 9th bit byte will be added). We will use "even" parity, where the parity bit is the exclusive or of all 8 data bits.

Code implementation:

module top_module (
    input [7:0] in,
    output parity); 
    
	assign parity = ^ in;
    
endmodule

Verification results:

3. Reduction: wider door

Establish a combinational circuit with 100 inputs in [99:0].

There are 3 outputs:
①out_and: 100 input and gate output.
②out_or: 100 input OR gate output.
③out_xor: 100 input the output of XOR gate.

Code implementation:

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

Verification results:

4. Combined for loop: vector inversion 2

Given a 100 bit input vector [99:0], reverse its bit order.

Code implementation:

module top_module( 
    input [99:0] in,
    output [99:0] out
);

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

Verification results:

5. Combined for loop: 255 bit total count

The "total count" circuit calculates the number of "1" in the input vector. Construct the overall counting circuit for the 255 bit input vector.

Code implementation:

module top_module( 
    input [254:0] in,
    output [7:0] out );
	
    integer i;
    always@(*) begin
        out = 8'b0;
        for(i = 0;i <= 254;i = i + 1) begin
            out = out + in[i];
        end
    end
    
endmodule

Verification results:

6. Generate for loop: 100 bit binary adder 2

Create a 100 bit binary traveling wave carry adder by instantiating 100 full adders. The adder adds two 100 bit numbers and a carry to produce a 100 bit sum and carry. To encourage you to actually instantiate the full adder, you also output the carry of each full adder in the traveling wave carry adder. cout[99] is the last carry of the last full adder, which you often see.

expand:

generate syntax

(1) Define genvar as the loop variable of generate.
(2) The for statement defined in the generate statement must have a begin to prepare for subsequent label addition.
begin must have a name, that is, it must have a label, because the label will be used as the instance name of the generate loop.
(3) The types that can be used in generate statements are:
① module
② UDP (user defined primitive)
③ Gate level primitive
④ Continuous assignment statement
⑤ initial or always statement

The basic structure of generate is as follows:

genvar Loop variable name;
generate

    // generate loop statement
    // generate conditional statement
    // generate branch statement
    // Nested generate statement

endgenerate

Code implementation:

module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );
	
    genvar i;
	generate
        for( i = 0 ; i < 100; i = i + 1 )
            begin:adder
                if(i==0)
                   	begin
                        assign {cout[i],sum[i]} = a[i] + b[i] + cin;
                	end
                else
                    begin
                        assign {cout[i],sum[i]} = a[i] + b[i] + cout[i-1];
                    end  
            end
	endgenerate
    
endmodule

Verification results:

7. Generate for loop: 100 bit BCD adder

Provides you with a file called bcd_fadd's BCD one digit adder, which adds the sum and carry of two BCD numbers to produce a sum and carry.

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

Instantiate 100 bcds_ FADD copy to create a 100 bit BCD traveling wave carry adder. Your adder should add two 100 bit BCD numbers (packed into a 400 bit vector) and a carry to produce a 100 bit sum and operate.

Code implementation:

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

    wire [99:0]cout1;
    genvar i;
	generate
        for( i = 0 ; i < 100; i = i + 1 )
            begin:adder
                if(i==0)
                    bcd_fadd U0( .a(a[3:0]), .b(b[3:0]), .cin(cin), .cout(cout1[0]), .sum(sum[3:0]));
                else
                    bcd_fadd U1( .a(a[4*i+3:4*i]), .b(b[4*i+3:4*i]), .cin(cout1[i-1]), .cout(cout1[i]), .sum(sum[4*i+3:4*i]));
            end
    assign cout = cout1[99];
	endgenerate
    
endmodule

Verification results:

Posted by falcon8253 on Sun, 19 Sep 2021 13:54:17 -0700