Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow "pass-thru" synthesis annotations on ports and name bindings #445

Open
thoughtpolice opened this issue Jan 29, 2022 · 3 comments
Open

Comments

@thoughtpolice
Copy link
Contributor

There are many use cases for attributes that are specified in the netlist; the most direct reasons are to guide the synthesis tool in some manner. Unfortunately, it's not possible to preserve or write arbitrary attributes in any way.

Two examples

There are two attributes I can think of off the top of my head.

(* keep *) and (* preserve *)

In various cases you want the synthesis tool to not strip wires. My need for this is actually normally very pedestrian: I like to design things by writing empty modules and specifying the interfaces first, and I'd like to annotate the ports as (* keep *) so that I can properly see the block diagram layout in the synthesis tool is correct. (You can often just keep a bunch of things and incrementally remove them as you iterate and play with the design; it's normally how I make sure the synthesis tool is happy with particular constructs.)

Things like altera_attributes

Attributes like altera_attribute allow you to specify things like entity and instance properties such as pin assignments directly (see the example below,) and also guide other features. But pin assignment in a top level is something that would be nice.

Prior art

This is mainly inspired by Clash, which has a type-level function called Annotate that lets you add attributes to things. For example:

blinker
  :: Clock Input
      `Annotate` 'StringAttr "chip_pin" "R8"
      `Annotate` 'StringAttr "altera_attribute" "-name IO_STANDARD \"3.3-V LVTTL\""
...

Maybe a hypothetical example

I have a pinout for the DE10-Pro and it would be nice if I could specify the clock pins and IO standards at the same time I write the port description. Here's a modified sample that might serve as a starting point:

interface FpgaTop;
  (* always_ready, result="LED" *) method Bit#(4) led;
endinterface

(* synthesize, no_default_clock, no_default_reset *)
module bsv_fpga_top
  ( (* osc="CLK_50_B2C" annotate[chip_pin] = "PIN_AW38", annotate[altera_attribute]="-name IO_STANDARD \"1.2 V\"" *)
    Clock clk_50_b2c
  , (* osc="CLK_50_B3I", annotate[chip_pin] = "PIN_M24", annotate[altera_attribute]="-name IO_STANDARD \"1.8 V\"" *)
    Clock clk_50_b3i

  , FpgaTop ifc
  );
  ...

  method Bit#(4) led = ...;
endmodule

The new syntax annotate[x] = y would add the attribute (* x = "y" *) in the generated netlist. (Why introduce the brackets? Because it's significantly less ugly and requires significantly less quote-escaping than just using a raw string with cases like attribute="x=\"...\"y\"...\"")

Alternatives

The pinout example has an obvious workaround, but in general you have to write a SystemVerilog module with the proper annotations, and then import it directly by writing a BVI import for it.

@quark17
Copy link
Collaborator

quark17 commented Feb 5, 2022

Again, I appreciate you making suggestions!

BSC supports a doc attribute, that can be attached in a few places (on modules, instances, and rules) and which is passed through the compiler and becomes a comment in the generated Verilog. Some people have repurposed this for pass-through attributes, by combining it with a post-processing script (with -verilog-filter) that looks for the doc string and rewrites it in the desired form.

So I think there are two separate issues here. One is just increasing BSC's capability for passing attributes through from source to output, and two is adding new attribute behaviors.

In your example, there is a pass-through attribute attached to a module port. Right now the doc attribute can't be attached there. But ports are something in the source that has a predictable correlated location in the output, so it makes sense to allow a pass-through attribute there.

Not everything in the source is preserved in the output (even if it had an obvious analog to begin with). With the doc attribute, if you put it on an instantiation but that instantiation is not a synthesis boundary, then the instance is inlined and the output Verilog doesn't have a Verilog instantiate for it; in that case, the doc comment is placed on the parent module (with text saying that it's for an inlined submodule). Similarly, the doc comment for a rule is placed before the WILL_FIRE and CAN_FIRE signals, which can also be inlined and not appear in the output. So I think it's worth identifying what are the places in the source that we want to annotate, and what that correlates to in the output, and what (if anything) needs to be done to preserve that location in the output.

Separately, I think it's a good idea to add a new attribute (or attributes) to directly support the kinds of things that people currently repurpose the doc attribute for. (The implementation for doc could be copied or extended.)

For the annotate attribute, I don't think that we need to resort to brackets. I might suggest syntax like this:

(* annotate = "x" *)
(* annotate = "x, y" *)

That is, the BSV parser would check that the first thing in quotes (the x) is a legal attribute identifier, optionally followed by a comma and then everything after the comma is the value for that attribute. (Although, I guess any character could be used instead of a comma, so it could be an equal-sign. Maybe I'm just influenced by the fact that a number of attributes are already parsed as comma-separated lists.)

(At the moment, BSV is its own language and is mostly a skin on the underlying language, but originally the goal was for it to be an extension to SystemVerilog, and the current situation was just supposed to be a stepping stone towards that. So there used to be a lot of resistance to anything that wasn't SV syntax. But that ship has sailed, so we're probably more free to make changes to syntax. But we probably shouldn't diverge unnecessarily. I think in this case we could avoid inventing a bracket syntax.)

Pass-through attributes could also be inserted into the output Verilog using Bluetcl or BSC features for correlating source names with output names. Such features could also be more generally useful. Sometimes you don't want an attribute in the output Verilog, but you have additional files that sit beside it (like a constraints file) and that file needs to references names/entities in the output Verilog, which may have names that don't exactly match their analog in the source. You may want BSC/Bluetcl to tell you the output names, knowing just the input names.

@quark17
Copy link
Collaborator

quark17 commented Apr 8, 2022

FYI, I looked into this with @rsnikhil who may contribute some enhancements.

As I mentioned, a first step would be to increase the places where the doc attribute can be placed, to include placing it on module arguments. (That should be easy to parse and record; it just remains to decide where it appears in the generated Verilog.) A second step would be to allow a new annotate attribute in places where doc is supported.

@quark17
Copy link
Collaborator

quark17 commented Apr 18, 2022

Nikhil pointed out that @jahagirdar also brought this up on the discussion mailing list last year: https://groups.io/g/b-lang-discuss/topic/80355042

In that thread, he mentioned some other scenarios to be mindful of: (1) attributes (like doc) aren't supported on methods (also files as #470) and (2) some state is inlined (like PulseWire). I'm also tagging him here, in case he has other situations to contribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants