circt icon indicating copy to clipboard operation
circt copied to clipboard

Support linking multiple MLIR files in firtool

Open unlsycn opened this issue 5 months ago • 9 comments
trafficstars

We propose a mechanism for linking multiple MLIR files in firtool. Specifically, this involves combining multiple circuits into a single one.

All modules instantiated within another module (i.e., all firrtl.instance operations) must have corresponding declarations in the same circuit, which can be either a firrtl.module or a firrtl.extmodule serving as an interface. Notably, a module can have both an interface (as an extmodule) and an implementation (as a module) within the same circuit.

The linking process works as follows: First, we verify that each instance has a corresponding declaration. Then, all circuits are concatenated into one. Finally, we iterate through all extmodules to find matching public module implementations, replacing them when possible and any remaining extmodules are treated as blackboxes.

For example, there are two .mlir files:

GCD.mlir

module {
  firrtl.circuit "GCD" {
    firrtl.module @GCD(out %output: !firrtl.bundle<valid: uint<1>, bits: bundle<z: uint<32>>>, in %input: !firrtl.bundle<valid: uint<1>, ready flip: uint<1>, bits: bundle<x: uint<32>, y: uint<32>>>, in %reset: !firrtl.uint<1>, in %clock: !firrtl.clock) attributes {convention = #firrtl<convention scalarized>} {
      ...
      %sub = firrtl.instance sub1 interesting_name @Subtractor(in a: !firrtl.uint<32>, in b: !firrtl.uint<32>, out z: !firrtl.uint<32>)
      ...
    }
    firrtl.extmodule @Subtractor(in a: !firrtl.uint<32>, in b: !firrtl.uint<32>, out z: !firrtl.uint<32>) attributes {defname = "Subtractor"}
  }
}

Subtractor.mlir

module {
  firrtl.circuit "Subtractor" {
    firrtl.module @Subtractor(in %a: !firrtl.uint<32>, in %b: !firrtl.uint<32>, out %z: !firrtl.uint<32>) attributes {convention = #firrtl<convention scalarized>} {
      ...
    }
  }
}

We can pass them to firtool together by

firtool GCD.mlir Subtractir.mlir

and produce a complete circuit:

module {
  firrtl.circuit "GCD"
    firrtl.module @GCD(out %output: !firrtl.bundle<valid: uint<1>, bits: bundle<z: uint<32>>>, in %input: !firrtl.bundle<valid: uint<1>, ready flip: uint<1>, bits: bundle<x: uint<32>, y: uint<32>>>, in %reset: !firrtl.uint<1>, in %clock: !firrtl.clock) attributes {convention = #firrtl<convention scalarized>} {
      ...
      %sub = firrtl.instance sub1 interesting_name @Subtractor(in a: !firrtl.uint<32>, in b: !firrtl.uint<32>, out z: !firrtl.uint<32>)
      ...
    }
    firrtl.module @Subtractor(in %a: !firrtl.uint<32>, in %b: !firrtl.uint<32>, out %z: !firrtl.uint<32>) attributes {convention = #firrtl<convention scalarized>} {
      ...
    }
  }
}

unlsycn avatar Jun 03 '25 14:06 unlsycn