Coder Social home page Coder Social logo

firrtl-spec's Introduction

This repository hosts the specification for the FIRRTL language.

To build this, you need the following:

After resolving these dependencies, run make to compile spec.md into build/spec.pdf.

firrtl-spec's People

Contributors

albert-magyar avatar azidar avatar chiselbot avatar dansvo avatar darthscsi avatar debs-sifive avatar donggyukim avatar dtzsifive avatar eigenform avatar ekiwi avatar ekiwi-sifive avatar felixonmars avatar grebe avatar jackkoenig avatar jared-barocsi avatar keszocze avatar mbty avatar mikeurbach avatar mmaloney-sf avatar mwachs5 avatar prithayan avatar richardxia avatar rwy7 avatar seldridge avatar sequencer avatar smarter avatar spriteovo avatar tdb-alcorn avatar tymcauley avatar uenoku avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

firrtl-spec's Issues

Manifests as an alternative to Filelists

With the recent addition of optionality to FIRRTL with layers and instance choices, a problem is brewing as it relates to knowing what files to include for a given compilation.

An example is helpful for the purposes of this discussion. Consider the following circuit which has one degree of optionality through layer A. The use of DontTouchAnnotations exist to ensure that modules and optionality are not removed:

FIRRTL version 4.0.0
circuit Foo: %[[
  {
    "class": "firrtl.transforms.DontTouchAnnotation",
    "target": "~Foo|Foo>c"
  },
  {
    "class": "firrtl.transforms.DontTouchAnnotation",
    "target": "~Foo|Bar>a"
  }
]]
  layer A, bind:

  module Bar:
    input a: UInt<1>
    output b: UInt<1>

    connect b, a

  public module Foo:
    input a: UInt<1>
    output b: UInt<2>

    inst bar of Bar
    connect bar.a, a
    connect b, bar.b

    layerblock A:
      node c = not(a)

Currently, there are three ways that such a circuit could be compiled:

  1. Using single file Verilog output.
  2. Using one-module-per-file Verilog output.
  3. Different behavior occurs if the user has include DUT and Testbench directory annotations. However, these are not something that should be brought into the spec as this does not handle multiple public modules well. (This issue is intentionally trying to replace this behavior.)

Note that it is reasonable that there are other strategies that could be employed here that are not one of two extremes. I.e., private modules can be flexibly emitted anywhere and it is reasonable that they could be emitted in a way that minimizes the number of distinct files.

Using single-file output, we get the following. Comments with "FILE" indicate what file the following block of SystemVerilog code is placed:

// ----- 8< ----- FILE "Foo.sv" ----- 8< -----
module Bar(
  input  a,
  output b
);

  assign b = a;
endmodule

module Foo_A(
  input a
);

  wire c = ~a;
endmodule

module Foo(
  input        a,
  output [1:0] b
);

  wire _bar_b;
  Bar bar (
    .a (a),
    .b (_bar_b)
  );
  assign b = {1'h0, _bar_b};
endmodule

// ----- 8< ----- FILE "layers_Foo_A.sv" ----- 8< -----
// Generated by CIRCT firtool-1.66.0-95-g4996f6781
`ifndef layers_Foo_A
`define layers_Foo_A
bind Foo Foo_A a_0 (
  .a (a)
);
`endif // layers_Foo_A

When compiling with one-file-per-module output, you get the following files:

// ----- 8< ----- FILE "Bar.sv" ----- 8< -----
module Bar(
  input  a,
  output b
);

  assign b = a;
endmodule

// ----- 8< ----- FILE "Foo_A.sv" ----- 8< -----
module Foo_A(
  input a
);

  wire c = ~a;
endmodule

// ----- 8< ----- FILE "Foo.sv" ----- 8< -----
module Foo(
  input        a,
  output [1:0] b
);

  wire _bar_b;
  Bar bar (
    .a (a),
    .b (_bar_b)
  );
  assign b = {1'h0, _bar_b};
endmodule

// ----- 8< ----- FILE "layers_Foo_A.sv" ----- 8< -----

// Generated by CIRCT firtool-1.66.0-95-g4996f6781
`ifndef layers_Foo_A
`define layers_Foo_A
bind Foo Foo_A a_0 (
  .a (a)
);
`endif // layers_Foo_A

This creates problems for downstream consumers of this. Specifically:

  1. If a user wants to compile module Foo, the ABI specifies that a file Foo.sv must exist. However, it does not say anything about where the other files are. The ABI is intentionally quiet about this for private modules and for layer enable files to allow for the compiler to place them anywhere it wants.
  2. A user of a FIRRTL compiler may want to, after the compilation, reorganize the outputs to match the needs of a customer. Specifically, it is useful to organize the directory structure based on what is "test code" and what is "design code" or to put layer collateral in it's own area. The FIRRTL spec should not care about nor prescribe such a structure as this is expected to be different for different FIRRTL compiler users. Additionally, this requires the spec to answer questions related to the placement of a module instantiated by two directory areas. I would prefer if this was left to the user of a FIRRTL compiler and not something the FIRRTL spec has to prescribe.
  3. Related to (2), it is often desirable for a FIRRTL compiler user to remove optionality after compilation. E.g., there is more verification code in some layers that is used to verify a piece of IP produced by a FIRRTL compiler that is removed when releasing this IP to a customer.
  4. The ABI doesn't say anything about what to do for files required for optionality. E.g., when compiling Foo with layer A enabled, the ABI says how to enable the layer, but not that that will include all optional files. (Should it?)

A partial solution to these problems exists in the FIRRTL spec today through filelists on public modules. The FIRRTL spec states that each public module must provide a filelist for all modules it instantiates. It follows that such filelists must be emitted for every degree of optionality in a circuit---each layer or instance choice becomes another filelist. This is viewed as not desirable (due to the duplication it creates). Filelists are also not really lists of files. They are newline delimited command line arguments provided to tools (see verilator -F). (This means they are actually lists of positional arguments.) It is natural that these may want to expand to include actual arguments in the filelists. However, this will run into problems where while filelists are closer to being universally accepted by tools, the arguments to them are not.

As an alternative to this, and proposed by several others, it may be useful to add the notion of a FIRRTL manifest to the ABI. Such a manifest would provide information that would allow a user to answer the questions raised above and to, through lightweight tooling, create a directory structure that a user wants and generate command line arguments to drive downstream tools.

A manifest should include at least the following information:

  1. The manifest version (as this may change over time as new FIRRTL spec or ABI features are added).
  2. The list of all public modules in the circuit.
  3. A description of all optionality in the circuit (layers, instance choices, and parameters once they are added).
  4. An instance graph that describes the instance hierarchy in the design.
  5. What file each module is in.
  6. Whether or not an instance is optionally instantiated and with what optionality feature.

As an example of this, for the single-file compilation, such a manifest could be:

{
    "version": "0.1",
    "name": "Foo",
    "instanceChoices": [],
    "layers": [
        {
            "name": "A",
            "convention": "bind",
            "file": "layers_Foo_A.sv",
            "layers": []
        }
    ],
    "parameters": [],
    "publicModules": [
        {
            "name": "Foo",
            "convention": "v1"
        }
    ],
    "instanceGraph": [
        {
            "module": "Foo",
            "file": "Foo.sv",
            "instances": [
                {
                    "module": "Bar",
                    "instance": "bar",
                    "conditional": null
                },
                {
                    "module": "Bar",
                    "instance": "bar",
                    "conditional": {
                        "type": "layer",
                        "layer": "A"
                    }
                }
            ]
        },
        {
            "module": "Foo_A",
            "file": "Foo.sv",
            "instances": []
        },
        {
            "module": "Bar",
            "file": "Foo.sv",
            "instances": []
        }
    ]
}

For one-file-per-module emission, the manifest would be:

{
    "version": "0.1",
    "name": "Foo",
    "instanceChoices": [],
    "layers": [
        {
            "name": "A",
            "convention": "bind",
            "file": "layers_Foo_A.sv",
            "layers": []
        }
    ],
    "parameters": [],
    "publicModules": [
        {
            "name": "Foo",
            "convention": "v1"
        }
    ],
    "instanceGraph": [
        {
            "module": "Foo",
            "file": "Foo.sv",
            "instances": [
                {
                    "module": "Bar",
                    "instance": "bar",
                    "conditional": null
                },
                {
                    "module": "Bar",
                    "instance": "bar",
                    "conditional": {
                        "type": "layer",
                        "layer": "A"
                    }
                }
            ]
        },
        {
            "module": "Foo_A",
            "file": "Foo_A.sv",
            "instances": []
        },
        {
            "module": "Bar",
            "file": "Bar.sv",
            "instances": []
        }
    ]
}

With one of these manifests, aforementioned lightweight tooling can generate a filelist based on arguments to the tool. E.g., a hypothetical tool invocation could be manifest-tool filelist manifest_Foo.json --top-module Foo --layer A and return one of the following filelists for the different manifests above:

Foo.sv
layers_Foo_A.sv
Foo.sv
Bar.sv
Foo_A.sv
layers_Foo_A.sv

Related Efforts

This is very similar to existing non-standard files emitted by the SFC and the MFC. Cf. dut_hier.json and tb_hier.json which are JSON representations of the instance hierarchy under, respectively, the design-under-test and the testbench.

This is also likely similar to existing industry standard formats like IP-XACT or similar efforts like DuH.

Does the firrtl spec support splitting long lines?

This is not a bug report per se, but more of a question.
See listing 15 from the specs:

{real: {word:UInt<32>, valid:UInt<1>, flip ready:UInt<1>} imag: {word:UInt<32>, valid:UInt<1>, flip ready:UInt<1>}}

The bundle is split among multiple lines with indentation.
The same goes for listing 54, where the type of the mem block is shown.

Does the firrtl spec support splitting long code among multiple lines,
or is this a result of formatting?

This is a bug report after all:
I think there should be a comma after between the real and imag bundle.

Spec Clarification: info strings

Hi,

just a quick question for clarification. As per the spec the info nodes contain string types. Despite not being explicitly specified strings are used in the spec with quotation marks, also when showing the info notation in listing 82.
I just ran the chisel tutorial from current releases and saw that info nodes are not in quotation marks. I am looking into adding a loFIRRTL frontend into Verilator and it would be nice to spare me some iterations ;)
Cheers,
Stefan

Ability to reference and generate modules with escaped identifiers?

The current syntax for identifiers is:

id = ( "_" | letter ) , { "_" | letter | digit_dec } | literal_id ;

Incidentally, this is also the syntax used for the right-hand-side of a defname:

[ "defname" , "=" , id , newline ] ,

However, SystemVerilog lets us define components with names that cannot be represented with this grammar due to its support for escaped identifiers (IEEE 1800-2017 §5.6.1):

Escaped identifiers shall start with the backslash character (\) and end with white space (space, tab,
newline). They provide a means of including any of the printable ASCII characters in an identifier (the
decimal values 33 through 126, or 21 through 7E in hexadecimal).

Neither the leading backslash character nor the terminating white space is considered to be part of the
identifier. Therefore, an escaped identifier \cpu3 is treated the same as a nonescaped identifier cpu3.

I was wondering if FIRRTL could adopt a similar notion of escaped identifiers, but the fact that MLIR itself doesn't seem to support escaped identifiers might make this a no-go. An alternative would be to allow defname to take a string rhs (it looks like strings can be escaped although this isn't specified). This still wouldn't allow defining a native FIRRTL module with an escaped name, but perhaps defname could be allowed on regular modules too?

Add Lowering Convention to External, Public Modules

Both external and public modules need to specify their port lowering convention. Currently, this is underspecified and left up to a compiler to implement (with annotations or a global option).

Some constraints:

  • The syntax should be similar for both external and public modules.
  • This should by optional in the syntax with a default convention (v1) assumed if not defined. This provides backwards compatibility with the current behavior.
  • The syntax shouldn't cause problems or confusion when trying to implement parameters later.
  • enablelayer currently goes after the module name

The following are some syntax ideas:

String after "public"

public v2 module Foo:

This is slightly problematic as it is incongruent with external modules which don't have the public keyword. We could add the public keyword to them:

public v1 extmodule Bar:

Use a string that starts with v after the module name:

public module Foo v2 enablelayer A:
extmodule Bar v1:

Use brackets, parentheses, or something like that

public module<v2> Foo:
extmodule<v1> Bar:

I expect that parameters will eventually show up as Foo<x: Int> type syntax, so this may not conflict too badly.

Make the convention port-like

public module Foo:
  convention v2
extmodule Bar:
  convention v1

Use an attribute dictionary-like syntax

public module Foo enablelayer A {convention = v2}:
extmodule Bar {convention = v1}:

Cleanup String-encoded Literals

The FIRRTL spec currently allows for string-encoded integer literals, e.g., "hDEADBEEF", to be used in almost any location where an integer is accepted. Because this has been how the SFC has worked since its inception, this is going to be enshrined in the spec here: #86

The current rule is (summarizing):

A string-encoded integer literal can be used any place an integer literal can be except when defining memory depths and memory read/write latencies. Additionally, string-encoded integer literals are treated as strings in external module and intrinsic module parameters (as there is no way to differentiate them from normal strings).

This allows for circuits like the following to be accepted by the SFC and MFC:

circuit Foo:
  module Foo:
    input clock: Clock
    input a: UInt<"hF">["o10"]
    output b: UInt<"b1111">[8]

    b <= a

However, this was never the intent of the original spec. (This actually stems from an incorrect implementation of the spec in the original FIRRTL grammar.) Additionally, there is concern that having multiple ways to represent numbers is not useful for a language like FIRRTL. There are several options that we can take here:

  1. Leave everything as it.
  2. Expand the usage of string-encoded integer literals to be used by memories. This would bring the spec in alignment with itself while leaving external module parameters as a corner case. This isn't terrible, but it continues to allow for interesting circuits like the one above.
  3. Restrict string-encoded integer literals to only being used in the construction of constant integer expressions, e.g., UInt("hBADF00D"). This would then disallow their usage in widths, sub-indices, etc. This brings the spec inline with its original intent.
  4. Remove all string-encoded integer literals. This would force UInt("hBADF00D") to be represented as UInt(195948557). This is less user-friendly, but is fine for a compiler. This also creates better round-trip behavior for compilers. I.e., it would be good if FIRRTL compilers could have one internal representation for constant integer expressions. However, if a compiler does this and it ingests "hBADF00D", can it then emit 195948557.

I'm of the opinion that we should just take option (4) and be done with it. I think the overhead of having more than one number representation isn't particularly useful. As a slight weakening of this, I would be okay if the numbers for constant expressions were only allowed to be hex. I do think it is a great thing if a compiler doesn't have to track additional state in order to round trip IR.

Other related options to consider:

  • Is it useful to have octal and binary representations in addition to hex? I'm of the opinion that no, these aren't useful. If we keep any non-decimal encoding, then it should be hex alone.
  • The current encoding of a string could be changed to something that isn't a string. E.g., UInt("hBADF00D") could be either UInt(hBADF00D) or UInt(0hBADF00D).
  • The location of the sign is odd for string-encoded integer literals. E.g., a negative number is SInt("h-42") when it seems more natural to have this as SInt("-h42").
  • The fact that there are negative hex, octal, and binary numbers is a bit odd. It could be cleaner to use the hex, octal, or binary encoding as the raw encoding that was then interpreted via two's complement. E.g., the current way that -1 is represented in hex is SInt("h-001"). It is likely more natural (to electrical and computer engineering types) to encode this as SInt("hFFF").

A very random note on converting numbers. The command line RPN calculator dc is fantastic at doing number conversions. For the above conversion, you can do echo "16i BADF00Dp" | dc to do the conversion.

Define public, private ("visibility")

As encountered in #75 and #76 , there's a notion of some modules as "public" and "private" being teased out, but this should be explicitly defined in the FIRRTL spec somewhere if we want to rely on it -- probably in its own PR if not as part of one of those.

Build error: make: *** No rule to make target `build/img/firrtl-folded-module.eps', needed by `build/spec.pdf'. Stop.

When I tried to build the spec on Mac OS, I got the following error:

$ make
make: *** No rule to make target `build/img/firrtl-folded-module.eps', needed by `build/spec.pdf'.  Stop.

With some digging, I find that the following make target is not executed:

%/:
	mkdir -p $@

And after I create the the directory of "build/img" manually and make again, the error is gone.

So how to automatically execute the make target when building the spec?

Rework Authorship / Acknowledgment to Better Align with a Specification

The FIRRTL specification was originally a Berkeley Tech Report. However, it has evolved significantly since that point, including having a large authorship that is not adequately respected by the original document.

I've talked with @azidar about how to clean this up, e.g., changing this to be authored by "The FIRRTL Developers" or something and providing a history section that calls out the original authors. However, I leave it to him to determine the best course of action here.

Splitting `spec.md` into more modular files

Since spec.md is nearing 3k lines, are there any thoughts on splitting it into different files (based on sections or something)?

I think it's kind of difficult to do in Markdown... Has there also been any consideration to moving to AsciiDoc? Or whatever else is popular these days for docs.

I think splitting up spec.md would be beneficial for organizational purposes and ease of writing!

Moving to a different format (like AsciiDoc) might also allow for easier parsing (e.g. people can read directly off the GitHub without needing to build a PDF).

Cleanup Spacing in Primitive Operations Table of Contents

The spacing in the document for the table-of-contents in the "Primitive Operations" section is weird. I think this requires increasing the global spacing for bullet points. There may be alternative solutions. See the image below:

Screen Shot 2023-03-23 at 12 42 13

Fileinfo specification

Checklist

  • Did you write out a description of the feature you want to see?
  • Did you look around for any related features?
  • Did you specify relevant external information?

Feature Description

In spec.pdf, fileinfo is defined as info = @[string], but the format of string is not defined.
I think this missing will cause compatibility issues with other front-ends except Chisel in future.
Additionally, the current string format of Chisel lacks absolute file path.
This means back-ends of FIRRTL can't find the original source codes.

So I think the specification of fileinfo should be defined like below:

info = @[ [[absolute_file_path]] [[line]]:[[row]] ]
absolute_file_path = string
line = int
row = int

This specification is an idea, and I think it can be improved.
For example, file path encoded as URI. It is described at chipsalliance/firrtl#1695 (comment).

The debug information of LLVM-IR may be helpful.

Type of Feature

  • documentation

Related Features

#8

External Information

https://llvm.org/docs/SourceLevelDebugging.html#c-c-front-end-specific-debug-information

Add CI/CD flow to bump CIRCT Version

Now that code blocks are being tested. This repository is another candidate for a nightly CI flow and CD flow to bump the CIRCT version on new releases.

Build this out and land it.

Run the pandoc formatter

Let's run the pandoc formatter:

$ pandoc --wrap=preserve spec.md -o spec.md

Additionally, let's make sure we get this integrated into CI.

are zero field/variant enum/bundle types legal

afaict the specification doesn't specify if you can have an enumeration type with no variants {||} (the grammar allows it, but I'm not sure if that's intentional, since uninhabited types behave very oddly).
The specification says you can have a bundle type with no fields but the grammar doesn't allow it:

firrtl-spec/spec.md

Lines 4406 to 4415 in 9b0357e

(* Bundle Types *)
type_bundle = "{" , type_bundle_field , { type_bundle_field } , "}" ;
type_bundle_field = [ "flip" ] , id , ":" , type ;
(* Vec Types *)
type_vec = type , "[" , int , "]" ;
(* Enum Types *)
type_enum = "{|" , { type_enum_alt } , "|}" ;
type_enum_alt = id, [ ":" , type_constable ] ;

Update CI to Build Graphviz Images

With the addition of Graphviz to build some images for the spec, CI is now broken. We should update the CI to install graphviz and process all images in the graphviz area into the appropriate build area.

I'm not super happy about the CI right now because it doesn't use the Makefile. However, I had problems getting a Docker image that had everything necessary for this to work. I'd be happy with just installing graphviz and doing this in a loop as part of the CI action.

Missing specification of how bit numbers are determined

the FIRRTL specification doesn't specify how to determine if bits(UInt<8>(0hF0), 3, 0) returns 0hF or 0h0 -- specifying this is needed because some significant specifications (the PowerISA specification in particular) counts bits starting from 0 at the MSB end and counting up to the LSB end, and most others count bits starting from 0 at the LSB end, though I expect some start counting at 1.

[ci] Move Contributors to GitHub Action

The contributors are currently manually updated with a script that generates markdown. Convert this to a script that generates JSON/YAML and have pandoc generate the \itemize from it. The contributors now live in the JSON/YAML file and are treated like yet another pandoc --metadata input. Add a GitHub action to run the script and generate a PR to update the JSON/YAML if anything has changed.

When to use `<-` or `<=`

I am wondering when exactly the single line arrow <- is used to connect things. In the Partial Connects Section they are used

  • in the first example, performing an actual partial connection:
module MyModule :
   input myinput: {flip a: UInt, b: UInt[2]}
   output myoutput: {flip a: UInt, b: UInt[3], c: UInt}
   myoutput <- myinput
  • in the second, equivalent, example to fully connect parts of the bundle/vector entries:
   myinput.a <- myoutput.a
   myoutput.b[0] <- myinput.b[0]
   myoutput.b[1] <- myinput.b[1]

I searched the document for further occurrences of <- and found none. What exactly are the semantics of <-? It does not seem to be a typo as <- is also used to define the grammar in the Language Definition Section

I propose to either

  1. remove <- from the spec or
  2. extend the part on partial connections, formally introducing and explaining <-.

I am very much in favor of 1 as it simplifies the grammar and I do not see the need for a distinction between partial and non-partial assignments in the first place.

If there is a consensus here, I will happily prepare a corresponding pull request.

Linguist Support, TextMate Grammar Support

FIRRTL has enough usage (O(100) repositories) that we can get it in as a supported language by Linguist (GitHub's source code identification/highlighting repository). This requires two things as far as I can sort out:

  1. We need to provide a TextMate-compatible grammar definition. A very basic version of this is here: https://github.com/seldridge/firrtl-grammar/blob/main/grammars/firrtl.json Somewhat annoyingly, I think this needs to be in a separate repository (not firrtl-spec) whose directory structure matches that of a TextMate grammar definition/bundle.
  2. We then go through the steps to add this grammar definition to Linguist via a PR.

Structurally, we should probably create a tool directory inside firrtl-spec to start bundling some of these editor-specific things.

Search query for number of files: https://github.com/search?q=path%3A*.fir+NOT+is%3Afork+circuit&type=code&ref=advsearch&query=path%3A*.fir+NOT+is%3Afork+circuit

Add CI to Build and Publish the FIRRTL Specification

Add CI that will automatically build and publish the FIRRTL specification. At minimum, this should publish every commit to main. A possibly better solution would be to create releases for any tagged version.

Consider/Add "Strict Connect" Operation

Now that partial connect is removed and connect has width truncation/extension behavior, we should consider adding a new connect operation that has stricter semantics. I.e., a connect operation which mandates: (1) known widths, (2) type equivalence, and (3) width equivalence.

We've been using this inside CIRCT for almost a year and it's proved incredibly useful.

I'm using made-up syntax here (<==). The following example shows what is legal and illegal:

wire a: Uint<1>
wire b: Uint<2>
wire c: UInt

a <== a ; this is legal
b <== b ; this is legal
c <== c ; this is illegal

a <== b ; this is illegal
a <== c ; this is illegal
b <== a ; this is illegal
b <== c ; this is illegal

It continues to be true that type equivalence holds, e.g.,:

wire d: Uint<3>
wire e: SInt<3>

d <== e ; this is illegal
d <=  e ; this is still illegal 

The main benefit of this is that it is a connect that is amenable to folding (replacing a connect operation with its operand) without any creation of a new pad/tail operation. This also may help provide strict connect semantics to Chisel.

Note: the strict connect op cannot be used to exclusively replace connect in situations where uninformed widths are present.

Make Commas Mandatory or Remove Them

While never reflected in the grammar, implementations of FIRRTL compilers have always treated commas as whitespace. This historically is because the original FIRRTL compiler implementation (predating the SFC) was written in Stanza and Stanza took the approach of treating commas as whitespace. This was inherited in the SFC grammar description of FIRRTL and was carried forward into the MFC FIRRTL parser.

We should decide what to do here. Likely either make the commas explicit (as the existing grammar indicates) or remove the commas. I'm not aware of other languages which treat commas as whitespace, though there is precedent for languages which do not use commas, typically for function declaration/application (Haskell, ML variants).

I'd be in favor of making the commas explicit. This would be, in practice, entirely backwards compatible because: (1) Chisel has always emitted the commas, (2) the FIRRTL specification has always used commas in examples, and (3) the FIRRTL grammar either ambiguously suggested commas (v0.2.0) or explicitly required them (every version including and since v0.3.0). The only actual way that an implementer of a FIRRTL compiler would likely know that commas are whitespace was if they examined the SFC antlr grammar (which is technically the reason why the MFC parser picked up this quirk).

@mmaloney-sf, @dtzSiFive, or @azidar: do you have any opinions here?

Determine how to handle non-Verilog legal Extmodule DefName, i.e., Literal Identifiers

A circuit that includes a Verilog-illegal defname in an extmodule should be handled or rejected. This depends on the interpretation of whether the defname is the "Verilog name" or if it is an identifier used to uniquely group multiple external modules together. Practically, it's the former.

Consider:

circuit Foo:
  extmodule Bar:
    defname = 42_Bar
  module Foo:
    inst bar of Bar

For now, let's just reject this and require Verilog-legal names.

How should this work for literal identifiers? Is this any different?

Is Auto-Punching IO's a feature worth supporting?

There has been great discussion about this topic on #75 , but it is a separate idea so I thought we'd move the conversation to a dedicated issue.

Background

Chisel, SFC and MFC support a BoringUtils API which enables users to tell the compiler to drill ports between two marked signals to physically connect them in the generated hardware design.

This feature has been used for many use-cases, one of which was for forcing/reading internal signals when testing a component. Unfortunately, it was a slight mismatch in intent versus impact because an unfortunate side-effect is that the test harness now influenced the compilation of the DUT (design-under-test), which is non-desirable as the Verilog validated is not the Verilog in the final design which instantiated that component. For this reason (among others), FIRRTL is introducing reference types to enable more side-channel simulation features to accomplish this task (#75).

Motivation

Now that this test-harness/DUT use-case has a different solution and implementation, is there still an important use-case for this auto-punching IO feature?

Off the top of my head, there are some indications that this still may be useful. For one, diplomacy itself does auto-punching (via a different mechanism), which we can look into to understand what use-cases it services. Secondly, some conceptual hardware features have a spooky-action-at-a-distance feel to them, one example being BIST for memories.

If auto-punching isn't the desired solution, I do feel it will often be the solution users will ask for us, so a discussion about the pros/cons that represent our historical decision behind this will be useful to document.

what is an enum's corresponding mask type? for memory write ports

The specification doesn't specify how to construct a memory write port's mask type from the memory's data-type when the type contains an enumeration.

I suggest using something like this:

The mask type of a FIRRTL type is defined for the following memory data types:

  • Any Ground Type: The mask type is UInt<1>
  • Vector Types T[N] for any type T and any non-negative integer N: The mask type is M[N] where M is the mask type of T.
  • Bundle Types {field0: Ty0, field1: Ty1, field2: Ty2, ...}: The mask type is {field0: M0, field1: M1, field2: M2, ...} where M0, M1, M2, ... are the corresponding mask types of Ty0, Ty1, Ty2, ...
  • Enumeration Types: The mask type is UInt<1>

FIRRTL Rationale

We should add a place to document the "Rationale" for FIRRTL's design, perhaps in the spirit of MLIR's rationales: https://mlir.llvm.org/docs/Rationale/ .

This has been proposed and requested by a number of folks actively contributing to the specification, and let's start sorting out what this might look like and where.

Introduce LTL as a part of firrtl specification

Since Chisel has supported LTL via intmodule, I think it might be a good idea to upstream LTL as a part of firrtl spec. This cleans up the fir file generation, and makes LTL->SVA flow more clean and elegant.

[nfc] Add markdown formatter

Figure out how to add a markdown formatter that works with pandoc and things that it understands, e.g., inline LaTeX like \clearpage.

This may work by using pandoc, itself, as a formatter with something like pandoc Foo.md -o Foo.md.

firrtl does not have context free grammar (specification 0.2.0)

Hello!
I'm currently writing a firrtl lexer/parser for yosys using flex/bison and am a bit stuck because
the grammar of firrtl is not context-free.

This is because firrtl allows an id to be a reserved firrtl keyword or an integer literal.
(an id can be named mem, inst, b1, h32, o3)

Example of problems this causes:

  1. field of bundle named with a keyword:

    input a: {flip flip: UInt}
    

    This makes it impossible to write the following grammar:

    bundle_type:
        '{' bundle_fields '}'
    bundle_fields:
        bundle_fields ',' bundle_field |
        bundle_field ;
    bundle_field:
        flip_opt TOK_ID ':' type ;
    flip_opt:
        TOK_FLIP |
        /*empty*/ ;
    

    where TOK_FLIP is a token representing the keyword flip,
    where TOK_ID is a token representing an id (= a string)

    The following bundle definition would fail this grammar:

    input a: {flip: UInt}
    
  2. id named after a keyword used by a stmt, e.g. inst ( signal inst: UInt<1> )

    inst <= UInt(1)
    

    The following context-free gammar does not apply, and the parser will fail.

    stmt:
        TOK_INST TOK_ID TOK_OF TOK_ID opt_info ;
    

    where TOK_INST is a token representing the keyword inst,
    where TOK_ID is a token representing an id (=string),
    where TOK_OF is a token representing the keyword of,
    where opt_info is a rule that matches the optional @[""] info.

    This is a problem because the grammar above conflicts with:

    stmt:
        exp <= exp ;
    exp:
        id ;
    

    The lexer/parser does not know how to interpret the signal inst:
    When the lexer matches the string inst, should it interpret it as TOK_INST or as TOK_ID (with value inst)?

  3. id named that collides with the integer rules
    e.g.

    input b1: UInt
    

    b1 should be interpreted as the string/name b1 but it can also be interpreted as the 1-bit literal 0b1 by the lexer.

Root cause:
This is the same problem as Java/C++/python disallowing use of reserved keywords as variables.
That's why I propose to force escaping of reserved keywords by firrtl.

My proposal
LLVM IR requires variables to be prefixed by %, which would solve this problem completely.
I believe firrtl was designed in the image of LLVM IR, so why not copy this property too?
It would make it much clearer when reading code that something is a keyword or an id:

mem     ; <= reserved keywordis a literal
%mem    ; <= id

Rename "Passive" to "Simplex" [RFC]

The FIRRTL spec names types that all have the same direction with no flipped-ness as "passive" (https://github.com/chipsalliance/firrtl-spec/blob/e7199fcc219bbc6e8bf9f380dc15dcdac20961c2/spec.md#passive-types). In other words this is the opposite of "Duplex". In english "Passive" and "Duplex" do not seem like intuitive opposites. Would "Simplex" Be a better term? Or is there some implied meaning of "Active vs Passive", but "Active" does not appear in the spec except in the context of read/write ports which seems like a very different concern,

Duplex is currently defined in contrast with "sink" and "source" for Flows, so not sure if this is an appropriate substitution of saying "anything not sipmlex is duplex" since passive is talking about the type not the particular hardware (Node, reg, port, etc).

RFC: Capture the version of the FIRRTL spec in a .fir file

As the FIRRTL specification may evolve, it would be nice to know what version of the specification a given .fir file claims to comply with.

Considerations:

  • Should this just be a single version, or a range / regex?
  • What should be the change on the spec version due to the addition of this version (what are FIRRTL's own versioning rules)?

spec: Clarify literal parentheses vs. statement groups in grammar spec

Current text

See spec.pdf, section 14.2, "Concrete Syntax Tree". For example, see the definition for circuit on the very first line:

circuit = circuit id : [[info]]? ([[module]]...)

It is apparent from Listing 85 above that the parentheses are not literal, but represent a statement group. However, see the definition for exp/primop below:

exp = primop ( [[exp]]..., [[int]]...)

From the final line of Listing 85, it appears that these parentheses are literal parentheses.

Desired text

It would be very helpful to revise the spec to make explicit where parentheses are literal symbols and where they represent statement groups.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.