How to generate different blocks based on parameter?

My aim is to generate systemverilog module instances based on the content of an array or enum (or something like these) got as a parameter.

In case of array parameter: it can be done if the array is static (i.e. array length is set with constant in declaration), but I would need to provide different length of arrays. If I use dynamic arrays, then I can not refer to the length of the array in a generate block, because length of a dynamic array is not a constant. I can define the length of the static array in a separate parameter, but it would be better to avoide that if possible.

In case of enum: I need to declare 2 enum types to cover the enum values needed in a given test (see t_place) and also the ones which are not needed in the given test (see t_NOT_CHECKED_place), but are referred in a module.

See the code snippets below (array version is remarked in the for loop)

Any hint on a better solution is appreciated.



package sim_checkers_pkg;
  typedef enum { GPIF_IN, GPIF_OUT} t_place;
  t_place places_to_check_enum;
  typedef enum {NUP_DUMMY=places_to_check.num(), CL_SYNCHRONIZER_IN, CL_SYNCHRONIZER_OUT, COLOR_CONV_IN, DATA_STORE_IN} t_NOT_CHECKED_place; // we need to have all the places deined (as enum or constant). The value of these entries must be outside the valid range of t_place entries.
endpackage

import sim_checkers_pkg::*;

module top_checkers();
  stream_checker #(
    .p_verbose_level             (1),
    .p_number_of_places_to_check (2),
    .places_to_check_arr ({GPIF_IN, GPIF_OUT})
  ) stream_checker_inst(
    .o_check_finished (w_check_finished)
  );
endmodule	

module stream_checker #(
  parameter p_verbose_level=1,
  parameter p_number_of_places_to_check=1,
  parameter t_place places_to_check_arr[number_of_places_to_check] = {GPIF_OUT}
) (
    output int o_check_finished
);

  generate
    genvar place;
    //for (place=0; place < p_number_of_places_to_check; place++) begin : gen_place //  $size(places_to_check_arr) could be also used, we can even generate an error if these are not equal.
    for (place=0; place < places_to_check_enum.num; place++) begin : gen_place
      case (place)

        GPIF_IN: begin  
          assign w_clk         [place][stream_addr] = `gpif_path.i_sys_clk;
          assign w_rst         [place][stream_addr] = !`gpif_path.i_sys_arst_n;
          assign w_drop        [place][stream_addr] = `gpif_path.i_drop_frame && (1 << stream_addr);
          assign w_start_valid [place][stream_addr] = `gpif_path.i_data_store_fifo_tfirst && `gpif_path.i_data_store_fifo_valid && `gpif_path.o_data_store_fifo_ready && (`gpif_path.i_data_store_gpif_addr == stream_addr);
          assign w_end_valid   [place][stream_addr] = `gpif_path.i_data_store_fifo_tlast  && `gpif_path.i_data_store_fifo_valid && `gpif_path.o_data_store_fifo_ready && (`gpif_path.i_data_store_gpif_addr == stream_addr);
          assign w_data_valid  [place][stream_addr] = !`gpif_path.i_data_store_fifo_tfirst && !`gpif_path.i_data_store_fifo_tlast && `gpif_path.i_data_store_fifo_valid && `gpif_path.o_data_store_fifo_ready && (`gpif_path.i_data_store_gpif_addr == stream_addr);
        end

        GPIF_OUT: begin
          assign w_clk         [place][stream_addr] = `gpif_path.i_sys_clk;
          assign w_rst         [place][stream_addr] = !`gpif_path.i_sys_arst_n;
          assign w_drop        [place][stream_addr] = `gpif_path.i_drop_frame && (1 << stream_addr);
          assign w_start_valid [place][stream_addr] =  1'bX;
          assign w_end_valid   [place][stream_addr] = !`gpif_path.o_gpif_pktend_n && !`gpif_path.o_gpif_slwr_n && !`gpif_path.o_gpif_slcs_n && `gpif_path.o_gpif_slrd_n && `gpif_path.o_gpif_sloe_n && (`gpif_path.o_gpif_addr == stream_addr);
          assign w_data_valid  [place][stream_addr] =  `gpif_path.o_gpif_pktend_n && !`gpif_path.o_gpif_slwr_n && !`gpif_path.o_gpif_slcs_n && `gpif_path.o_gpif_slrd_n && `gpif_path.o_gpif_sloe_n && (`gpif_path.o_gpif_addr == stream_addr);
        end

        default: begin
          $error("Unhandled place");
        end
      endcase

      stream_frame_checker #(
        .p_verbose_level                   (p_verbose_level),
        .p_has_start_flag                  (c_has_start_flag),
        .p_has_end_flag                    (c_has_end_flag),
        .p_supress_first_error_after_reset (c_supress_first_error_after_reset),
        .p_stream_len                      (c_stream_len)
      ) stream_frame_checker_inst (
        .i_clk                   (w_clk[place][stream_addr]),
        .i_rst                   (w_rst[place][stream_addr]),
        .i_drop                  (w_drop[place][stream_addr]),
        .i_start_valid           (w_start_valid[place][stream_addr]),
        .i_data_valid            (w_data_valid[place][stream_addr]),
        .i_end_valid             (w_end_valid[place][stream_addr]),
        .i_stream_addr           (G_GPIF_ADDR_BITS'(stream_addr)),
        .i_stream_name           ({spaces, name}),
        .o_transferred_frame_cnt (transferred_frame_cnt[place][stream_addr]),
        .o_error_cnt             (error_cnt[place][stream_addr])
      );
    end
  endgenerate

endmodule	


In reply to forgi007:

Hard to know what you are trying to accomplish without a minimal example that can actually be compiled.

In reply to dave_59:

Hi Dave,

Here is an improved minimal example:

sim_checkers_pkg_per_test_case.sv:


package sim_checkers_pkg;
  typedef enum { GPIF_IN, GPIF_OUT} t_place;
  t_place places_to_check;
  typedef enum {NUP_DUMMY=places_to_check.num(), CL_SYNCHRONIZER_IN, CL_SYNCHRONIZER_OUT, COLOR_CONV_IN, DATA_STORE_IN} t_NOT_CHECKED_place; // we need to have all the places deined (as enum or constant). The value of these entries must be outside the valid range of t_place entries.
endpackage

top_checkers_per_test_case.sv:


import sim_checkers_pkg::*;

module top_checkers();
  stream_checker #(
    .p_verbose_level (1)/*,
    .p_number_of_places_to_check (2),
    .places_to_check_arr ({GPIF_IN, GPIF_OUT})*/
  ) stream_checker_inst(
    .o_check_finished (w_check_finished)
  );
endmodule	

stream_checker.sv:


import sim_checkers_pkg::*;

module stream_checker #(
  parameter p_verbose_level=1/*,
  parameter p_number_of_places_to_check=1,
  parameter t_place places_to_check_arr[number_of_places_to_check] = {GPIF_OUT}*/) (
    output int o_check_finished
);
  parameter G_NUM_OF_STREAMS = 3;
  parameter stream_addr = 0;
  wire w_start_valid[places_to_check.num()][G_NUM_OF_STREAMS];
  wire w_end_valid[places_to_check.num()][G_NUM_OF_STREAMS];
  wire w_data_valid[places_to_check.num()][G_NUM_OF_STREAMS];
  wire w_clk[places_to_check.num()][G_NUM_OF_STREAMS];
  wire w_rst[places_to_check.num()][G_NUM_OF_STREAMS];
  wire w_drop[places_to_check.num()][G_NUM_OF_STREAMS];

  `define gpif_path path_to_dut_in_tb
  generate
    genvar place;
    //for (place=0; place < p_number_of_places_to_check; place++) begin : gen_place //  $size(places_to_check_arr) could be also used, we can even generate an error if these are not equal.
    for (place=0; place < places_to_check.num; place++) begin : gen_place
      case (place)

        GPIF_IN: begin  
          assign w_clk         [place][stream_addr] = `gpif_path.i_sys_clk;
          assign w_rst         [place][stream_addr] = !`gpif_path.i_sys_arst_n;
          assign w_drop        [place][stream_addr] = `gpif_path.i_drop_frame && (1 << stream_addr);
          assign w_start_valid [place][stream_addr] = `gpif_path.i_data_store_fifo_tfirst && `gpif_path.i_data_store_fifo_valid && `gpif_path.o_data_store_fifo_ready && (`gpif_path.i_data_store_gpif_addr == stream_addr);
          assign w_end_valid   [place][stream_addr] = `gpif_path.i_data_store_fifo_tlast  && `gpif_path.i_data_store_fifo_valid && `gpif_path.o_data_store_fifo_ready && (`gpif_path.i_data_store_gpif_addr == stream_addr);
          assign w_data_valid  [place][stream_addr] = !`gpif_path.i_data_store_fifo_tfirst && !`gpif_path.i_data_store_fifo_tlast && `gpif_path.i_data_store_fifo_valid && `gpif_path.o_data_store_fifo_ready && (`gpif_path.i_data_store_gpif_addr == stream_addr);
        end

        GPIF_OUT: begin
          assign w_clk         [place][stream_addr] = `gpif_path.i_sys_clk;
          assign w_rst         [place][stream_addr] = !`gpif_path.i_sys_arst_n;
          assign w_drop        [place][stream_addr] = `gpif_path.i_drop_frame && (1 << stream_addr);
          assign w_start_valid [place][stream_addr] =  1'bX;
          assign w_end_valid   [place][stream_addr] = !`gpif_path.o_gpif_pktend_n && !`gpif_path.o_gpif_slwr_n && !`gpif_path.o_gpif_slcs_n && `gpif_path.o_gpif_slrd_n && `gpif_path.o_gpif_sloe_n && (`gpif_path.o_gpif_addr == stream_addr);
          assign w_data_valid  [place][stream_addr] =  `gpif_path.o_gpif_pktend_n && !`gpif_path.o_gpif_slwr_n && !`gpif_path.o_gpif_slcs_n && `gpif_path.o_gpif_slrd_n && `gpif_path.o_gpif_sloe_n && (`gpif_path.o_gpif_addr == stream_addr);
        end

        default: begin
          $error("Unhandled place");
        end
      endcase

      stream_frame_checker #(
        .p_verbose_level          (p_verbose_level)
      ) stream_frame_checker_inst (
        .i_clk                    (w_clk[place][stream_addr]),
        .i_rst                    (w_rst[place][stream_addr]),
        .i_drop                   (w_drop[place][stream_addr]),
        .i_start_valid            (w_start_valid[place][stream_addr]),
        .i_data_valid             (w_data_valid[place][stream_addr]),
        .i_end_valid              (w_end_valid[place][stream_addr]),
        .i_stream_addr            (stream_addr),
        .i_stream_name            (),
        .o_transferred_frame_cnt  (),
        .o_error_cnt              ()
      );
    end
  endgenerate

endmodule	

`timescale 1ns /1fs
module stream_frame_checker #( parameter p_verbose_level=0) (
  input i_clk,
  input i_rst,
  input i_drop,
  input i_start_valid,
  input i_data_valid,
  input i_end_valid,
  input [1:0] i_stream_addr,
  output reg [31:0] o_transferred_frame_cnt=0,
  output reg [31:0] o_error_cnt=0);

endmodule

Thank you for your help in advance, regards,
Tamas