Is there a way to get firtool to output arrays in a module interface?

Can firtool create arrays in the module interfaces from a Chisel array?

If I run verilator -cc test.v on test.v:

module array_example
(
    input [63:0] int_array [7:0], // Array of 8, 64-bit integers
    output reg [63:0] sum
);

    initial sum = 64'b0;

    always @(*) begin
        sum = 64'b0;
        for (int i = 0; i < 8; i = i + 1) begin
            sum = sum + int_array[i];
        end
    end

endmodule

I get an array in the module interface:

class Vtest VL_NOT_FINAL : public VerilatedModel {
  private:
    // Symbol table holding complete model state (owned by this class)
    Vtest__Syms* const vlSymsp;

  public:

    // PORTS
    // The application code writes and reads these signals to
    // propagate new values into/out from the Verilated model.
    VL_OUT64(&sum,63,0);
    VL_IN64((&int_array)[8],63,0);

Yes, Chisel and firtool have a flag to control “aggregate preservation”: https://github.com/chipsalliance/chisel/blob/851613e0f5b9cb687fad3540091beba54d110b7f/src/main/scala/circt/stage/Annotations.scala#L14

By default, aggregates like vectors are “flattened”, but you can control this with the above annotation. For example, this will preserve 1d vectors:

import chisel3._
import chisel3.stage.ChiselGeneratorAnnotation
import circt.stage.{ChiselStage, PreserveAggregate}

class Example extends RawModule {
  val int_array = IO(Input(Vec(8, UInt(64.W))))
  val sum = IO(Output(UInt(64.W)))

  sum := int_array.reduce(_ + _)
}

object Example {
  def main(args: Array[String]): Unit = {
    (new ChiselStage).execute(
      Array("--target", "systemverilog"),
      Seq(ChiselGeneratorAnnotation(() => new Example), PreserveAggregate(PreserveAggregate.OneDimVec))
    )
  }
}

This produces the following System Verilog:

// Generated by CIRCT unknown git version                                                                                                                                                                                                                                       
module Example( // <stdin>:9:3                                                                                                                                                                                                                                                  
  input  [7:0][63:0] int_array, // example.scala:6:21                                                                                                                                                                                                                           
  output [63:0]      sum        // example.scala:7:15                                                                                                                                                                                                                           
);

  assign sum =
    int_array[3'h0] + int_array[3'h1] + int_array[3'h2] + int_array[3'h3]
    + int_array[3'h4] + int_array[3'h5] + int_array[3'h6] + int_array[3'h7];    // <stdin>:9:3, example.scala:9:29                                                                                                                                                              
endmodule

Other options allow you to preserve multi-dimensional vectors, as well as vectors and bundles. But we have tested 1d vectors most thoroughly in CIRCT.

1 Like