ALU 总是返回 Z 作为结果

ALU always returning Z for the result

我制作了一个示例 ALU 以及一些测试平台代码。但出于某种原因,我的 ALU 总是返回一个 'Z' 作为结果。有人可以帮我吗?

这是 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

A​​LU 测试台:

`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

提前感谢您的帮助!

在您的测试平台中,您定义:

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

但是模块内部的零被定义为一个位:

output reg ZERO;

因此该模块将仅驱动测试台的 LSB,其余 bis 未连接 (z)。

你对输出的定义导致了一些错误。

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;

您已重新声明为输出,宽度应包含在使用此语法的 reg 定义中正确的格式为:

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;

现代风格是:

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