1
\$\begingroup\$

This is 32bit ALU with a zero flag,

F2:0 Function
000  A AND B
001  A OR B
010  A + B
011  not used
100  A AND B
101  A OR B
110  A − B
111  SLT

SLT is set less than, it sets the least the output of ALU to 1 if A < B


This is the ALU module

module alu(input logic [31:0] a, input logic [31:0] b, input logic [2:0] f, output logic [31:0] out, output logic zero);
    logic [31:0]tmp;
    always @(a, b,f)
        begin
        if (f == 3'b000)    // And
            out = a & b;
        else if( f == 3'b001)   // Or
            out = a | b;
        else if( f == 3'b010)   // Add
            out = a + b;
        else if( f == 3'b100)   // New and
            out = a & ~b;
        else if( f == 3'b101)   // New or
            out = a | ~b;
        else if( f == 3'b110)   // SUB
            out = a - b;
        else if( f == 3'b111)   // SLT
        begin
            tmp = a - b;
            out[31:1] = 31'h0;
            out[0] = (tmp[31] ==  1'b1);
        end
        if (out == 32'h00000000)
            zero = 1;
        else
            zero = 0;
    end
endmodule

This is the test bench I built for the code

module alu_tb;
    reg[31:0] a;
    reg [31:0] b;
    reg[2:0] f;
    wire [31:0] out;
    wire zero;
    alu DUT (a,b,f,out,zero);
    initial begin
        $dumpfile("alu.vcd");
        $dumpvars(0, DUT);
        $monitor("A = 0x%x, B = 0x%x, f=0b%b\n\tOut = 0x%x, z = %b", a, b,f, out, zero);

        f = 3'b010; // 0 + 0
        a = 32'h0000_0000;
        b = 32'h0000_0000;
        #10
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%s0 + 0 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b010; // 0 + (-1)
        a = 32'h0000_0000;
        b = 32'hFFFF_FFFF;
        #10
        if ( out !== 32'hFFFF_FFFF | zero !== 1'b0)
             $display("\t%s0 + (-1) failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'hFFFF_FFFF, 1'b0, "\033[0m");

        f = 3'b010; // 1 + (-1)
        a = 32'h0000_0001;
        b = 32'hFFFF_FFFF;
        #10
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%s1 + (-1) failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b010; // FF + 1
        a = 32'h0000_00FF;
        b = 32'h0000_0001;
        #10;
        if ( out !== 32'h100 | zero !== 1'b0)
             $display("\t%s0xFF + 1 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h100, 1'b0, "\033[0m");

        f = 3'b110; // 0 - 0
        a = 32'h0000_0000;
        b = 32'h0000_0000;
        #10;
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%s0 - 0 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b110; // 0 - (-1)
        a = 32'h0000_0000;
        b = 32'hFFFF_FFFF;
        #10;
        if ( out !== 32'h1 | zero !== 1'b0)
             $display("\t%s0 - (-1) failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h1, 1'b0, "\033[0m");

        f = 3'b110; // 1 - 1
        a = 32'h0000_0001;
        b = 32'h0000_0001;
        #10;
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%s1 - 1 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b110; // 100 - 1
        a = 32'h0000_0100;
        b = 32'h0000_0001;
        #10;
        if ( out !== 32'hFF | zero !== 1'b0)
             $display("\t%s100 - 1 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'hFF, 1'b0, "\033[0m");

        f = 3'b111; // SLT 0, 0
        a = 32'h0000_0000;
        b = 32'h0000_0000;
        #10;
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%sSLT 0, 0 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b111; // SLT 0, 1
        a = 32'h0000_0000;
        b = 32'h0000_0001;
        #10;
        if ( out !== 32'h1 | zero !== 1'b0)
             $display("\t%sSLT 0, 1 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h1, 1'b0, "\033[0m");

        f = 3'b111; // SLT 0, -1
        a = 32'h0000_0000;
        b = 32'hFFFF_FFFF;
        #10;
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%sSLT 0, -1 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b111; // SLT 1, 0
        a = 32'h0000_0001;
        b = 32'h0000_0000;
        #10;
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%sSLT 1, 0 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b111; // SLT -1, 0
        a = 32'hFFFF_FFFF;
        b = 32'h0000_0000;
        #10;
        if ( out !== 32'h1 | zero !== 1'b0)
             $display("\t%sSLT -1, 0 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h1, 1'b0, "\033[0m");

        f = 3'b000; // -1 & -1
        a = 32'hFFFF_FFFF;
        b = 32'hFFFF_FFFF;
        #10;
        if ( out !== 32'hFFFF_FFFF | zero !== 1'b0)
             $display("\t%s 0xFFFFFFFF & 0xFFFFFFFF failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'hFFFF_FFFF, 1'b0, "\033[0m");

        f = 3'b000; // -1 & 12345678
        a = 32'hFFFF_FFFF;
        b = 32'h1234_5678;
        #10;
        if ( out !== 32'h1234_5678 | zero !== 1'b0)
             $display("\t%s0xFFFFFFFF & 0x12345678 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h12345678, 1'b0, "\033[0m");

        f = 3'b000; // 12345678 & 87654321
        a = 32'h1234_5678;
        b = 32'h8765_4321;
        #10;
        if ( out !== 32'h02244220 | zero !== 1'b0)
             $display("\t%s0x12345678 & 0x87654321 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h02244220, 1'b0, "\033[0m");

        f = 3'b000; // -1 & 0
        a = 32'hFFFF_FFFF;
        b = 32'h0000_0000;
        #10;
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%s0xFFFFFFFF & 0x0 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        f = 3'b001; // -1 | -1
        a = 32'hFFFF_FFFF;
        b = 32'hFFFF_FFFF;
        #10;
        if ( out !== 32'hFFFF_FFFF | zero !== 1'b0)
             $display("\t%s0xFFFFFFFF | 0xFFFFFFFF failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'hFFFFFFFF, 1'b0, "\033[0m");

        f = 3'b001; // 12345678 | 87654321
        a = 32'h1234_5678;
        b = 32'h8765_4321;
        #10;
        if ( out !== 32'h9775_5779 | zero !== 1'b0)
             $display("\t%s0x12345678 | 0x87654321 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h97755779, 1'b0, "\033[0m");

        f = 3'b001; // 0 | -1
        a = 32'h0000_0000;
        b = 32'hFFFF_FFFF;
        #10;
        if ( out !== 32'hFFFF_FFFF | zero !== 1'b0)
             $display("\t%s0x0 | 0xFFFFFFFF failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'hFFFFFFFF, 1'b0, "\033[0m");

        f = 3'b001; // 0 | 0
        a = 32'h0000_0000;
        b = 32'h0000_0000;
        #10;
        if ( out !== 32'h0 | zero !== 1'b1)
             $display("\t%s0 | 0 failed.\tExpected out = 0x%0x, z = %b%s","\033[0;31m", 32'h0, 1'b1, "\033[0m");

        $finish;
    end
endmodule

Improvement to the ALU code or the test bench will be appreciated.

\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

For the design

Issues

The biggest issues with your code is out is an inferred latch because the condition f == 3'b011 is undefined. This type of latch is not ideal as they can cause area and timing issues. To remove the latch, simply assign out to a determinate value; out = a, out = b, out = 0, or other constant (not out = out which is still a latch).

Depending on your synthesizer, tmp may be treated as a latch. If it is, you should move the tmp = a - b above the if/case statement. Or code STL differently and not need tmp.

Improvements

Other than using declaring the port data types as logic, you have not used any SystemVerilog constructs.

always @(a, b,f) is a one Verilog 2001 way of declaring a combinational block and its sensitivity list. Verilog 1995 required or instead of ,. Verilog 2001 also introduced auto-sensitivity (@* or the synonymous @(*)) which is preferred over manually managed sensitivity lists; especially when the list is long. Your @(a, b,f) is not wrong; it could be better. For more refer to IEEE1800-2012 § 9.4.2.2 Implicit event_expression list.

SystemVerilog when one step further and introduced always_comb as an improvement over always @*. always_comb throws a compiling error when one of the variables it is assigning is also assigned by any other block (if not caught here it would have been an error in synthesis). It also allows the designer to specify the intention of the block to lint, lec, synthesis, and other tools that the block is combinational logic. This allows those tools to flag an warning/error if they detect a latch in the logic. (There is always_latch for when you want a latch). For more refer to IEEE1800-2012 § 9.2.2.2.2 always_comb compared to always @*.

You may consider changing chained else-ifs statements into an case-statement. It can be easier for the synthesizer to detect a a full case logic with a case statement than else-if statements. Since you are using SystemVerilog, you may want to consider the unique or priority prefix depending your your target area/performance/design-constraints.

For the test bench

The test bench is very brute forced testing only about 21 conditions; not testing an conditions where f == 3'b100 or f == 3'b101. There are trillions of legal combinations. It unreasonable to check all of them, but you need to check the major conferrers: all legal values of f, overflow, underflow, and random values.

I suggest adding a clock to your test bench to synchronizes randomization and checking. This way you can randomize your values and use assertions to check them. Read about assertions in IEEE1800-2012 § 16. Example of an assertion:

a_SLT : assert property(@(posedge clk) f==3'b111 |-> out == (a<b))
  else $error("%0t : STL failed out == %0h expected %0h with a = %h, b = %h, was out = %h", $time, out, (a<b), a, b);

You might also want to look into functional coverage (IEEE1800-2012 § 19), to get an idea that your test bench has covered and spot possible coverage holes.

There are plenty of advance test bench practices and strategies; such as UVM and formal analysis, that I will not cover. For your assignment automated checking and constrained randomization should get you what you need.

Reminder: a and b are unsigned, therefore 32'hFFFF_FFFF is 4294967295, not -1

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.