zachjs / sv2v

SystemVerilog to Verilog conversion
BSD 3-Clause "New" or "Revised" License
561 stars 55 forks source link

Support for type parameterization #118

Closed tomeroberts closed 3 years ago

tomeroberts commented 4 years ago

Not sure if this would be a complete nightmare to support(!), but it's quite a useful construct for creating generic helper modules.

Example:

module sub #(
    parameter type Type     = logic,
    parameter Type ResetVal = '0
) (
    input  logic clk_i,
    input  logic rst_ni,
    input  Type  data_i,
    output Type  data_o
);

  Type data_q;

  always_ff @(posedge clk_i or negedge rst_ni) begin
    if (!rst_ni) begin
      data_q <= ResetVal;
    end else begin
      data_q <= data_i;
    end
  end

  assign data_o = data_q;

endmodule

Could be instantiated in:

module example (
    input  logic clk_i,
    input  logic rst_ni
);

  typedef struct packed {
    logic field1;
    logic field2;
  } mystruct_t;

  mystruct_t in_struct, out_struct;

  sub #(
    .Type     (mystruct_t),
    .ResetVal ('0)
  ) u_sub (
    .clk_i   (clk_i),
    .rst_ni  (rst_ni),
    .data_i  (in_struct),
    .data_o  (out_struct)
  );

endmodule

This works currently if all files are passed as one (by creating multiple versions of the parameterized module). Is there a way to make it work if the files are converted one by one (maybe by converting the type parameterization into a width parameter)?

zachjs commented 4 years ago

While some instances of type parameters may have an equivalent representation that can be applied, I don't think this is true in the general case. Complications that come to mind include structs, default type parameters, and port bindings using unbased unsized literals (such as '1).

As you mentioned, if the files are converted in a single pass, this works correctly. This restriction is true of other conversions as well. For example, wildcard port bindings (.*) cannot be converted unless (at least the header of) the instantiated module is available at conversion time.

Could you explain why converting the files together is prohibitive for your use case? Perhaps there is another solvable issue at hand.

tomeroberts commented 4 years ago

Understood - thanks.

We convert the files one by one just to maintain easier debug-ability in the verilog files passed into the rest of the toolflow (here). It's not a particularly strong requirement, so we can move away from that if we need to.

zachjs commented 4 years ago

I've toyed with the idea of a mode wherein the input files would be converted in aggregate, but output in individual files, potentially in some other directory. Would that provide the debug-ability you're looking for?

tomeroberts commented 4 years ago

Yes that would be equivalent. Again, not a strong requirement since one rarely needs to inspect the generated verilog.

zachjs commented 3 years ago

I created a branch https://github.com/zachjs/sv2v/tree/write which adds a new option (--write=adjacent, -wadj, etc.) which takes each input .sv and writes its corresponding converted output to a file in the same location, but with the .v extension instead. It refuses to proceed if any input files don't have that extension. It also refuses to overwrite any files if they already exist. This isn't quite the implementation we discussed before, but I think it satisfies the use case. Please let me know what you think!

tomeroberts commented 3 years ago

Thanks @zachjs - I'll take a look!

tomeroberts commented 3 years ago

Just tried it - should work well for our use-case. Thanks @zachjs! I'll close this issue.

zachjs commented 3 years ago

Thanks for checking it out! This has been pushed to master.