zachjs / sv2v

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

Classes as namespaces not supported? #97

Open fl4shk opened 4 years ago

fl4shk commented 4 years ago

Here is a feature that I've yet to see supported in synthesis of SystemVerilog that I think would be useful, the ability to use a class as a namespace.

It's the only way to parameterize a struct placed onto a port in SystemVerilog, and it's explicitly mentioned as the way to do that in the SystemVerilog standard. I've attached an example of what I mean.

alu_module.txt

zachjs commented 4 years ago

This is pretty interesting! I had never really considered that classes could be used in synthesizable code. This is something I can add.

It's the only way to parameterize a struct placed onto a port in SystemVerilog

Isn't it possible to use a struct from a parameterized interface modport? This might be a little clunky, but I think it might be another way to achieve a similar result.

fl4shk commented 4 years ago

I am unsure if it's possible to do what you've suggested, though it does sound reasonable.

What seems impossible with SV is the ability to use interfaces as namespaces. The SV standard people seem to have intended that classes be usable for that, but as I mentioned, I don't believe any synthesis tools support that use case for classes. They give up at the sight of the class keyword, despite this specific use case being mentioned in the SV standard.

fl4shk commented 4 years ago

Also, I made a mistake in showing the use of classes as namespaces: :: is used rather than .. The enum usage should have been like so: AluNs(.WIDTH(WIDTH))::OP_ADD rather than AluNs(.WIDTH(WIDTH)).OP_ADD.

zachjs commented 4 years ago

There may be a relatively straightforward way to add support, provided that any identifiers in the class parameter bindings only refer to declarations at the top level of the module, rather than localparams defined within a procedure or generate block. Do you think this would still satisfy most use cases?

fl4shk commented 4 years ago

I think it'd definitely be best, in general, to also support the localparams defined within a procedure or generate block. Many, many use cases would be solved with just top level parameters and localparams, though, from what I can tell. Here is why: you can just move the parameter to the top level of the module, at least for procedures. Generate blocks might want to have a localparam based upon the loop variable, though, which may cause a problem in some cases?

zachjs commented 3 years ago

Sorry for the delay over here! I have been making progress behind the scenes and have pushed what I've got so far. I've added initial support for using classes in this way, but there is a key limitation. While these class scoped identifiers can be used in any context, parameter overrides can only refer to declarations the global or module scope. Please let me know if it works for you!

zachjs commented 3 years ago

As of 3955c47e7a0d84e599ef561e4f6a62f456811fc9, the parameter overrides can refer to declarations in a local generate scope. I'm still eager to see if this implementation is working as you'd expect it to!

andrewandrepowell commented 3 years ago

Hello again!

To add to this current discussion on using classes as namespaces, it would be really nice if the following was supported.

class adder #(
  parameter type T = logic[31:0]);
  static function T operate(T operand0, T operand1);
    return operand0+operand1;
  endfunction
endclass

module reduce(clock, reset, operand0, operand1, result);
  parameter type T = logic[31:0];
  parameter type OPERATION = adder;

  input logic clock, reset;
  flow.receive operand0, operand1;
  flow.send result;

  always_ff @(posedge clock) begin
    if (reset) begin
      result.valid <= 0;
    end else begin
      result.valid <= operand0.valid&&operand1.valid;
    end;
    result.data <= OPERATION#(.T(T))::operate(operand0.data, operand1.data);
  end;

endmodule

The main thing is supporting static functions and tasks so that even operations can be abstracted from modules. This actually builds in Vivado 2020.2.

EDIT: Oops. There was a mistake with the example. I made the correction. I meant to use OPERATION to call the add operation.

zachjs commented 3 years ago

I've just added proper support for static methods. sv2v doesn't yet support class types as parameters (parameter type OPERATION = adder;). The current architecture surrounding the elaboration of type parameters and classes does not lend itself well to this extension, but I can look into some options.

andrewandrepowell commented 3 years ago

Pulled down the changes and I can see that the static functions convert. Thanks again!