diff --git a/chisel3/docs/cookbooks/hierarchy.html b/chisel3/docs/cookbooks/hierarchy.html index f27c52154..3c01576d4 100644 --- a/chisel3/docs/cookbooks/hierarchy.html +++ b/chisel3/docs/cookbooks/hierarchy.html @@ -219,7 +219,7 @@

How do I make m }
Width is 10
-Circuit(Top,List(DefModule(repl.MdocSession$MdocApp5$MyModule@3047b79f,MyModule,List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo)),Vector()), DefModule(repl.MdocSession$MdocApp5$Top@2b62e953,Top,List(Port(Top.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(Top.reset: IO[Bool],Input,UnlocatableSourceInfo)),Vector(DefInstance(SourceLine(hierarchy.md,112,22),ModuleClone(repl.MdocSession$MdocApp5$MyModule@3047b79f),List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo))), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.clock: IO[Clock]),Node(Top.clock: IO[Clock])), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.reset: IO[Reset]),Node(Top.reset: IO[Bool]))))),List(),firrtl.renamemap.package$MutableRenameMap@51621d58,List())
+Circuit(Top,List(DefModule(repl.MdocSession$MdocApp5$MyModule@1794dfb5,MyModule,List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo)),Vector()), DefModule(repl.MdocSession$MdocApp5$Top@73c76035,Top,List(Port(Top.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(Top.reset: IO[Bool],Input,UnlocatableSourceInfo)),Vector(DefInstance(SourceLine(hierarchy.md,112,22),ModuleClone(repl.MdocSession$MdocApp5$MyModule@1794dfb5),List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo))), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.clock: IO[Clock]),Node(Top.clock: IO[Clock])), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.reset: IO[Reset]),Node(Top.reset: IO[Bool]))))),List(),firrtl.renamemap.package$MutableRenameMap@71296d2e,List())
 

How do I look up parameters from a Definition, if I don’t want to instantiate it?

diff --git a/community.html b/community.html index 91128adc9..e9a2c15a9 100644 --- a/community.html +++ b/community.html @@ -265,7 +265,6 @@

Contributors

  • @eymay
  • @felixonmars
  • @ferresb
  • -
  • @GeorgeLyon
  • @grebe
  • @hcook
  • @hngenc
  • diff --git a/contributors.md b/contributors.md index e965ad60e..c9d1a20f6 100644 --- a/contributors.md +++ b/contributors.md @@ -35,7 +35,6 @@ - [`@eymay`](https://github.com/eymay) - [`@felixonmars`](https://github.com/felixonmars) - [`@ferresb`](https://github.com/ferresb) -- [`@GeorgeLyon`](https://github.com/GeorgeLyon) - [`@grebe`](https://github.com/grebe) - [`@hcook`](https://github.com/hcook) - [`@hngenc`](https://github.com/hngenc) diff --git a/js/search.js b/js/search.js index ec2ee3087..0bfc8b8f8 100644 --- a/js/search.js +++ b/js/search.js @@ -155,18 +155,38 @@ function prepareIdxAndDocMap() { { "title": "Hierarchy Cookbook", "url": "/chisel3/docs/cookbooks/hierarchy.html", - "content": "Hierarchy Cookbook How do I instantiate multiple instances with the same module parameterization, but avoid re-elaboration? How do I access internal fields of an instance? How do I make my parameters accessable from an instance? How do I reuse a previously elaborated module, if my new module has the same parameterization? How do I parameterize a module by its children instances? How do I use the new hierarchy-specific Select functions? How do I instantiate multiple instances with the same module parameterization? Prior to this package, Chisel users relied on deduplication in a FIRRTL compiler to combine structurally equivalent modules into one module (aka “deduplication”). This package introduces the following new APIs to enable multiply-instantiated modules directly in Chisel. Definition(...) enables elaborating a module, but does not actually instantiate that module. Instead, it returns a Definition class which represents that module’s definition. Instance(...) takes a Definition and instantiates it, returning an Instance object. Instantiate(...) provides an API similar to Module(...), except it uses Definition and Instance to only elaborate modules once for a given set of parameters. It returns an Instance object. Modules (classes or traits) which will be used with the Definition/Instance api should be marked with the @instantiable annotation at the class/trait definition. To make a Module’s members variables accessible from an Instance object, they must be annotated with the @public annotation. Note that this is only accessible from a Scala sense—this is not in and of itself a mechanism for cross-module references. Using Definition and Instance In the following example, use Definition, Instance, @instantiable and @public to create multiple instances of one specific parameterization of a module, AddOne. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public} @instantiable class AddOne(width: Int) extends Module { @public val in = IO(Input(UInt(width.W))) @public val out = IO(Output(UInt(width.W))) out := in + 1.U } class AddTwo(width: Int) extends Module { val in = IO(Input(UInt(width.W))) val out = IO(Output(UInt(width.W))) val addOneDef = Definition(new AddOne(width)) val i0 = Instance(addOneDef) val i1 = Instance(addOneDef) i0.in := in i1.in := i0.out out := i1.out } // Generated by CIRCT firtool-1.30.0 module AddOne( // <stdin>:3:10 input [9:0] in, // hierarchy.md:16:23 output [9:0] out // hierarchy.md:17:23 ); assign out = in + 10'h1; // <stdin>:3:10, hierarchy.md:18:13 endmodule module AddTwo( // <stdin>:13:10 input clock, // <stdin>:14:11 reset, // <stdin>:15:11 input [9:0] in, // hierarchy.md:23:15 output [9:0] out // hierarchy.md:24:15 ); wire [9:0] _i0_out; // hierarchy.md:26:20 AddOne i0 ( // hierarchy.md:26:20 .in (in), .out (_i0_out) ); AddOne i1 ( // hierarchy.md:27:20 .in (_i0_out), // hierarchy.md:26:20 .out (out) ); endmodule Using Instantiate Similar to the above, the following example uses Instantiate to create multiple instances of AddOne. import chisel3.experimental.hierarchy.Instantiate class AddTwoInstantiate(width: Int) extends Module { val in = IO(Input(UInt(width.W))) val out = IO(Output(UInt(width.W))) val i0 = Instantiate(new AddOne(width)) val i1 = Instantiate(new AddOne(width)) i0.in := in i1.in := i0.out out := i1.out } // Generated by CIRCT firtool-1.30.0 module AddOne( // <stdin>:3:10 input [15:0] in, // hierarchy.md:16:23 output [15:0] out // hierarchy.md:17:23 ); assign out = in + 16'h1; // <stdin>:3:10, hierarchy.md:18:13 endmodule module AddTwoInstantiate( // <stdin>:13:10 input clock, // <stdin>:14:11 reset, // <stdin>:15:11 input [15:0] in, // hierarchy.md:47:15 output [15:0] out // hierarchy.md:48:15 ); wire [15:0] _i0_out; // hierarchy.md:49:23 AddOne i0 ( // hierarchy.md:49:23 .in (in), .out (_i0_out) ); AddOne i1 ( // hierarchy.md:50:23 .in (_i0_out), // hierarchy.md:49:23 .out (out) ); endmodule How do I access internal fields of an instance? You can mark internal members of a class or trait marked with @instantiable with the @public annotation. The requirements are that the field is publicly accessible, is a val or lazy val, and is a valid type. The list of valid types are: IsInstantiable IsLookupable Data BaseModule Iterable/Option containing a type that meets these requirements Basic type like String, Int, BigInt etc. To mark a superclass’s member as @public, use the following pattern (shown with val clock). import chisel3._ import chisel3.experimental.hierarchy.{instantiable, public} @instantiable class MyModule extends Module { @public val clock = clock } You’ll get the following error message for improperly marking something as @public: import chisel3._ import chisel3.experimental.hierarchy.{instantiable, public} object NotValidType @instantiable class MyModule extends Module { @public val x = NotValidType } // error: @public is only legal within a class or trait marked @instantiable, and only on vals of type Data, BaseModule, MemBase, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable, Option, Either, or Tuple2 // val x = circt.stage.ChiselStage.emitCHIRRTL(new Top) // ^ How do I make my parameters accessible from an instance? If an instance’s parameters are simple (e.g. Int, String etc.) they can be marked directly with @public. Often, parameters are more complicated and are contained in case classes. In such cases, mark the case class with the IsLookupable trait. This indicates to Chisel that instances of the IsLookupable class may be accessed from within instances. However, ensure that these parameters are true for all instances of a definition. For example, if our parameters contained an id field which was instance-specific but defaulted to zero, then the definition’s id would be returned for all instances. This change in behavior could lead to bugs if other code presumed the id field was correct. Thus, it is important that when converting normal modules to use this package, you are careful about what you mark as IsLookupable. In the following example, we added the trait IsLookupable to allow the member to be marked @public. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, IsLookupable, public} case class MyCaseClass(width: Int) extends IsLookupable @instantiable class MyModule extends Module { @public val x = MyCaseClass(10) } class Top extends Module { val inst = Instance(Definition(new MyModule)) println(s\"Width is ${inst.x.width}\") } Width is 10 Circuit(Top,List(DefModule(repl.MdocSession$MdocApp5$MyModule@3047b79f,MyModule,List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo)),Vector()), DefModule(repl.MdocSession$MdocApp5$Top@2b62e953,Top,List(Port(Top.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(Top.reset: IO[Bool],Input,UnlocatableSourceInfo)),Vector(DefInstance(SourceLine(hierarchy.md,112,22),ModuleClone(repl.MdocSession$MdocApp5$MyModule@3047b79f),List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo))), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.clock: IO[Clock]),Node(Top.clock: IO[Clock])), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.reset: IO[Reset]),Node(Top.reset: IO[Bool]))))),List(),firrtl.renamemap.package$MutableRenameMap@51621d58,List()) How do I look up parameters from a Definition, if I don’t want to instantiate it? Just like Instances, Definition’s also contain accessors for @public members. As such, you can directly access them: import chisel3._ import chisel3.experimental.hierarchy.{Definition, instantiable, public} @instantiable class AddOne(val width: Int) extends RawModule { @public val width = width @public val in = IO(Input(UInt(width.W))) @public val out = IO(Output(UInt(width.W))) out := in + 1.U } class Top extends Module { val definition = Definition(new AddOne(10)) println(s\"Width is: ${definition.width}\") } // Generated by CIRCT firtool-1.30.0 module Top( // <stdin>:11:10 input clock, // <stdin>:12:11 reset // <stdin>:13:11 ); endmodule How do I parameterize a module by its children instances? Prior to the introduction of this package, a parent module would have to pass all necessary parameters when instantiating a child module. This had the unfortunate consequence of requiring a parent’s parameters to always contain the child’s parameters, which was an unnecessary coupling which lead to some anti-patterns. Now, a parent can take a child Definition as an argument, and instantiate it directly. In addition, it can analyze the parameters used in the definition to parameterize itself. In a sense, now the child can actually parameterize the parent. In the following example, we create a definition of AddOne, and pass the definition to AddTwo. The width of the AddTwo ports are now derived from the parameterization of the AddOne instance. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public} @instantiable class AddOne(val width: Int) extends Module { @public val width = width @public val in = IO(Input(UInt(width.W))) @public val out = IO(Output(UInt(width.W))) out := in + 1.U } class AddTwo(addOneDef: Definition[AddOne]) extends Module { val i0 = Instance(addOneDef) val i1 = Instance(addOneDef) val in = IO(Input(UInt(addOneDef.width.W))) val out = IO(Output(UInt(addOneDef.width.W))) i0.in := in i1.in := i0.out out := i1.out } // Generated by CIRCT firtool-1.30.0 module AddOne( // <stdin>:3:10 input [9:0] in, // hierarchy.md:184:23 output [9:0] out // hierarchy.md:185:23 ); assign out = in + 10'h1; // <stdin>:3:10, hierarchy.md:186:13 endmodule module AddTwo( // <stdin>:13:10 input clock, // <stdin>:14:11 reset, // <stdin>:15:11 input [9:0] in, // hierarchy.md:193:15 output [9:0] out // hierarchy.md:194:15 ); wire [9:0] _i0_out; // hierarchy.md:191:20 AddOne i0 ( // hierarchy.md:191:20 .in (in), .out (_i0_out) ); AddOne i1 ( // hierarchy.md:192:20 .in (_i0_out), // hierarchy.md:191:20 .out (out) ); endmodule How do I use the new hierarchy-specific Select functions? Select functions can be applied after a module has been elaborated, either in a Chisel Aspect or in a parent module applied to a child module. There are seven hierarchy-specific functions, which (with the exception of ios) either return Instance’s or Definition’s: instancesIn(parent): Return all instances directly instantiated locally within parent instancesOf[type](parent): Return all instances of provided type directly instantiated locally within parent allInstancesOf[type](root): Return all instances of provided type directly and indirectly instantiated, locally and deeply, starting from root definitionsIn: Return definitions of all instances directly instantiated locally within parent definitionsOf[type]: Return definitions of all instances of provided type directly instantiated locally within parent allDefinitionsOf[type]: Return all definitions of instances of provided type directly and indirectly instantiated, locally and deeply, starting from root ios: Returns all the I/Os of the provided definition or instance. To demonstrate this, consider the following. We mock up an example where we are using the Select.allInstancesOf and Select.allDefinitionsOf to annotate instances and the definition of EmptyModule. When converting the ChiselAnnotation to firrtl’s Annotation, we print out the resulting Target. As shown, despite EmptyModule actually only being elaborated once, we still provide different targets depending on how the instance or definition is selected. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, Hierarchy, instantiable, public} import firrtl.annotations.{IsModule, NoTargetAnnotation} case object EmptyAnnotation extends NoTargetAnnotation case class MyChiselAnnotation(m: Hierarchy[RawModule], tag: String) extends experimental.ChiselAnnotation { def toFirrtl = { println(tag + \": \" + m.toTarget) EmptyAnnotation } } @instantiable class EmptyModule extends Module { println(\"Elaborating EmptyModule!\") } @instantiable class TwoEmptyModules extends Module { val definition = Definition(new EmptyModule) val i0 = Instance(definition) val i1 = Instance(definition) } class Top extends Module { val definition = Definition(new TwoEmptyModules) val instance = Instance(definition) aop.Select.allInstancesOf[EmptyModule](instance).foreach { i => experimental.annotate(MyChiselAnnotation(i, \"instance\")) } aop.Select.allDefinitionsOf[EmptyModule](instance).foreach { d => experimental.annotate(MyChiselAnnotation(d, \"definition\")) } } Elaborating EmptyModule! instance: ~Top|Top/instance:TwoEmptyModules/i0:EmptyModule instance: ~Top|Top/instance:TwoEmptyModules/i1:EmptyModule definition: ~Top|EmptyModule You can also use Select.ios on either a Definition or an Instance to annotate the I/Os appropriately: case class MyIOAnnotation(m: Data, tag: String) extends experimental.ChiselAnnotation { def toFirrtl = { println(tag + \": \" + m.toTarget) EmptyAnnotation } } @instantiable class InOutModule extends Module { @public val in = IO(Input(Bool())) @public val out = IO(Output(Bool())) out := in } @instantiable class TwoInOutModules extends Module { val in = IO(Input(Bool())) val out = IO(Output(Bool())) val definition = Definition(new InOutModule) val i0 = Instance(definition) val i1 = Instance(definition) i0.in := in i1.in := i0.out out := i1.out } class InOutTop extends Module { val definition = Definition(new TwoInOutModules) val instance = Instance(definition) aop.Select.allInstancesOf[InOutModule](instance).foreach { i => aop.Select.ios(i).foreach { io => experimental.annotate(MyIOAnnotation(io, \"instance io\")) }} aop.Select.allDefinitionsOf[InOutModule](instance).foreach { d => aop.Select.ios(d).foreach {io => experimental.annotate(MyIOAnnotation(io, \"definition io\")) }} } instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>clock instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>reset instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>in instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>out instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>clock instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>reset instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>in instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>out definition io: ~InOutTop|InOutModule>clock definition io: ~InOutTop|InOutModule>reset definition io: ~InOutTop|InOutModule>in definition io: ~InOutTop|InOutModule>out" + "content": "Hierarchy Cookbook How do I instantiate multiple instances with the same module parameterization, but avoid re-elaboration? How do I access internal fields of an instance? How do I make my parameters accessable from an instance? How do I reuse a previously elaborated module, if my new module has the same parameterization? How do I parameterize a module by its children instances? How do I use the new hierarchy-specific Select functions? How do I instantiate multiple instances with the same module parameterization? Prior to this package, Chisel users relied on deduplication in a FIRRTL compiler to combine structurally equivalent modules into one module (aka “deduplication”). This package introduces the following new APIs to enable multiply-instantiated modules directly in Chisel. Definition(...) enables elaborating a module, but does not actually instantiate that module. Instead, it returns a Definition class which represents that module’s definition. Instance(...) takes a Definition and instantiates it, returning an Instance object. Instantiate(...) provides an API similar to Module(...), except it uses Definition and Instance to only elaborate modules once for a given set of parameters. It returns an Instance object. Modules (classes or traits) which will be used with the Definition/Instance api should be marked with the @instantiable annotation at the class/trait definition. To make a Module’s members variables accessible from an Instance object, they must be annotated with the @public annotation. Note that this is only accessible from a Scala sense—this is not in and of itself a mechanism for cross-module references. Using Definition and Instance In the following example, use Definition, Instance, @instantiable and @public to create multiple instances of one specific parameterization of a module, AddOne. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public} @instantiable class AddOne(width: Int) extends Module { @public val in = IO(Input(UInt(width.W))) @public val out = IO(Output(UInt(width.W))) out := in + 1.U } class AddTwo(width: Int) extends Module { val in = IO(Input(UInt(width.W))) val out = IO(Output(UInt(width.W))) val addOneDef = Definition(new AddOne(width)) val i0 = Instance(addOneDef) val i1 = Instance(addOneDef) i0.in := in i1.in := i0.out out := i1.out } // Generated by CIRCT firtool-1.30.0 module AddOne( // <stdin>:3:10 input [9:0] in, // hierarchy.md:16:23 output [9:0] out // hierarchy.md:17:23 ); assign out = in + 10'h1; // <stdin>:3:10, hierarchy.md:18:13 endmodule module AddTwo( // <stdin>:13:10 input clock, // <stdin>:14:11 reset, // <stdin>:15:11 input [9:0] in, // hierarchy.md:23:15 output [9:0] out // hierarchy.md:24:15 ); wire [9:0] _i0_out; // hierarchy.md:26:20 AddOne i0 ( // hierarchy.md:26:20 .in (in), .out (_i0_out) ); AddOne i1 ( // hierarchy.md:27:20 .in (_i0_out), // hierarchy.md:26:20 .out (out) ); endmodule Using Instantiate Similar to the above, the following example uses Instantiate to create multiple instances of AddOne. import chisel3.experimental.hierarchy.Instantiate class AddTwoInstantiate(width: Int) extends Module { val in = IO(Input(UInt(width.W))) val out = IO(Output(UInt(width.W))) val i0 = Instantiate(new AddOne(width)) val i1 = Instantiate(new AddOne(width)) i0.in := in i1.in := i0.out out := i1.out } // Generated by CIRCT firtool-1.30.0 module AddOne( // <stdin>:3:10 input [15:0] in, // hierarchy.md:16:23 output [15:0] out // hierarchy.md:17:23 ); assign out = in + 16'h1; // <stdin>:3:10, hierarchy.md:18:13 endmodule module AddTwoInstantiate( // <stdin>:13:10 input clock, // <stdin>:14:11 reset, // <stdin>:15:11 input [15:0] in, // hierarchy.md:47:15 output [15:0] out // hierarchy.md:48:15 ); wire [15:0] _i0_out; // hierarchy.md:49:23 AddOne i0 ( // hierarchy.md:49:23 .in (in), .out (_i0_out) ); AddOne i1 ( // hierarchy.md:50:23 .in (_i0_out), // hierarchy.md:49:23 .out (out) ); endmodule How do I access internal fields of an instance? You can mark internal members of a class or trait marked with @instantiable with the @public annotation. The requirements are that the field is publicly accessible, is a val or lazy val, and is a valid type. The list of valid types are: IsInstantiable IsLookupable Data BaseModule Iterable/Option containing a type that meets these requirements Basic type like String, Int, BigInt etc. To mark a superclass’s member as @public, use the following pattern (shown with val clock). import chisel3._ import chisel3.experimental.hierarchy.{instantiable, public} @instantiable class MyModule extends Module { @public val clock = clock } You’ll get the following error message for improperly marking something as @public: import chisel3._ import chisel3.experimental.hierarchy.{instantiable, public} object NotValidType @instantiable class MyModule extends Module { @public val x = NotValidType } // error: @public is only legal within a class or trait marked @instantiable, and only on vals of type Data, BaseModule, MemBase, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable, Option, Either, or Tuple2 // val x = circt.stage.ChiselStage.emitCHIRRTL(new Top) // ^ How do I make my parameters accessible from an instance? If an instance’s parameters are simple (e.g. Int, String etc.) they can be marked directly with @public. Often, parameters are more complicated and are contained in case classes. In such cases, mark the case class with the IsLookupable trait. This indicates to Chisel that instances of the IsLookupable class may be accessed from within instances. However, ensure that these parameters are true for all instances of a definition. For example, if our parameters contained an id field which was instance-specific but defaulted to zero, then the definition’s id would be returned for all instances. This change in behavior could lead to bugs if other code presumed the id field was correct. Thus, it is important that when converting normal modules to use this package, you are careful about what you mark as IsLookupable. In the following example, we added the trait IsLookupable to allow the member to be marked @public. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, IsLookupable, public} case class MyCaseClass(width: Int) extends IsLookupable @instantiable class MyModule extends Module { @public val x = MyCaseClass(10) } class Top extends Module { val inst = Instance(Definition(new MyModule)) println(s\"Width is ${inst.x.width}\") } Width is 10 Circuit(Top,List(DefModule(repl.MdocSession$MdocApp5$MyModule@1794dfb5,MyModule,List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo)),Vector()), DefModule(repl.MdocSession$MdocApp5$Top@73c76035,Top,List(Port(Top.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(Top.reset: IO[Bool],Input,UnlocatableSourceInfo)),Vector(DefInstance(SourceLine(hierarchy.md,112,22),ModuleClone(repl.MdocSession$MdocApp5$MyModule@1794dfb5),List(Port(MyModule.clock: IO[Clock],Input,UnlocatableSourceInfo), Port(MyModule.reset: IO[Reset],Input,UnlocatableSourceInfo))), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.clock: IO[Clock]),Node(Top.clock: IO[Clock])), Connect(SourceLine(hierarchy.md,112,22),Node(MyModule.inst.reset: IO[Reset]),Node(Top.reset: IO[Bool]))))),List(),firrtl.renamemap.package$MutableRenameMap@71296d2e,List()) How do I look up parameters from a Definition, if I don’t want to instantiate it? Just like Instances, Definition’s also contain accessors for @public members. As such, you can directly access them: import chisel3._ import chisel3.experimental.hierarchy.{Definition, instantiable, public} @instantiable class AddOne(val width: Int) extends RawModule { @public val width = width @public val in = IO(Input(UInt(width.W))) @public val out = IO(Output(UInt(width.W))) out := in + 1.U } class Top extends Module { val definition = Definition(new AddOne(10)) println(s\"Width is: ${definition.width}\") } // Generated by CIRCT firtool-1.30.0 module Top( // <stdin>:11:10 input clock, // <stdin>:12:11 reset // <stdin>:13:11 ); endmodule How do I parameterize a module by its children instances? Prior to the introduction of this package, a parent module would have to pass all necessary parameters when instantiating a child module. This had the unfortunate consequence of requiring a parent’s parameters to always contain the child’s parameters, which was an unnecessary coupling which lead to some anti-patterns. Now, a parent can take a child Definition as an argument, and instantiate it directly. In addition, it can analyze the parameters used in the definition to parameterize itself. In a sense, now the child can actually parameterize the parent. In the following example, we create a definition of AddOne, and pass the definition to AddTwo. The width of the AddTwo ports are now derived from the parameterization of the AddOne instance. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public} @instantiable class AddOne(val width: Int) extends Module { @public val width = width @public val in = IO(Input(UInt(width.W))) @public val out = IO(Output(UInt(width.W))) out := in + 1.U } class AddTwo(addOneDef: Definition[AddOne]) extends Module { val i0 = Instance(addOneDef) val i1 = Instance(addOneDef) val in = IO(Input(UInt(addOneDef.width.W))) val out = IO(Output(UInt(addOneDef.width.W))) i0.in := in i1.in := i0.out out := i1.out } // Generated by CIRCT firtool-1.30.0 module AddOne( // <stdin>:3:10 input [9:0] in, // hierarchy.md:184:23 output [9:0] out // hierarchy.md:185:23 ); assign out = in + 10'h1; // <stdin>:3:10, hierarchy.md:186:13 endmodule module AddTwo( // <stdin>:13:10 input clock, // <stdin>:14:11 reset, // <stdin>:15:11 input [9:0] in, // hierarchy.md:193:15 output [9:0] out // hierarchy.md:194:15 ); wire [9:0] _i0_out; // hierarchy.md:191:20 AddOne i0 ( // hierarchy.md:191:20 .in (in), .out (_i0_out) ); AddOne i1 ( // hierarchy.md:192:20 .in (_i0_out), // hierarchy.md:191:20 .out (out) ); endmodule How do I use the new hierarchy-specific Select functions? Select functions can be applied after a module has been elaborated, either in a Chisel Aspect or in a parent module applied to a child module. There are seven hierarchy-specific functions, which (with the exception of ios) either return Instance’s or Definition’s: instancesIn(parent): Return all instances directly instantiated locally within parent instancesOf[type](parent): Return all instances of provided type directly instantiated locally within parent allInstancesOf[type](root): Return all instances of provided type directly and indirectly instantiated, locally and deeply, starting from root definitionsIn: Return definitions of all instances directly instantiated locally within parent definitionsOf[type]: Return definitions of all instances of provided type directly instantiated locally within parent allDefinitionsOf[type]: Return all definitions of instances of provided type directly and indirectly instantiated, locally and deeply, starting from root ios: Returns all the I/Os of the provided definition or instance. To demonstrate this, consider the following. We mock up an example where we are using the Select.allInstancesOf and Select.allDefinitionsOf to annotate instances and the definition of EmptyModule. When converting the ChiselAnnotation to firrtl’s Annotation, we print out the resulting Target. As shown, despite EmptyModule actually only being elaborated once, we still provide different targets depending on how the instance or definition is selected. import chisel3._ import chisel3.experimental.hierarchy.{Definition, Instance, Hierarchy, instantiable, public} import firrtl.annotations.{IsModule, NoTargetAnnotation} case object EmptyAnnotation extends NoTargetAnnotation case class MyChiselAnnotation(m: Hierarchy[RawModule], tag: String) extends experimental.ChiselAnnotation { def toFirrtl = { println(tag + \": \" + m.toTarget) EmptyAnnotation } } @instantiable class EmptyModule extends Module { println(\"Elaborating EmptyModule!\") } @instantiable class TwoEmptyModules extends Module { val definition = Definition(new EmptyModule) val i0 = Instance(definition) val i1 = Instance(definition) } class Top extends Module { val definition = Definition(new TwoEmptyModules) val instance = Instance(definition) aop.Select.allInstancesOf[EmptyModule](instance).foreach { i => experimental.annotate(MyChiselAnnotation(i, \"instance\")) } aop.Select.allDefinitionsOf[EmptyModule](instance).foreach { d => experimental.annotate(MyChiselAnnotation(d, \"definition\")) } } Elaborating EmptyModule! instance: ~Top|Top/instance:TwoEmptyModules/i0:EmptyModule instance: ~Top|Top/instance:TwoEmptyModules/i1:EmptyModule definition: ~Top|EmptyModule You can also use Select.ios on either a Definition or an Instance to annotate the I/Os appropriately: case class MyIOAnnotation(m: Data, tag: String) extends experimental.ChiselAnnotation { def toFirrtl = { println(tag + \": \" + m.toTarget) EmptyAnnotation } } @instantiable class InOutModule extends Module { @public val in = IO(Input(Bool())) @public val out = IO(Output(Bool())) out := in } @instantiable class TwoInOutModules extends Module { val in = IO(Input(Bool())) val out = IO(Output(Bool())) val definition = Definition(new InOutModule) val i0 = Instance(definition) val i1 = Instance(definition) i0.in := in i1.in := i0.out out := i1.out } class InOutTop extends Module { val definition = Definition(new TwoInOutModules) val instance = Instance(definition) aop.Select.allInstancesOf[InOutModule](instance).foreach { i => aop.Select.ios(i).foreach { io => experimental.annotate(MyIOAnnotation(io, \"instance io\")) }} aop.Select.allDefinitionsOf[InOutModule](instance).foreach { d => aop.Select.ios(d).foreach {io => experimental.annotate(MyIOAnnotation(io, \"definition io\")) }} } instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>clock instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>reset instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>in instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i0:InOutModule>out instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>clock instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>reset instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>in instance io: ~InOutTop|InOutTop/instance:TwoInOutModules/i1:InOutModule>out definition io: ~InOutTop|InOutModule>clock definition io: ~InOutTop|InOutModule>reset definition io: ~InOutTop|InOutModule>in definition io: ~InOutTop|InOutModule>out" + } , + { + "title": "ChiselTest", + "url": "/chiseltest/", + "content": "chiseltest Chiseltest is the batteries-included testing and formal verification library for Chisel-based RTL designs. Chiseltest emphasizes tests that are lightweight (minimizes boilerplate code), easy to read and write (understandability), and compose (for better test code reuse). Installation To use chisel-testers as a managed dependency, add this in your build.sbt: libraryDependencies += \"edu.berkeley.cs\" %% \"chiseltest\" % \"0.5.2\" If you are also directly depending on the chisel3 library, please make sure that your chisel3 and chiseltest versions match to avoid linking errors. Writing a Test ChiselTest integrates with the ScalaTest framework, which provides good IDE and continuous integration support for launching unit tests. Assuming a typical Chisel project with MyModule defined in src/main/scala/MyModule.scala: class MyModule extend Module { val io = IO(new Bundle { val in = Input(UInt(16.W)) val out = Output(UInt(16.W)) }) io.out := RegNext(io.in) } Create a new file in src/test/scala/, for example, BasicTest.scala. In this file: Add the necessary imports: import chisel3._ import chiseltest._ import org.scalatest.flatspec.AnyFlatSpec Create a test class: class BasicTest extends AnyFlatSpec with ChiselScalatestTester { behavior of \"MyModule\" // test class body here } AnyFlatSpec is the default and recommended ScalaTest style for unit testing. ChiselScalatestTester provides testdriver functionality and integration (like signal value assertions) within the context of a ScalaTest environment. For those interested in additional ScalaTest assertion expressibility, Matchers provides additional assertion syntax options. Matchers is optional as it’s mainly for Scala-land assertions and does not inter-operate with circuit operations. In the test class, define a test case: it should \"do something\" in { // test case body here } There can be multiple test cases per test class, and we recommend one test class per Module being tested, and one test case per individual test. In the test case, define the module being tested: test(new MyModule) { c => // test body here } test automatically runs the default simulator (which is treadle), and runs the test stimulus in the block. The argument to the test stimulus block (c in this case) is a handle to the module under test. In the test body, use poke, step, and expect operations to write the test: c.io.in.poke(0.U) c.clock.step() c.io.out.expect(0.U) c.io.in.poke(42.U) c.clock.step() c.io.out.expect(42.U) println(\"Last output value :\" + c.io.out.peek().litValue) With your test case complete, you can run all the test cases in your project by invoking ScalaTest. If you’re using sbt, you can either run sbt test from the command line, or test from the sbt console. testOnly can also be used to run specific tests. Usage References See the test cases for examples: BasicTest shows basic peek, poke, and step functionality QueueTest shows example uses of the DecoupledDriver library, providing functions like enqueueNow, expectDequeueNow, their sequence variants, expectPeek, and expectInvalid. Also, check out the DecoupledDriver implementation, and note that it is not a special case, but code that any user can write. BundleLiteralsSpec shows examples of using bundle literals to poke and expect bundle wires. Note: Bundle literals are still an experimental chisel3 feature and need to be explicitly imported: import chisel3.experimental.BundleLiterals._ AlutTest shows an example of re-using the same test for different data ShiftRegisterTest shows an example of using fork/join to define a test helper function, where multiple invocations of it are pipelined using fork. New Constructs fork to spawn threads, and join to block (wait) on a thread. Pokes and peeks/expects to wires from threads are checked during runtime to ensure no collisions or unexpected behavior. forked threads provide a concurrency abstraction for writing testbenches only, without real parallelism. The test infrastructure schedules threads one at a time, with threads running once per simulation cycle. Thread order is deterministic, and attempts to follow lexical order (as it would appear from the code text): forked (child) threads run immediately, then return to the spawning (parent) thread. On future cycles, child threads run before their parent, in the order they were spawned. Only cross-thread operations that round-trip through the simulator (eg, peek-after-poke) are checked. You can do cross-thread operations in Scala (eg, using shared variables) that aren’t checked, but it is up to you to make sure they are correct and intuitive. This is not recommended. In the future, we may provide checked mechanisms for communicating between test threads. Regions can be associated with a thread, with fork.withRegion(...), which act as a synchronization barrier within simulator time steps. This can be used to create monitors that run after other main testdriver threads have been run, and can read wires those threads have poked. timescope allows pokes to be scoped - that is, pokes inside the timescope block “disappear” and the wire reverts to its previous value at the end of the block. This fits well with the pattern of assigning a default pull-up/down to a wire, and temporarily overriding that value, for example a Decoupled valid signal defaulting low but driven high during an enqueue transaction. See TimescopeTest for examples. Simulator Backends One of our goals is to keep your tests independent of the underlying simulator as much as possible. Thus, in most cases you should be able to choose from one of our four supported backends and get the exact same test results albeit with differences in execution speed and wave dump quality. We provide full bindings to two popular open-source simulator: treadle: default, fast startup times, slow execution for larger circuits, supports only VCD verilator: enable with VerilatorBackendAnnotation, slow startup, fast execution, supports VCD and FST We also provide bindings with some feature limitations to: iverilog: open-source, enable with IcarusBackendAnnotation, supports VCD, FST and LXT vcs: commercial, enable with VcsBackendAnnotation, supports VCD and FSDB Verilator Versions We currently support the following versions of the verilator simulator: v4.028: Ubuntu 20.04, Fedora 32 v4.032: Fedora 33 v4.034: Chipyard v4.038: Ubuntu 20.10 v4.108: Fedora 34 v4.202 Frequently Asked Questions How do I rerun with –full-stacktrace? Whereas Chisel accepts command-line arguments, chiseltest exposes the underlying annotation interface. You can pass annotations to a test by using .withAnnotations(...), for example: // Top of file import chisel3.stage.PrintFullStackTraceAnnotation // ... // Inside your test spec test(new MyModule).withAnnotations(Seq(PrintFullStackTraceAnnotation)) { c => // test body here } This will remove the chisel3 stacktrace suppression (ie. at ... ()). However, if you are using ScalaTest, you may notice a shortened stack trace with ... at the end. You can tell ScalaTest to stop suppressing the stack trace by passing -oF to it. For example (using SBT): $ sbt > testOnly <spec name> -- -oF Any arguments after -- pass to ScalaTest directly instead of being interpreted by SBT. Stability Most APIs that can be accessed through import chiseltest._ are going to remain stable. We are also trying to keep the API provided through import chiseltest.formal._ relatively stable. All other packages are considered internal and thus might change at any time. Migrating from chisel-testers / iotesters Port to new API The core abstractions (poke, expect, step) are similar to chisel-testers, but the syntax is inverted: instead of doing tester.poke(wire, value) with a Scala number value, in ChiselTest you would write wire.poke(value) with a Chisel literal value. Furthermore, as no reference to the tester context is needed, test helper functions can be defined outside a test class and written as libraries. PeekPokeTester compatibility chiseltest now provides a compatibility layer that makes it possible to re-use old PeekPokeTester based tests with little to no changes to the code. We ported the majority of tests from the chisel-testers repository to our new compatibility layer. While the test itself can mostly remain unchanged, the old Driver is removed and instead tests are launched with the new test syntax. Hardware testers Hardware testers are synthesizeable tests, most often extending the BasicTester class provided by chisel3. You can now directly use these tests with chiseltest through the runUntilStop function." } , { "title": "Chisel3", "url": "/chisel3/", "content": "" - } , + } , { - "title": "Diagrammer API Documentation", - "url": "/api/diagrammer/", - "content": "Diagrammer API Documentation We host only the latest minor version for each major version to keep the size down for website hosting. Please see the page about Versioning for more information about major and minor versioning and binary compatibility. 1.5 1.3 1.2 1.1" + "title": "FIRRTL", + "url": "/firrtl/", + "content": "This project is in maintenance mode Pull Requests should only be made for bug fixes against versions 1.6 and below (Chisel 3.6 and below). Please see CIRCT for the next generation FIRRTL compiler. Also see Chisel. Flexible Internal Representation for RTL Firrtl is an intermediate representation (IR) for digital circuits designed as a platform for writing circuit-level transformations. This repository consists of a collection of transformations (written in Scala) which simplify, verify, transform, or emit their input circuit. A Firrtl compiler is constructed by chaining together these transformations, then writing the final circuit to a file. For a detailed description of Firrtl’s intermediate representation, see the FIRRTL Language Specification (source). Wiki Pages and Tutorials Useful information is on our wiki, located here: https://github.com/freechipsproject/firrtl/wiki Some important pages to read, before writing your own transform: Submitting Pull Requests Understanding Firrtl’s IR Traversing a Circuit Common Pass Idioms To write a Firrtl transform, please start with the tutorial here: src/main/scala/tutorial. To run these examples: sbt assembly ./utils/bin/firrtl -td regress -i regress/RocketCore.fir --custom-transforms tutorial.lesson1.AnalyzeCircuit ./utils/bin/firrtl -td regress -i regress/RocketCore.fir --custom-transforms tutorial.lesson2.AnalyzeCircuit Other Tools Firrtl syntax highlighting for Vim users: https://github.com/azidar/firrtl-syntax Firrtl syntax highlighting for Sublime Text 3 users: https://github.com/codelec/highlight-firrtl Firrtl syntax highlighting for Atom users: https://atom.io/packages/language-firrtl Firrtl syntax highlighting, structure view, navigate to corresponding Chisel code for IntelliJ platform: install, source Firrtl mode for Emacs users: https://github.com/ibm/firrtl-mode Chisel3, an embedded hardware DSL that generates Firrtl: https://github.com/freechipsproject/chisel3 Treadle, a Firrtl Interpreter: https://github.com/freechipsproject/treadle Yosys Verilog-to-Firrtl Front-end: https://github.com/cliffordwolf/yosys Installation Instructions Disclaimer: The installation instructions should work for OSX/Linux machines. Other environments may not be tested. Prerequisites If not already installed, install verilator (Requires at least v3.886) If not already installed, install yosys (Requires at least v0.8) If not already installed, install sbt (Recommend v1.6.2) Installation Clone the repository: git clone https://github.com/freechipsproject/firrtl.git && cd firrtl Compile firrtl: sbt compile Run tests: sbt test Build executable (utils/bin/firrtl): sbt assembly Note: You can add utils/bin to your path to call firrtl from other processes Publish this version locally in order to satisfy other tool chain library dependencies: sbt publishLocal Useful sbt Tips Run a single test suite: sbt \"testOnly firrtlTests.UnitTests\" Continually execute a command: sbt ~compile Only invoke sbt once: sbt > compile > test Use scalafix to remove unused import and deprecated procedure syntax Remove unused import: sbt \"firrtl/scalafix RemoveUnused\" Remove deprecated procedure syntax sbt \"firrtl/scalafix ProcedureSyntax\" Using Firrtl as a commandline tool utils/bin/firrtl -i regress/rocket.fir -o regress/rocket.v -X verilog // Compiles rocket-chip to Verilog utils/bin/firrtl --help // Returns usage string Using the JQF Fuzzer The build.sbt defines the fuzzer/jqfFuzz and fuzzer/jqfRepro tasks. These can be used to randomly generate and run test cases and reproduce failing test cases respectively. These tasks are Scala implementations of the FuzzGoal and ReproGoal of the JQF maven plugin and should be functionally identical. The format for the arguments to jqfFuzz are as follows: sbt> fuzzer/jqfFuzz <testClassName> <testMethodName> <otherArgs>... The available options are: --classpath <value> the classpath to instrument and load the test class from --outputDirectory <value> the directory to output test results --testClassName <value> the full class path of the test class --testMethod <value> the method of the test class to run --excludes <value> comma-separated list of FQN prefixes to exclude from coverage instrumentation --includes <value> comma-separated list of FQN prefixes to forcibly include, even if they match an exclude --time <value> the duration of time for which to run fuzzing --blind whether to generate inputs blindly without taking into account coverage feedback --engine <value> the fuzzing engine, valid choices are zest|zeal --disableCoverage disable code-coverage instrumentation --inputDirectory <value> the name of the input directory containing seed files --saveAll save ALL inputs generated during fuzzing, even the ones that do not have any unique code coverage --libFuzzerCompatOutput use libFuzzer like output instead of AFL like stats screen --quiet avoid printing fuzzing statistics progress in the console --exitOnCrash stop fuzzing once a crash is found. --runTimeout <value> the timeout for each individual trial, in milliseconds The fuzzer/jqfFuzz sbt task is a thin wrapper around the firrtl.jqf.jqfFuzz main method that provides the --classpath argument and a default --outputDirectory and passes the rest of the arguments to the main method verbatim. The results will be put in the fuzzer/target/JQf/$testClassName/$testMethod directory. Input files in the fuzzer/target/JQf/$testClassName/$testMethod/corpus and fuzzer/target/JQf/$testClassName/$testMethod/failures directories can be passed as inputs to the fuzzer/jqfRepro task. The format for the arguments to jqfRepro are the same as jqfFuzz sbt> fuzzer/jqfRepro <testClassName> <testMethodName> <otherArgs>... The available options are: --classpath <value> the classpath to instrument and load the test class from --testClassName <value> the full class path of the test class --testMethod <value> the method of the test class to run --input <value> input file or directory to reproduce test case(s) --logCoverage <value> output file to dump coverage info --excludes <value> comma-separated list of FQN prefixes to exclude from coverage instrumentation --includes <value> comma-separated list of FQN prefixes to forcibly include, even if they match an exclude --printArgs whether to print the args to each test case Like fuzzer/jqfFuzz, the fuzzer/jqfRepro sbt task is a thin wrapper around the firrtl.jqf.jqfRepro main method that provides the --classpath argument and a default --outputDirectory and passes the rest of the arguments to the main method verbatim. Citing Firrtl If you use Firrtl in a paper, please cite the following ICCAD paper and technical report: https://ieeexplore.ieee.org/document/8203780 @INPROCEEDINGS{8203780, author={A. Izraelevitz and J. Koenig and P. Li and R. Lin and A. Wang and A. Magyar and D. Kim and C. Schmidt and C. Markley and J. Lawson and J. Bachrach}, booktitle={2017 IEEE/ACM International Conference on Computer-Aided Design (ICCAD)}, title={Reusability is FIRRTL ground: Hardware construction languages, compiler frameworks, and transformations}, year={2017}, volume={}, number={}, pages={209-216}, keywords={field programmable gate arrays;hardware description languages;program compilers;software reusability;hardware development practices;hardware libraries;open-source hardware intermediate representation;hardware compiler transformations;Hardware construction languages;retargetable compilers;software development;virtual Cambrian explosion;hardware compiler frameworks;parameterized libraries;FIRRTL;FPGA mappings;Chisel;Flexible Intermediate Representation for RTL;Reusability;Hardware;Libraries;Hardware design languages;Field programmable gate arrays;Tools;Open source software;RTL;Design;FPGA;ASIC;Hardware;Modeling;Reusability;Hardware Design Language;Hardware Construction Language;Intermediate Representation;Compiler;Transformations;Chisel;FIRRTL}, doi={10.1109/ICCAD.2017.8203780}, ISSN={1558-2434}, month={Nov},} https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-9.html @techreport{Li:EECS-2016-9, Author = {Li, Patrick S. and Izraelevitz, Adam M. and Bachrach, Jonathan}, Title = {Specification for the FIRRTL Language}, Institution = {EECS Department, University of California, Berkeley}, Year = {2016}, Month = {Feb}, URL = {http://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-9.html}, Number = {UCB/EECS-2016-9} }" + } , + { + "title": "Treadle", + "url": "/treadle/", + "content": "What is the Treadle Treadle is a hardware circuit simulator that takes its circuit description directly from FIRRTL. It is based on earlier work done in the FirrtlInterpreter. Treadle is most commonly used as a backend for ChiselTest and ChiselTesters unit tests framework. It supports a Peek, Poke, Expect, Step interface. Treadle can be quite a bit slower for very large circuits but it spins up much faster than other backends so for unit tests of small to medium circuits it generally runs considerably faster. Treadle also provides the TreadleRepl, an interactive shell that provides execution and debugging commands." + } , + { + "title": "Diagrammer", + "url": "/diagrammer/", + "content": "Chisel / FIRRTL Diagramming Project This project can generate GraphViz dot files and from those svg files representing Chisel generated Firrtl circuits. It is also an example of a creating a Firrtl Transformation. This transformation can be applied through the use of annotations as demonstrated in the examples.GCD test. The graphs are mostly clickable, clicking a module will take you to a diagram for just that module. There is a TopLevel diagram that just shows the module hierarchy. Also, an individual arrow can be hovered over to make it turn red and become easier to follow. Example Top Level Example Module Example Using Install Installing this software should be pretty much the following. git clone https://github.com/freechipsproject/diagrammer cd diagrammer Dependencies You will need GraphViz (specifically a default path to the program dot) and sbt. Note that this project currently depends on the master branches of all components of the Chisel ecosystem (chisel3 and firrtl), so you will need to clone and sbt publishLocal for each of these. Creating Circuit Diagrams. To create a set of graphs of a Firrtl Circuit all you need is this project and a Firrtl file (typically a file generated by Chisel with a .fir extension). Let’s say you have a Firrtl file ~/projects/output/circuit.fir. From the command line you while in this directory for this project, you run ./diagram.sh -i ~/projects/output/circuit.fir This will create a number of files in the same directory as the firrtl file that representing the firrtl graph. Each file will be a diagram for each module contained in the firrtl file, plus a file TopLevel.dot.svg file. It will also attempt to open the TopLevel.dot.svg file in a browser using the command open. Each Module in the TopLevel diagram is clickable and should take you into the diagram for that specific module. Because of the size of these files, the diagrams will include the internal logic of that module plus and IO only presentation of any sub-modules found. Options -i, –firrtl-source set the source firrtl to work on -t, –targer-dir sets the output directory for the svg -s, –start-module sets the module name where the graphs will start being generated. The default is at the top -o, –open-program sets the open program, default is open, set to empty to tell it not to do open -j, –just-top-level generates just the top level diagram How Diagrammer Works This program uses a number of firrtl transforms to create multiple graphviz dot file graph programs. The dot files are translated into .svg files. See GeneratorBootcamp Firrtl Chapters for a good introduction to writing Firrtl transforms TODO This used to work by annotating a circuit, consider re-adding that Setting to allow the graphs to go deeper into sub-module logic Provide links to the chisel source" } , + { + "title": "ChiselTest API Documentation", + "url": "/api/chiseltest/", + "content": "ChiselTest API Documentation We host only the latest minor version for each major version to keep the size down for website hosting. Please see the page about Versioning for more information about major and minor versioning and binary compatibility. 0.5 0.3 0.2 0.1" + } , { "title": "FIRRTL API Documentation", "url": "/api/firrtl/", @@ -178,34 +198,14 @@ function prepareIdxAndDocMap() { "content": "Treadle API Documentation We host only the latest minor version for each major version to keep the size down for website hosting. Please see the page about Versioning for more information about major and minor versioning and binary compatibility. 1.5 1.3 1.2 1.1" } , { - "title": "ChiselTest API Documentation", - "url": "/api/chiseltest/", - "content": "ChiselTest API Documentation We host only the latest minor version for each major version to keep the size down for website hosting. Please see the page about Versioning for more information about major and minor versioning and binary compatibility. 0.5 0.3 0.2 0.1" + "title": "Diagrammer API Documentation", + "url": "/api/diagrammer/", + "content": "Diagrammer API Documentation We host only the latest minor version for each major version to keep the size down for website hosting. Please see the page about Versioning for more information about major and minor versioning and binary compatibility. 1.5 1.3 1.2 1.1" } , { "title": "Chisel API Documentation", "url": "/api/", "content": "Chisel API Documentation We host only the latest minor version for each major version to keep the size down for website hosting. Please see the page about Versioning for more information about major and minor versioning and binary compatibility. 3.6 3.5 3.4 3.3 3.2" - } , - { - "title": "Diagrammer", - "url": "/diagrammer/", - "content": "Chisel / FIRRTL Diagramming Project This project can generate GraphViz dot files and from those svg files representing Chisel generated Firrtl circuits. It is also an example of a creating a Firrtl Transformation. This transformation can be applied through the use of annotations as demonstrated in the examples.GCD test. The graphs are mostly clickable, clicking a module will take you to a diagram for just that module. There is a TopLevel diagram that just shows the module hierarchy. Also, an individual arrow can be hovered over to make it turn red and become easier to follow. Example Top Level Example Module Example Using Install Installing this software should be pretty much the following. git clone https://github.com/freechipsproject/diagrammer cd diagrammer Dependencies You will need GraphViz (specifically a default path to the program dot) and sbt. Note that this project currently depends on the master branches of all components of the Chisel ecosystem (chisel3 and firrtl), so you will need to clone and sbt publishLocal for each of these. Creating Circuit Diagrams. To create a set of graphs of a Firrtl Circuit all you need is this project and a Firrtl file (typically a file generated by Chisel with a .fir extension). Let’s say you have a Firrtl file ~/projects/output/circuit.fir. From the command line you while in this directory for this project, you run ./diagram.sh -i ~/projects/output/circuit.fir This will create a number of files in the same directory as the firrtl file that representing the firrtl graph. Each file will be a diagram for each module contained in the firrtl file, plus a file TopLevel.dot.svg file. It will also attempt to open the TopLevel.dot.svg file in a browser using the command open. Each Module in the TopLevel diagram is clickable and should take you into the diagram for that specific module. Because of the size of these files, the diagrams will include the internal logic of that module plus and IO only presentation of any sub-modules found. Options -i, –firrtl-source set the source firrtl to work on -t, –targer-dir sets the output directory for the svg -s, –start-module sets the module name where the graphs will start being generated. The default is at the top -o, –open-program sets the open program, default is open, set to empty to tell it not to do open -j, –just-top-level generates just the top level diagram How Diagrammer Works This program uses a number of firrtl transforms to create multiple graphviz dot file graph programs. The dot files are translated into .svg files. See GeneratorBootcamp Firrtl Chapters for a good introduction to writing Firrtl transforms TODO This used to work by annotating a circuit, consider re-adding that Setting to allow the graphs to go deeper into sub-module logic Provide links to the chisel source" - } , - { - "title": "FIRRTL", - "url": "/firrtl/", - "content": "This project is in maintenance mode Pull Requests should only be made for bug fixes against versions 1.6 and below (Chisel 3.6 and below). Please see CIRCT for the next generation FIRRTL compiler. Also see Chisel. Flexible Internal Representation for RTL Firrtl is an intermediate representation (IR) for digital circuits designed as a platform for writing circuit-level transformations. This repository consists of a collection of transformations (written in Scala) which simplify, verify, transform, or emit their input circuit. A Firrtl compiler is constructed by chaining together these transformations, then writing the final circuit to a file. For a detailed description of Firrtl’s intermediate representation, see the FIRRTL Language Specification (source). Wiki Pages and Tutorials Useful information is on our wiki, located here: https://github.com/freechipsproject/firrtl/wiki Some important pages to read, before writing your own transform: Submitting Pull Requests Understanding Firrtl’s IR Traversing a Circuit Common Pass Idioms To write a Firrtl transform, please start with the tutorial here: src/main/scala/tutorial. To run these examples: sbt assembly ./utils/bin/firrtl -td regress -i regress/RocketCore.fir --custom-transforms tutorial.lesson1.AnalyzeCircuit ./utils/bin/firrtl -td regress -i regress/RocketCore.fir --custom-transforms tutorial.lesson2.AnalyzeCircuit Other Tools Firrtl syntax highlighting for Vim users: https://github.com/azidar/firrtl-syntax Firrtl syntax highlighting for Sublime Text 3 users: https://github.com/codelec/highlight-firrtl Firrtl syntax highlighting for Atom users: https://atom.io/packages/language-firrtl Firrtl syntax highlighting, structure view, navigate to corresponding Chisel code for IntelliJ platform: install, source Firrtl mode for Emacs users: https://github.com/ibm/firrtl-mode Chisel3, an embedded hardware DSL that generates Firrtl: https://github.com/freechipsproject/chisel3 Treadle, a Firrtl Interpreter: https://github.com/freechipsproject/treadle Yosys Verilog-to-Firrtl Front-end: https://github.com/cliffordwolf/yosys Installation Instructions Disclaimer: The installation instructions should work for OSX/Linux machines. Other environments may not be tested. Prerequisites If not already installed, install verilator (Requires at least v3.886) If not already installed, install yosys (Requires at least v0.8) If not already installed, install sbt (Recommend v1.6.2) Installation Clone the repository: git clone https://github.com/freechipsproject/firrtl.git && cd firrtl Compile firrtl: sbt compile Run tests: sbt test Build executable (utils/bin/firrtl): sbt assembly Note: You can add utils/bin to your path to call firrtl from other processes Publish this version locally in order to satisfy other tool chain library dependencies: sbt publishLocal Useful sbt Tips Run a single test suite: sbt \"testOnly firrtlTests.UnitTests\" Continually execute a command: sbt ~compile Only invoke sbt once: sbt > compile > test Use scalafix to remove unused import and deprecated procedure syntax Remove unused import: sbt \"firrtl/scalafix RemoveUnused\" Remove deprecated procedure syntax sbt \"firrtl/scalafix ProcedureSyntax\" Using Firrtl as a commandline tool utils/bin/firrtl -i regress/rocket.fir -o regress/rocket.v -X verilog // Compiles rocket-chip to Verilog utils/bin/firrtl --help // Returns usage string Using the JQF Fuzzer The build.sbt defines the fuzzer/jqfFuzz and fuzzer/jqfRepro tasks. These can be used to randomly generate and run test cases and reproduce failing test cases respectively. These tasks are Scala implementations of the FuzzGoal and ReproGoal of the JQF maven plugin and should be functionally identical. The format for the arguments to jqfFuzz are as follows: sbt> fuzzer/jqfFuzz <testClassName> <testMethodName> <otherArgs>... The available options are: --classpath <value> the classpath to instrument and load the test class from --outputDirectory <value> the directory to output test results --testClassName <value> the full class path of the test class --testMethod <value> the method of the test class to run --excludes <value> comma-separated list of FQN prefixes to exclude from coverage instrumentation --includes <value> comma-separated list of FQN prefixes to forcibly include, even if they match an exclude --time <value> the duration of time for which to run fuzzing --blind whether to generate inputs blindly without taking into account coverage feedback --engine <value> the fuzzing engine, valid choices are zest|zeal --disableCoverage disable code-coverage instrumentation --inputDirectory <value> the name of the input directory containing seed files --saveAll save ALL inputs generated during fuzzing, even the ones that do not have any unique code coverage --libFuzzerCompatOutput use libFuzzer like output instead of AFL like stats screen --quiet avoid printing fuzzing statistics progress in the console --exitOnCrash stop fuzzing once a crash is found. --runTimeout <value> the timeout for each individual trial, in milliseconds The fuzzer/jqfFuzz sbt task is a thin wrapper around the firrtl.jqf.jqfFuzz main method that provides the --classpath argument and a default --outputDirectory and passes the rest of the arguments to the main method verbatim. The results will be put in the fuzzer/target/JQf/$testClassName/$testMethod directory. Input files in the fuzzer/target/JQf/$testClassName/$testMethod/corpus and fuzzer/target/JQf/$testClassName/$testMethod/failures directories can be passed as inputs to the fuzzer/jqfRepro task. The format for the arguments to jqfRepro are the same as jqfFuzz sbt> fuzzer/jqfRepro <testClassName> <testMethodName> <otherArgs>... The available options are: --classpath <value> the classpath to instrument and load the test class from --testClassName <value> the full class path of the test class --testMethod <value> the method of the test class to run --input <value> input file or directory to reproduce test case(s) --logCoverage <value> output file to dump coverage info --excludes <value> comma-separated list of FQN prefixes to exclude from coverage instrumentation --includes <value> comma-separated list of FQN prefixes to forcibly include, even if they match an exclude --printArgs whether to print the args to each test case Like fuzzer/jqfFuzz, the fuzzer/jqfRepro sbt task is a thin wrapper around the firrtl.jqf.jqfRepro main method that provides the --classpath argument and a default --outputDirectory and passes the rest of the arguments to the main method verbatim. Citing Firrtl If you use Firrtl in a paper, please cite the following ICCAD paper and technical report: https://ieeexplore.ieee.org/document/8203780 @INPROCEEDINGS{8203780, author={A. Izraelevitz and J. Koenig and P. Li and R. Lin and A. Wang and A. Magyar and D. Kim and C. Schmidt and C. Markley and J. Lawson and J. Bachrach}, booktitle={2017 IEEE/ACM International Conference on Computer-Aided Design (ICCAD)}, title={Reusability is FIRRTL ground: Hardware construction languages, compiler frameworks, and transformations}, year={2017}, volume={}, number={}, pages={209-216}, keywords={field programmable gate arrays;hardware description languages;program compilers;software reusability;hardware development practices;hardware libraries;open-source hardware intermediate representation;hardware compiler transformations;Hardware construction languages;retargetable compilers;software development;virtual Cambrian explosion;hardware compiler frameworks;parameterized libraries;FIRRTL;FPGA mappings;Chisel;Flexible Intermediate Representation for RTL;Reusability;Hardware;Libraries;Hardware design languages;Field programmable gate arrays;Tools;Open source software;RTL;Design;FPGA;ASIC;Hardware;Modeling;Reusability;Hardware Design Language;Hardware Construction Language;Intermediate Representation;Compiler;Transformations;Chisel;FIRRTL}, doi={10.1109/ICCAD.2017.8203780}, ISSN={1558-2434}, month={Nov},} https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-9.html @techreport{Li:EECS-2016-9, Author = {Li, Patrick S. and Izraelevitz, Adam M. and Bachrach, Jonathan}, Title = {Specification for the FIRRTL Language}, Institution = {EECS Department, University of California, Berkeley}, Year = {2016}, Month = {Feb}, URL = {http://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-9.html}, Number = {UCB/EECS-2016-9} }" - } , - { - "title": "Treadle", - "url": "/treadle/", - "content": "What is the Treadle Treadle is a hardware circuit simulator that takes its circuit description directly from FIRRTL. It is based on earlier work done in the FirrtlInterpreter. Treadle is most commonly used as a backend for ChiselTest and ChiselTesters unit tests framework. It supports a Peek, Poke, Expect, Step interface. Treadle can be quite a bit slower for very large circuits but it spins up much faster than other backends so for unit tests of small to medium circuits it generally runs considerably faster. Treadle also provides the TreadleRepl, an interactive shell that provides execution and debugging commands." - } , - { - "title": "ChiselTest", - "url": "/chiseltest/", - "content": "chiseltest Chiseltest is the batteries-included testing and formal verification library for Chisel-based RTL designs. Chiseltest emphasizes tests that are lightweight (minimizes boilerplate code), easy to read and write (understandability), and compose (for better test code reuse). Installation To use chisel-testers as a managed dependency, add this in your build.sbt: libraryDependencies += \"edu.berkeley.cs\" %% \"chiseltest\" % \"0.5.2\" If you are also directly depending on the chisel3 library, please make sure that your chisel3 and chiseltest versions match to avoid linking errors. Writing a Test ChiselTest integrates with the ScalaTest framework, which provides good IDE and continuous integration support for launching unit tests. Assuming a typical Chisel project with MyModule defined in src/main/scala/MyModule.scala: class MyModule extend Module { val io = IO(new Bundle { val in = Input(UInt(16.W)) val out = Output(UInt(16.W)) }) io.out := RegNext(io.in) } Create a new file in src/test/scala/, for example, BasicTest.scala. In this file: Add the necessary imports: import chisel3._ import chiseltest._ import org.scalatest.flatspec.AnyFlatSpec Create a test class: class BasicTest extends AnyFlatSpec with ChiselScalatestTester { behavior of \"MyModule\" // test class body here } AnyFlatSpec is the default and recommended ScalaTest style for unit testing. ChiselScalatestTester provides testdriver functionality and integration (like signal value assertions) within the context of a ScalaTest environment. For those interested in additional ScalaTest assertion expressibility, Matchers provides additional assertion syntax options. Matchers is optional as it’s mainly for Scala-land assertions and does not inter-operate with circuit operations. In the test class, define a test case: it should \"do something\" in { // test case body here } There can be multiple test cases per test class, and we recommend one test class per Module being tested, and one test case per individual test. In the test case, define the module being tested: test(new MyModule) { c => // test body here } test automatically runs the default simulator (which is treadle), and runs the test stimulus in the block. The argument to the test stimulus block (c in this case) is a handle to the module under test. In the test body, use poke, step, and expect operations to write the test: c.io.in.poke(0.U) c.clock.step() c.io.out.expect(0.U) c.io.in.poke(42.U) c.clock.step() c.io.out.expect(42.U) println(\"Last output value :\" + c.io.out.peek().litValue) With your test case complete, you can run all the test cases in your project by invoking ScalaTest. If you’re using sbt, you can either run sbt test from the command line, or test from the sbt console. testOnly can also be used to run specific tests. Usage References See the test cases for examples: BasicTest shows basic peek, poke, and step functionality QueueTest shows example uses of the DecoupledDriver library, providing functions like enqueueNow, expectDequeueNow, their sequence variants, expectPeek, and expectInvalid. Also, check out the DecoupledDriver implementation, and note that it is not a special case, but code that any user can write. BundleLiteralsSpec shows examples of using bundle literals to poke and expect bundle wires. Note: Bundle literals are still an experimental chisel3 feature and need to be explicitly imported: import chisel3.experimental.BundleLiterals._ AlutTest shows an example of re-using the same test for different data ShiftRegisterTest shows an example of using fork/join to define a test helper function, where multiple invocations of it are pipelined using fork. New Constructs fork to spawn threads, and join to block (wait) on a thread. Pokes and peeks/expects to wires from threads are checked during runtime to ensure no collisions or unexpected behavior. forked threads provide a concurrency abstraction for writing testbenches only, without real parallelism. The test infrastructure schedules threads one at a time, with threads running once per simulation cycle. Thread order is deterministic, and attempts to follow lexical order (as it would appear from the code text): forked (child) threads run immediately, then return to the spawning (parent) thread. On future cycles, child threads run before their parent, in the order they were spawned. Only cross-thread operations that round-trip through the simulator (eg, peek-after-poke) are checked. You can do cross-thread operations in Scala (eg, using shared variables) that aren’t checked, but it is up to you to make sure they are correct and intuitive. This is not recommended. In the future, we may provide checked mechanisms for communicating between test threads. Regions can be associated with a thread, with fork.withRegion(...), which act as a synchronization barrier within simulator time steps. This can be used to create monitors that run after other main testdriver threads have been run, and can read wires those threads have poked. timescope allows pokes to be scoped - that is, pokes inside the timescope block “disappear” and the wire reverts to its previous value at the end of the block. This fits well with the pattern of assigning a default pull-up/down to a wire, and temporarily overriding that value, for example a Decoupled valid signal defaulting low but driven high during an enqueue transaction. See TimescopeTest for examples. Simulator Backends One of our goals is to keep your tests independent of the underlying simulator as much as possible. Thus, in most cases you should be able to choose from one of our four supported backends and get the exact same test results albeit with differences in execution speed and wave dump quality. We provide full bindings to two popular open-source simulator: treadle: default, fast startup times, slow execution for larger circuits, supports only VCD verilator: enable with VerilatorBackendAnnotation, slow startup, fast execution, supports VCD and FST We also provide bindings with some feature limitations to: iverilog: open-source, enable with IcarusBackendAnnotation, supports VCD, FST and LXT vcs: commercial, enable with VcsBackendAnnotation, supports VCD and FSDB Verilator Versions We currently support the following versions of the verilator simulator: v4.028: Ubuntu 20.04, Fedora 32 v4.032: Fedora 33 v4.034: Chipyard v4.038: Ubuntu 20.10 v4.108: Fedora 34 v4.202 Frequently Asked Questions How do I rerun with –full-stacktrace? Whereas Chisel accepts command-line arguments, chiseltest exposes the underlying annotation interface. You can pass annotations to a test by using .withAnnotations(...), for example: // Top of file import chisel3.stage.PrintFullStackTraceAnnotation // ... // Inside your test spec test(new MyModule).withAnnotations(Seq(PrintFullStackTraceAnnotation)) { c => // test body here } This will remove the chisel3 stacktrace suppression (ie. at ... ()). However, if you are using ScalaTest, you may notice a shortened stack trace with ... at the end. You can tell ScalaTest to stop suppressing the stack trace by passing -oF to it. For example (using SBT): $ sbt > testOnly <spec name> -- -oF Any arguments after -- pass to ScalaTest directly instead of being interpreted by SBT. Stability Most APIs that can be accessed through import chiseltest._ are going to remain stable. We are also trying to keep the API provided through import chiseltest.formal._ relatively stable. All other packages are considered internal and thus might change at any time. Migrating from chisel-testers / iotesters Port to new API The core abstractions (poke, expect, step) are similar to chisel-testers, but the syntax is inverted: instead of doing tester.poke(wire, value) with a Scala number value, in ChiselTest you would write wire.poke(value) with a Chisel literal value. Furthermore, as no reference to the tester context is needed, test helper functions can be defined outside a test class and written as libraries. PeekPokeTester compatibility chiseltest now provides a compatibility layer that makes it possible to re-use old PeekPokeTester based tests with little to no changes to the code. We ported the majority of tests from the chisel-testers repository to our new compatibility layer. While the test itself can mostly remain unchanged, the old Driver is removed and instead tests are launched with the new test syntax. Hardware testers Hardware testers are synthesizeable tests, most often extending the BasicTester class provided by chisel3. You can now directly use these tests with chiseltest through the runUntilStop function." } , { "title": "Home",