llvm / llvm/circt

[FIRRTL][ExportVerilog] Signed multiplier doesn't emit "$signed" expressions

Open
#4,152 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
2.2k
Forks
524
Avg merge
3d 2h
Merged PRs (30d)
46

Description

I'm specifying a mixed signed-unsigned multiplier like this:

circuit Mult :
  module Mult :
    input clock : Clock
    input reset : UInt<1>
    input a : SInt<34>
    input b : UInt<32>
    output y : SInt<66>

    node _y_T = cvt(b) @[main.scala 10:10]
    node _y_T_1 = mul(a, _y_T) @[main.scala 10:10]
    node _y_T_2 = tail(_y_T_1, 1) @[main.scala 10:10]
    node _y_T_3 = asSInt(_y_T_2) @[main.scala 10:10]
    y <= _y_T_3 @[main.scala 10:5]

When run through the SFC, I get this output:

module Mult(
  input         clock,
  input         reset,
  input  [33:0] a,
  input  [31:0] b,
  output [65:0] y
);
  wire [32:0] _y_T = {1'b0,$signed(b)}; // @[main.scala 10:10]
  wire [66:0] _y_T_1 = $signed(a) * $signed(_y_T); // @[main.scala 10:10]
  assign y = _y_T_1[65:0]; // @[main.scala 10:10]
endmodule

When run through firtool, I get this output:

module Mult(
  input         clock,
                reset,
  input  [33:0] a,
  input  [31:0] b,
  output [65:0] y);

  assign y = 66'({{32{a[33]}}, a} * {34'h0, b});        // @[main.scala:10:10]
endmodule

I see that firtool is doing the "explicit" style of sign extension here (which I honestly like), so these two designs should be identical.

I'm trying to run a formal equivalence check on some of our Chisel designs between the SFC and firtool outputs, but the difference in multiplier styles is causing the tools to choke. Is there any way to control how firtool emits these signed/unsigned conversions? I also noticed integration_test/EmitVerilog/verilog_equiv.fir, which seems to have examples of FIRRTL resulting in Verilog $signed expressions, but for whatever reason that doesn't happen here. I tried some simple fixes (do a signed-signed multiplier, make both inputs have the same size, etc), but the firtool output always looked the same.

Here's how I invoked firtool:

firtool \
    --format=fir \
    --dedup \
    --verify-each \
    --split-verilog \
    --lowering-options=disallowPackedArrays,emittedLineLength=2048,noAlwaysComb,disallowLocalVariables,explicitBitcast,verifLabels,locationInfoStyle=wrapInAtSquareBracket \
    -o firtool-output \
    Mult.fir

Thanks for any help!

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with integration_test/EmitVerilog/verilog_equiv.fir and compare its signed-expression cases with the mixed signed/unsigned FIRRTL example. Review the listed firtool lowering options and Verilog emission behavior to determine whether conversion style is configurable. Done means establishing a supported way to produce equivalent output or documenting the limitation and expected behavior.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.