Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable length generics arguments #1158

Open
MurakamiShun opened this issue Dec 19, 2024 · 11 comments
Open

Variable length generics arguments #1158

MurakamiShun opened this issue Dec 19, 2024 · 11 comments
Labels
lang Language design

Comments

@MurakamiShun
Copy link

Variable length arguments unpackable and computed on the veryl side.

https://twitter.com/taichi600730/status/1869312671746752842

@dalance dalance added the lang Language design label Dec 19, 2024
@taichi-ishitani
Copy link
Contributor

@MurakamiShun
Copy link
Author

https://x.com/n_hatta/status/1869504448370008366

I thought it's true. The "for" keyword is worst for implementation side and may be confused with the syntax of System verilog side. So how about "foreach" keyword and it just expand each items and indices in veryl.

https://gist.github.com/MurakamiShun/ed7e3b3603aa598c772784b5ae9d7dd6

@taichi-ishitani
Copy link
Contributor

foreach is also SystemVerilog keyword so I think another keyword is needed.

@taichi-ishitani
Copy link
Contributor

taichi-ishitani commented Dec 20, 2024

How aboud adding generic_ to for keyword like SV's generate keyword?

module RVDecoder<DecModules: {DecProto}>(
    i_inst : input logic<32>,
    o_uop  : output MicroOP,
){  
    var uops : MicroOP[DecModules::size];
  
    generic_for i, dec_module in DecModules : g_decoder {
        inst decoder: dec_module (
            .i_inst,
            .o_uop(uops[i])
        );
    } // for decode_modules

    inst reduction : Reduction::<DecModules::size, MicroOP, SelMicroOP>(
        i: uops,
        o: o_uop
    );
}

@MurakamiShun
Copy link
Author

MurakamiShun commented Dec 20, 2024

I didn't know System verilog has "foreach" keyword. I agree that "generic_for" is a better.

And we must discuss default parameter too.
Below code is listing up internal registers of Digital Signal Processor in generics.
Definition:

enum DSPReg{
    PreAdd,
    PostMul,
    CarryChain,
}


module DSPWrapper::<N: const, R: {const} = {}>(
    i_a : input logic<N>,
    i_b : input logic<N>,
    i_c : input logic<N>,
    o : output logic<N*2>,
){
    // Enable internal registers only in R
}

Instantiation:

inst comb_dsp : DSPWrapper<18>(
    // ports
);
inst long_latency_dsp : DSPWrapper<64, {DSPReg::PreAdd, DSPReg::PostMul, DSPReg::CarryChain}>(
    // ports
);

@dalance
Copy link
Collaborator

dalance commented Dec 20, 2024

Instead of generic_for, generic for may be more extensible like generic if, generic case.

@MurakamiShun
Copy link
Author

Instead of generic_for, generic for may be more extensible like generic if, generic case.

"generic for" is just expand generics, but "generic if" must evaluate the condition statements at veryl side. I thought that are there any implementation issues?

@dalance
Copy link
Collaborator

dalance commented Dec 21, 2024

"generic for" is just expand generics, but "generic if" must evaluate the condition statements at veryl side. I thought that are there any implementation issues?

Yes. So all operands of condition expression should be known by Veryl like literal and index of generic for.

@taichi-ishitani
Copy link
Contributor

I think we don't have to introduce generic if and generic case because SV's generate if and generate case can handle them.

For example, consider the Veryl code below.

var result: logic<MODULE_LIST::size>;
generic for i, MODULE in MODULE_LIST : g_inst_module {
  if i == 0 : g {
    inst u_mod: MODULE (
      o_result: result[i]
    );
  } else {
    assign o_result[i] = 0;
  }
}

Iterator variables i and MODULE will be replaced with the actual arguments during emitting SV code and the above code will be emitted like blow.

if (1) begin: g_inst_module_0
  if (0 == 0) begin : g
    module_0 u_mod (
      .o_result(result[0])
    );
  end else begin : g
    assign result[0] = 0;
  end
end
if (1) begin: g_inst_module_1
  if (1 == 0) begin : g
    module_1 u_mod (
      .o_result(result[0])
    );
  end else begin : g
    assign result[1] = 0;
  end
end

As a result of evaluating condition of generate if, actual effective SV code is:

if (1) begin: g_inst_module_0
  if (1) begin : g
    module_0 u_mod (
      .o_result(result[0])
    );
  end
end
if (1) begin: g_inst_module_1
  if (1) begin : g
    assign result[1] = 0;
  end
end

I think this SV code matches with the orignal Veryl code.

@MurakamiShun
Copy link
Author

MurakamiShun commented Dec 23, 2024

Certainly, the benefit of "generic if" is only the emitted code is slightly easier to read. For this issue, we should target only "generic for".

I think we don't have to introduce generic if and generic case because SV's generate if and generate case can handle them.

For example, consider the Veryl code below.

var result: logic<MODULE_LIST::size>;
generic for i, MODULE in MODULE_LIST : g_inst_module {
  if i == 0 : g {
    inst u_mod: MODULE (
      o_result: result[i]
    );
  } else {
    assign o_result[i] = 0;
  }
}

Iterator variables i and MODULE will be replaced with the actual arguments during emitting SV code and the above code will be emitted like blow.

if (1) begin: g_inst_module_0
  if (0 == 0) begin : g
    module_0 u_mod (
      .o_result(result[0])
    );
  end else begin : g
    assign result[0] = 0;
  end
end
if (1) begin: g_inst_module_1
  if (1 == 0) begin : g
    module_1 u_mod (
      .o_result(result[0])
    );
  end else begin : g
    assign result[1] = 0;
  end
end

As a result of evaluating condition of generate if, actual effective SV code is:

if (1) begin: g_inst_module_0
  if (1) begin : g
    module_0 u_mod (
      .o_result(result[0])
    );
  end
end
if (1) begin: g_inst_module_1
  if (1) begin : g
    assign result[1] = 0;
  end
end

I think this SV code matches with the orignal Veryl code.

@MurakamiShun
Copy link
Author

Here is summary of the Variable length generics arguments up to now.

Declaration

  • Declaration in generic parameter list like module Something::<M_L: {module}>
  • As default parameter, use = such as normal generics and parameter declaration is like array style {list0, list1} or {} as empty.

Unpack list of generics

  • To get list length, use M_L::size
  • To access each parameter, generic for is employed.
  • generic for can apply "for each" style only, like generic for idx, item in M_L. Can not write generate for style, indices be freedom.

Instantiation

  • Use array style declaration like inst inst_name : Something::<{4,6,7}>();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lang Language design
Projects
None yet
Development

No branches or pull requests

3 participants