Skip to content

Commit 0f3fd05

Browse files
authored
Add an annotation for specifying module port conventions (#3030)
This annotation is being handled in mfc via: llvm/circt#4665 The convention lets users define how ports with aggregate types are lowered to verilog.
1 parent 90e92be commit 0f3fd05

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

src/main/scala/circt/Convention.scala

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package circt
4+
5+
import chisel3.experimental.{annotate, BaseModule, ChiselAnnotation}
6+
import firrtl.annotations.{ModuleTarget, SingleTargetAnnotation}
7+
import firrtl.FirrtlUserException
8+
9+
/** Annotation to specify a module's port convention.
10+
* The port convention defines how the ports of a module are transformed while
11+
* lowering to verilog.
12+
*/
13+
case class ConventionAnnotation(target: ModuleTarget, convention: String) extends SingleTargetAnnotation[ModuleTarget] {
14+
override def duplicate(target: ModuleTarget): ConventionAnnotation =
15+
ConventionAnnotation(target, convention)
16+
}
17+
18+
/** Utilities for annotating modules with a port convention.
19+
* The port convention defines how the ports of a module are transformed while
20+
* lowering to verilog.
21+
*
22+
* @example {{{
23+
* class Inner extends Module {
24+
* val io = IO(new Bundle{})
25+
* }
26+
*
27+
* class Top extends Module {
28+
* val inner = Module(new Inner)
29+
* convention.scalarized(inner)
30+
* }
31+
* }}}
32+
*/
33+
object convention {
34+
private def apply[T <: BaseModule](data: T, convention: String): Unit =
35+
annotate(new ChiselAnnotation {
36+
def toFirrtl = ConventionAnnotation(data.toTarget, convention)
37+
})
38+
39+
/** Annotate a module as having the "scalarized" port convention.
40+
* With this port convention, the aggregate ports of the module will be
41+
* fully scalarized.
42+
*/
43+
def scalarized[T <: BaseModule](data: T): Unit =
44+
apply(data, "scalarized")
45+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package circtTests
4+
5+
import chisel3._
6+
import circt.convention
7+
import circt.stage.ChiselStage
8+
import org.scalatest.funspec.AnyFunSpec
9+
import org.scalatest.matchers.should.Matchers
10+
11+
class ConventionSpec extends AnyFunSpec with Matchers {
12+
describe("convention.scalarized") {
13+
it("should scalarize the ports of a module") {
14+
class PassThrough extends RawModule {
15+
val i = IO(Input(new Bundle {
16+
val x = UInt(16.W)
17+
val y = UInt(16.W)
18+
}))
19+
val o = IO(Output(new Bundle {
20+
val x = UInt(16.W)
21+
val y = UInt(16.W)
22+
}))
23+
o := i
24+
}
25+
26+
def makePassThrough() = {
27+
val p = new PassThrough
28+
convention.scalarized(p)
29+
p
30+
}
31+
32+
val expected = Array(
33+
"input [15:0] i_x,",
34+
"input [15:0] i_y,",
35+
"output [15:0] o_x,",
36+
"output [15:0] o_y",
37+
"assign o_x = i_x;",
38+
"assign o_y = i_y;"
39+
)
40+
41+
val options = Array(
42+
"--preserve-aggregate=all",
43+
"--strip-debug-info",
44+
"--scalarize-top-module=false",
45+
"--lowering-options=disallowPortDeclSharing"
46+
)
47+
48+
val actual = ChiselStage.emitSystemVerilog(makePassThrough(), Array(), options).split("\n").map(_.trim)
49+
expected.foreach { e => actual should contain(e) }
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)