`timescale 1ns / 1ps

module tb_multiplier;

  // Parameters
  parameter WIDTH = 18;
  parameter NUM_TESTS = 10;

  // DUT signals
  logic clk;
  logic [WIDTH-1:0] X, Y;
  logic [2*WIDTH-1:0] P;

  // Instantiate DUT
  multiplier #(.WIDTH(WIDTH)) dut (
    .clk(clk),
    .X(X),
    .Y(Y),
    .P(P)
  );

  // Clock generation
  initial clk = 0;
  always #5 clk = ~clk;  // 100MHz

  // Test variables
  int i;
  logic [WIDTH-1:0] X_vec [0:NUM_TESTS-1];
  logic [WIDTH-1:0] Y_vec [0:NUM_TESTS-1];
  logic [2*WIDTH-1:0] expected [0:NUM_TESTS-1];

  // Register to capture output with 1-cycle latency
  logic [2*WIDTH-1:0] observed [0:NUM_TESTS-1];

  initial begin
    $display("=== Multiplier Test Start ===");

    // Prepare inputs
    for (i = 0; i < NUM_TESTS; i++) begin
      X_vec[i] = i * 3 + 1;
      Y_vec[i] = i * 5 + 2;
      expected[i] = X_vec[i] * Y_vec[i];
    end

    // Initialize
    X = 0;
    Y = 0;
    @(posedge clk);  // initial cycle

    // Feed inputs and store outputs with 1-cycle latency
    for (i = 0; i < NUM_TESTS; i++) begin
      @(posedge clk);
      X = X_vec[i];
      Y = Y_vec[i];
      if (i > 0)
        observed[i-1] = P;  // capture output from previous input
    end

    // Capture final result after last input
    @(posedge clk);
    observed[NUM_TESTS-1] = P;

    // Check results
    for (i = 0; i < NUM_TESTS; i++) begin
      if (observed[i] !== expected[i])
        $display("Test %0d: %0d * %0d = %0d (Got %0d)", i, X_vec[i], Y_vec[i], expected[i], observed[i]);
      else
        $display("Test %0d: %0d * %0d = %0d", i, X_vec[i], Y_vec[i], observed[i]);
    end

    $display("=== Multiplier Test Complete ===");
    #10;
    $finish;
  end

endmodule
