Trouble passing a string as a parameter in a generate loop

I have a module in which I generate multiple RAMs, and each one reads initial data from a file. I am having trouble passing the file name to the RAM module as a parameter. I can pass a specific file name no problem, but when I create a filename using $sformatf, it fails at run time. I have seen this thread here Is it not allowed to use $sformat inside generate statement? which discusses strings in generate loops but (I think) it does not address passing the string as a parameter.

So: how can I pass an arbitrary string (built from $sformatf or something similar) as a parameter?

Below is a cut-down example. Here, all the play_ram module does is display the parameter ram_init_file. What I want is to pass “ram0.dat” as the parameter when i==0, and “ram1.dat” as the parameter when i==1

module play_ram(a);
  input a;
  parameter ram_init_file = "default.dat";

  initial begin
    $display("file name is %s", ram_init_file);
  end
endmodule // ram

module play;
  wire [9:0] a;
  
  genvar i;
  generate
    for (i=0; i<2; i=i+1) begin:ram_gen
      play_ram #(.ram_init_file($sformatf("ram%1d.dat", i))) ram_inst(a[i]); // fails
    end
  endgenerate
endmodule // play

Your code succeeds. Please show us the failure message.

Thanks for the quick reply!
Modelsim compiles, but fails at runtime:

 ** Error: (vsim-8576) Override of parameter 'ram_init_file' from '/play/ram_gen[0]/ram_inst' has an incompatible value.
#    Time: 0 ns  Iteration: 0  Instance: /play/ram_gen[0]/ram_inst File: play.v
# ** Error: (vsim-8576) Override of parameter 'ram_init_file' from '/play/ram_gen[1]/ram_inst' has an incompatible value.
#    Time: 0 ns  Iteration: 0  Instance: /play/ram_gen[1]/ram_inst File: play.v

I also tried iverilog, which fails at compile time:

play.v:16: error: Unable to evaluate parameter ram_init_file value: $sformatf("ram%1d.dat", <i=2'sd0, wid=2>)
play.v:16: error: Unable to evaluate parameter ram_init_file value: $sformatf("ram%1d.dat", <i=2'sd1, wid=2>)
2 error(s) during elaboration.

In any case, since posting I have found a workaround using the ternary operator:

  generate
    for (i=0; i<2; i=i+1) begin:ram_gen
      play_ram 
	   #(.ram_init_file(i==0 ? "ram0.dat" : "ram1.dat"))
      ram_inst(a[i]);
    end
  endgenerate

In my actual application I need multiple ternary operators, but I can live with that for now

$sformatf is a SystemVerilog construct returning a string datatype, but you are using *.v file extensions, which are Verilog only. I suggest changing the file extensions to *.sv. Also, change your module header to

module play_ram #(string ram_init_file)( input a);

This also forces you to override the parameter by not providing a default, and keeps the parameter type consistently a string.

That makes sense. Thanks!