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

Register initialization #823

Open
nathsou opened this issue Jul 22, 2024 · 11 comments
Open

Register initialization #823

nathsou opened this issue Jul 22, 2024 · 11 comments

Comments

@nathsou
Copy link

nathsou commented Jul 22, 2024

Hi, thanks for the good work!

Maybe I missed something, but I couldn't find an example of how to initialize a register value:

pub module RegisterFile (
  i_clk: input clock,
) {
  var regs: logic<16>[8];

  initial {
    regs[0] = '0;
  }
}

Fails with:

Error: invalid_statement (link)

  × assignment statement can't be placed at here
   ╭─[/home/nathan/code/fpga/cpu16/design/src/RegisterFile.veryl:7:13]
 6 │   initial {
 7 │     regs[0] = '0;
   ·             ┬
   ·             ╰── Error location
 8 │   }
   ╰────
  help: remove assignment statement

I also tried var reg: logic<1> = 1'b1; but this also fails.

Is there a way to achieve this already?

@nblei
Copy link
Contributor

nblei commented Jul 23, 2024

You initialize registers via reset.

always_ff {
  if_reset { 
    regs[0] = '0;
  } else {
   ...  
  }
}

@nathsou
Copy link
Author

nathsou commented Jul 23, 2024

Thanks @nblei for your quick reply, while this indeed works, using a reset signal does not seem behaviorally equivalent as we need to introduce an input reset signal in the module ports and assert it high at startup.

Is this a desired design decision? I guess this is not a bad thing since it means that the design can easily be ported to devices without initialization capabilities like ASICs.

Although initialization with $readmemb and $readmemh seems to work fine, so this does not seem to be the case:

  var regs: logic<16>[8];

  initial {
    $readmemh("regs.hex", regs);
  }

@nblei
Copy link
Contributor

nblei commented Jul 23, 2024

Veryl is a hardware description language --- not a simulation language. As flops take random values on power-on, initializing them in an initial procedural block does not make sense.

$readmemh "works" because SystemVerilog system functions get transpiled literally.

@nathsou nathsou closed this as completed Jul 23, 2024
@nathsou nathsou reopened this Jul 23, 2024
@nathsou
Copy link
Author

nathsou commented Jul 23, 2024

I'm not at all an expert but initial blocks are not just used for simulation, some FPGAs do support flip-flop initialization, I have for instance used $readmemh to initialize a block RAM with a simple image and when actually programmed onto a Xilinx 7 FPGA in this case, the image did appear so the flip flops were in the correct startup state without relying on a reset signal.

Anyway the proposed solution does work although it's a workaround, so I'm closing this issue.

@nathsou nathsou closed this as completed Jul 23, 2024
@nblei
Copy link
Contributor

nblei commented Jul 23, 2024

I have for instance used $readmemh to initialize a block RAM with a simple image and when actually programmed onto a Xilinx 7 FPGA in this case

FPGA BRAM is implemented as SRAMs, not flops.

@nathsou
Copy link
Author

nathsou commented Jul 23, 2024

Makes sense

@punzik
Copy link

punzik commented Nov 9, 2024

Veryl is a hardware description language --- not a simulation language. As flops take random values on power-on, initializing them in an initial procedural block does not make sense.

In most FPGAs, the initial state of the flops is determined by the configuration bitstream. Therefore, the initial initialization is successfully synthesized for the FPGA. This is convenient when, for example, there is no external reset signal.
I think it would be right to add the possibility of initial initialization in Veryl.

@dalance
Copy link
Collaborator

dalance commented Nov 11, 2024

I agree that this use case is common in FPGA. But I think allowing this feature unconditionally is not good. This is because ASIC synthesizers (possibly few FPGA synthesizer too?) ignore initial statement.
Now readmemh is allowed, but it is because assignment by function call is not checked yet. So I think it should be checked in future, and the way which allows this feature explicitly should be provided for FPGA usage.

@dalance dalance reopened this Nov 11, 2024
@punzik
Copy link

punzik commented Nov 11, 2024

@dalance, thanks for the reply. One solution is to create a Verilog module with a register and necessary initialization. It is only need to tell the module about clock polarity and reset type. Is it possible as I know?

@dalance
Copy link
Collaborator

dalance commented Nov 12, 2024

By following code, clock polarity and reset type which Verilog module receives can be specified.
Veryl compiler inserts ~ if polarity inversion is required at casting.

module Module (
    i_clk: input clock,
    i_rst: input reset,
) {
    let w_clk: `_ clock_posedge    = i_clk as clock_posedge;
    let w_rst:    reset_async_high = i_rst as reset_async_high;

    inst u: $sv::ModuleSv (
        i_clk: w_clk,
        i_rst: w_rst,
    );
}

@dalance
Copy link
Collaborator

dalance commented Nov 13, 2024

I think the following design may be acceptable.

  • Introduce #[allow(initial_assign)]
pub module RegisterFile (
  i_clk: input clock,
) {
  var regs: logic<16>[8];

  #[allow(initial_assign)]
  initial {
    regs[0] = '0;
  }
}
  • A project Including #[allow(initial_assign)] can't be published by veryl publish

This restriction is required to prevent that FPGA only project is added to ASIC project through dependencies.

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

No branches or pull requests

4 participants