aurora91
aurora91

Reputation: 518

ALU always returning Z for the result

I made a sample ALU along with a some test bench code. But for some reason, my ALU is always returning a 'Z' for the result. Could someone please help me out?

Here is the ALU:

`include "prj_definition.v"
module ALU(OUT, ZERO, OP1, OP2, OPRN);
// input list
input [`DATA_INDEX_LIMIT:0] OP1; // operand 1
input [`DATA_INDEX_LIMIT:0] OP2; // operand 2
input [`ALU_OPRN_INDEX_LIMIT:0] OPRN; // operation code

// output list
output [`DATA_INDEX_LIMIT:0] OUT; // result of the operation.
output ZERO;

//output registers
output reg OUT;
output reg ZERO;

always @(OP1 or OP2 or OPRN)
begin
// TBD - Code for the ALU
case (OPRN)
        `ALU_OPRN_WIDTH'h01 : OUT = OP1 + OP2; // addition
    `ALU_OPRN_WIDTH'h02 : OUT = OP1 - OP2; // subtraction
    `ALU_OPRN_WIDTH'h03 : OUT = OP1 * OP2; // multiplication  
    `ALU_OPRN_WIDTH'h04 : OUT = OP1 >> OP2; // shift_right
    `ALU_OPRN_WIDTH'h05 : OUT = OP1 << OP2; // shift_left
    `ALU_OPRN_WIDTH'h06 : OUT = OP1 & OP2; // bitwise and
    `ALU_OPRN_WIDTH'h07 : OUT = OP1 | OP2; // bitwise or
    `ALU_OPRN_WIDTH'h08 : OUT = ~(OP1 | OP2); // bitwise nor
    `ALU_OPRN_WIDTH'h09 : OUT = OP1 < OP2; // less than

        default: OUT = `DATA_WIDTH'hxxxxxxxx;
endcase
end

always @(OUT) //whenever the output changes
begin
if(OUT == 0) ZERO = 1; //if result is 0, set the zero flag
else ZERO = 0; //otherwise keep the 0 flag false
end

endmodule

ALU TestBench:

`timescale 1ns/10ps
`include "prj_definition.v"
module alu_tb;

integer total_test;
integer pass_test;

reg [`ALU_OPRN_INDEX_LIMIT:0] oprn_reg;
reg [`DATA_INDEX_LIMIT:0] op1_reg;
reg [`DATA_INDEX_LIMIT:0] op2_reg;

wire [`DATA_INDEX_LIMIT:0] r_net;
wire [`DATA_INDEX_LIMIT:0] z_net;
// Instantiation of ALU
ALU alu_inst_01(.OUT(r_net), .ZERO(z_net), .OP1(op1_reg), 
                .OP2(op2_reg), .OPRN(oprn_reg));

// Drive the test patterns and test
initial
begin
op1_reg=0;
op2_reg=0;
oprn_reg=0;

total_test = 0;
pass_test = 0;

// test 15 + 3 = 18
#5  op1_reg=15;
    op2_reg=3;
    oprn_reg=`ALU_OPRN_WIDTH'h01;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h02;   
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h01;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
// 
// TBD: Fill out for other operations
//
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h03;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h04;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h05;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h06;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h07;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h08;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  op1_reg=15;
    op2_reg=5;
    oprn_reg=`ALU_OPRN_WIDTH'h09;
#5  test_and_count(total_test, pass_test, 
                   test_golden(op1_reg,op2_reg,oprn_reg,r_net,z_net));
#5  $write("\n");
    $write("\tTotal number of tests %d\n", total_test);
    $write("\tTotal number of pass  %d\n", pass_test);
    $write("\n");
    $stop; // stop simulation here
end

//-----------------------------------------------------------------------------
// TASK: test_and_count
// 
// PARAMETERS: 
//     INOUT: total_test ; total test counter
//     INOUT: pass_test ; pass test counter
//     INPUT: test_status ; status of the current test 1 or 0
//
// NOTES: Keeps track of number of test and pass cases.
//
//-----------------------------------------------------------------------------
task test_and_count;
inout total_test;
inout pass_test;
input test_status;

integer total_test;
integer pass_test;
begin
    total_test = total_test + 1;
    if (test_status)
    begin
        pass_test = pass_test + 1;
    end
end
endtask

//-----------------------------------------------------------------------------
// FUNCTION: test_golden
// 
// PARAMETERS: op1, op2, oprn and result
// RETURN: 1 or 0 if the result matches golden 
//
// NOTES: Tests the result against the golden. Golden is generated inside.
//
//-----------------------------------------------------------------------------
function test_golden;
input [`DATA_INDEX_LIMIT:0] op1;
input [`DATA_INDEX_LIMIT:0] op2;
input [`ALU_OPRN_INDEX_LIMIT:0] oprn;
input [`DATA_INDEX_LIMIT:0] res;
input [`DATA_INDEX_LIMIT:0] zero;

reg [`DATA_INDEX_LIMIT:0] golden; // expected result
begin
    $write("[TEST] %0d ", op1);
    case(oprn)
        `ALU_OPRN_WIDTH'h01 : begin $write("+ "); golden = op1 + op2; end
        //
        // TBD: fill out for the other operations
        //
    `ALU_OPRN_WIDTH'h02 : begin $write("- "); golden = op1 - op2; end
    `ALU_OPRN_WIDTH'h03 : begin $write("* "); golden = op1 * op2; end
    `ALU_OPRN_WIDTH'h04 : begin $write(">> "); golden = op1 >> op2; end
    `ALU_OPRN_WIDTH'h05 : begin $write("<< "); golden = op1 << op2; end
    `ALU_OPRN_WIDTH'h06 : begin $write("AND "); golden = op1 & op2; end
    `ALU_OPRN_WIDTH'h07 : begin $write("OR "); golden = op1 | op2; end
    `ALU_OPRN_WIDTH'h08 : begin $write("NOR "); golden = ~(op1 | op2); end
    `ALU_OPRN_WIDTH'h09 : begin $write("< "); golden = op1 < op2; end
        default: begin $write("? "); golden = `DATA_WIDTH'hx; end
    endcase
    $write("%0d = %0d , got %0d ... ", op2, golden, res);

    test_golden = (res === golden)?1'b1:1'b0; // case equality
    if (test_golden)
    $write("[PASSED]");
    else 
        $write("[FAILED]");
    if(zero === 0)
    $write("[ZERO FLAG SET]");
    $write("\n");
end
endfunction

endmodule

Thank you in advance for your help!

Upvotes: 0

Views: 827

Answers (1)

Morgan
Morgan

Reputation: 20514

In your testbench you define:

  wire [`DATA_INDEX_LIMIT:0] z_net;
  ALU alu_inst_01( .ZERO(z_net) //..

But zero inside the module is defined as a single bit:

output reg ZERO;

Therefore the module will only drive the LSB of the testbench the rest of the bis are unconnected (z).

Your definition of outputs was causing me some errors.

module ALU(OUT, ZERO, OP1, OP2, OPRN);
  // input list
  input [`DATA_INDEX_LIMIT:0] OP1; // operand 1
  input [`DATA_INDEX_LIMIT:0] OP2; // operand 2
  input [`ALU_OPRN_INDEX_LIMIT:0] OPRN; // operation code

  // output list
  output [`DATA_INDEX_LIMIT:0] OUT; // result of the operation.
  output ZERO;

  //output registers
  output reg OUT;
  output reg ZERO;

You have redeclared as output, and the width should be included on the reg definition using this syntax the correct format would be:

module ALU(OUT, ZERO, OP1, OP2, OPRN);
  // input list
  input [`DATA_INDEX_LIMIT:0] OP1; // operand 1
  input [`DATA_INDEX_LIMIT:0] OP2; // operand 2
  input [`ALU_OPRN_INDEX_LIMIT:0] OPRN; // operation code

  // output list
  output OUT; // result of the operation.
  output ZERO;

  //output registers
  reg [`DATA_INDEX_LIMIT:0] OUT;
  reg ZERO;

The modern style would be:

module ALU(
  // output list
  output reg [`DATA_INDEX_LIMIT:0] OUT, // result of the operation.
  output reg ZERO,

  // input list
  input [`DATA_INDEX_LIMIT:0] OP1, // operand 1
  input [`DATA_INDEX_LIMIT:0] OP2, // operand 2
  input [`ALU_OPRN_INDEX_LIMIT:0] OPRN // operation code
);

Upvotes: 2

Related Questions