Skip to content

Conversation

@widlarizer
Copy link
Collaborator

Superior ASIC synthesis could be achieved with SDC (Synopsys design constraints) awareness and rewriting. While a standard for the SDC file format exists, every tool implements SDC with a lot of extra features. Instead of Yosys implementing its own flavor of SDC, complexity of ingested SDC can be reduced by letting OpenSTA resolve SDC itself. This PR doesn't make Yosys SDC-aware, but it is a dependency to that

This PR introduces the commands publish, icell_liberty, opensta, and sdc_expand. sdc_expand is an all-in-one script pass that expands SDC constraints by calling the OpenSTA executable through opensta. Before that, it uses the other passes to prepare: icell_liberty constructs a skeleton Liberty file for the yosys internal cells which publish makes non-internal.

OpenSTA reading in and writing out SDC resolves filters and regexes, ensures that there is one object being constrained per SDC line, and that objects are only referenced with getter SDC functions and not general. This is done based on exported elaborated Verilog netlist and a Liberty file modeling used Yosys internal cells. The Verilog support in OpenSTA is limited, so particular care is taken not to introduce language primitives it doesn't implement, like the reg keyword and parameters. reg is eliminated with the memory pass and the write flags for write_verilog, parameters are emitted in the defparam style which OpenSTA seems to happily ignore. I'm not aware of a case where the loss of parameters of internal cells would change what objects SDC applies to.

The Yosys-generated Liberty file currently only provides pin directions and some basic information about flip flops. We need at least this much to be able to resolve things like all_registers -clock_pins correctly. Polarities aren't implemented yet, so resolving SDC using features like -rise_from might be broken.

What I mean by "correctly": In hierarchical synthesis, the SDC file is applied entirely after synthesis, but if synthesis is allowed to do non-trivial transformations like eliminating module boundaries, the SDC has to be first interpreted on the pre-synthesis elaborated netlist, so correctness then means a correspondence of the objects SDC constraints match before synthesis and after. This requires the SDC writer not to rely on information that exists only after synthesis and isn't a Yosys-unique limitation.

OpenSTA is GPL-licensed software and will not be linked to or shipped with Yosys, this PR only adds an interface that can launch this program.

In #5197, I wanted to create one Liberty cell per unique set of parameters for an internal cell in box_derive. I don't think this is necessary anymore. OpenSTA complains about port (pin/bus) width mismatches, but expands constraints nicely. Also, I refactored kernel/ff.* to be able to yield information about flops just from the cell type.

As an example, this SDC can constrain tests/sat/alu.v:

create_clock -name this_clk -period 1 clk
create_clock -name that_clk -period 2 [all_registers -clock_pins]
set_input_delay  -min -add_delay -clock this_clk 1.0 [get_ports {A B}]

which expands to this (shortened):

current_design alu
create_clock -name this_clk -period 1.0000 [get_ports {clk}]
create_clock -name that_clk -period 2.0000 \
    [list [get_pins {$procdff$30/CLK}]\
          [get_pins {$procdff$31/CLK}]\
          [get_pins {$procdff$32/CLK}]\
          [get_pins {$procdff$33/CLK}]]
set_input_delay 1.0000 -clock [get_clocks {this_clk}] -rise -min -add_delay [get_ports {A[0]}]
set_input_delay 1.0000 -clock [get_clocks {this_clk}] -rise -min -add_delay [get_ports {A[1]}]
# ...

with an invocation like this, assuming OpenSTA binary sta is in PATH:
yosys -p "read_verilog tests/sat/alu.v; sdc_expand -sdc-in alu.sdc -sdc-out expanded.sdc

This PR is a bit overweight, but all its components are linked and I don't see an opportunity for reasonably cutting something out. Any suggestions for refactoring are welcome.

  • fix up help strings
  • figure out approach to testing with OpenSTA in CI

cc @jix @povik @mikesinouye @QuantamHD

@whitequark
Copy link
Member

whitequark commented Jul 18, 2025

This is an incredibly cursed solution. I'm unconvinced it's worth it going through this workaround just to avoid writing an SDC parser.

The main reason why I think it's the wrong approach is because in a properly built toolchain, SDC would be applied right after the frontend, with the constraints remaining attached regardless of which transformations are done, by being tied to the netlist entities rather than their names. This solution is everything I would not do.

The fact that non-Yosys toolchains can't correctly apply SDC constraints isn't an excuse or a motivation to not do better in Yosys.

@QuantamHD
Copy link
Contributor

QuantamHD commented Jul 18, 2025

This is an incredibly cursed solution. I'm unconvinced it's worth it going through this workaround just to avoid writing an SDC parser.

The main reason why I think it's the wrong approach is because in a properly built toolchain, SDC would be applied right after the frontend, with the constraints remaining attached regardless of which transformations are done, by being tied to the netlist entities rather than their names. This solution is everything I would not do.

The fact that non-Yosys toolchains can't correctly apply SDC constraints isn't an excuse or a motivation to not do better in Yosys.

Hey @whitequark,

I think you might be missing some of the reason for this solution to exist, and why it was requested in the first place. First I do want to agree with you I think this solution is not ideal, but the overall goal is to allow Yosys to correctly mark netlist elements that are optimization barriers, because they have SDC constraints that must apply before and after yosys processes the RTL. In off the shelf tools your synthesis tool would emit an SDC file that you read in place and route tools that respects the original intent of the constraints, but is flattened and where names may have changed.

Ideally Yosys would implement a direct link to OpenSTA, and implement its network API which would give you the constraint propagation, SDC writing and constraint query for "free". However, given that OpenSTA and Yosys have license conflicts that's not possible.

Thus, we're left with two options that are not great in my opinion, but where one has fewer downsides:

  1. Yosys implements it's own STA parser.
  2. Offloading the SDC parsing to a downstream tool, and reading the simplified constraints back into Yosys in order to put up optimization barriers so that the original SDC applies to the emitted netlist.

Solution 1 is non-ideal for a couple of reasons:

  • there is no actual standard for SDC, just a loose collection of similarish TCL functions, and some non-overlapping functionality. Which means that for any SDC users you would basically only be allowed to use the intersection of what Yosys supported and the downstream tool they are using. In practice that's going to be a very very small subset of functionality.
  • This general intersection will make it even harder to integrate tools together, and cause further fragmentation between tools. Ideally, we would all gather around a single implementation of SDC.
  • SDC's in many cases are actual programs that need to executed, and in particular some of the SDC query constraints themselves rely on physical information stored in LEF/DEF. So in order to even significant coverage of SDC functionality you would need to create an interpreter for the query language and connect it to physical information.

Solution 2 is obviously non-ideal in its implementation being extra weird, but has a lot of nice properties:

  • That it doesn't cause the intersection behavior since we're using the same SDC parser as OpenROAD. Meaning users won't need to tailor their SDC to the subset that makes Yosys and OpenROAD happy.
  • It's relatively low cost, in that YosysHQ isn't signing up for a massive amount of work to implement SDC where that SDC engine is providing little to no value to Yosys the compiler other than to just say don't optimize this thing.

I do understand your concern around it being very hackey, I agree with you on that, but I think in the short term this unlocks a big set of functionality for ASIC users at relatively low cost, and make Yosys a lot more amenable to adoption in chip design workflows. In the long term I would like to see some solution that allows OpenSTA to be connected to Yosys perhaps over a shared memory bus or RPC that would obviate the need for this solution, but I think for now this is the right tradeoff at this moment in time.

I hope that helps clarify and gives further context on the sets of things being traded off.

@whitequark
Copy link
Member

whitequark commented Jul 19, 2025

  • there is no actual standard for SDC, just a loose collection of similarish TCL functions, and some non-overlapping functionality. Which means that for any SDC users you would basically only be allowed to use the intersection of what Yosys supported and the downstream tool they are using. In practice that's going to be a very very small subset of functionality.

Yes, I realize that. In fact in prjunnamed, we will eventually have to write our own SDC parser for the exact same reason, which is why I've spent a while considering the problem domain.

I offer Solution 3: Implement an SDC parser under a permissive license that could be used by multiple tools to get an identical, or at least reasonably close, view of the SDC information. (Yes, this will get pretty complex when querying physical information gets involved, but it's not like you get this "for free" this way either. For example, as far as I can tell, your approach will not benefit FPGA flows at all, which is another significant drawback of what's laid out here from my perspective.)

Ideally this would be coupled with a proper "de facto" specification (i.e. a document writing down what the actual use is, rather than defining what the use should be), similar to how it happened with HTML, but even a collection of C files implementing the functionality would be a step up from either this or your RPC/shared memory proposal (which I believe solves essentially none of my issues with what's laid out here).

@jix
Copy link
Member

jix commented Jul 19, 2025

The main reason why I think it's the wrong approach is because in a properly built toolchain, SDC would be applied right after the frontend, with the constraints remaining attached regardless of which transformations are done, by being tied to the netlist entities rather than their names.

That's what I've argued for before, but I'm not opposed to a adding a hack like this to get bug/non-standard compatibility with OpenSTA in the near term. My idea for transitioning to proper SDC support would be to add such a constraint tracking infrastructure and a simple SDC parser to yosys, initially still relying on OpenSTA to turn complex SDC files into expanded normalized SDC files so we can get away with a very simple parser and then gradually expand that so you don't need to rely on a hack like this unless you really need exact bug/non-standard compatibility with OpenSTA.

@whitequark
Copy link
Member

My idea for transitioning to proper SDC support would be to add such a constraint tracking infrastructure and a simple SDC parser to yosys, initially still relying on OpenSTA to turn complex SDC files into expanded normalized SDC files so we can get away with a very simple parser and then gradually expand that so you don't need to rely on a hack like this unless you really need exact bug/non-standard compatibility with OpenSTA.

This essentially makes sense. My opposition is primarily down to the fact that nothing either in the PR description or in the follow-up explanations suggests that this is the plan. Rather, I concluded from the PR description and the follow-up explanations that the conceptual OpenSTA integration is the end point of the plan, and the improvements would perhaps include a slightly different flavor of OpenSTA integration that changes nothing conceptually.

@widlarizer
Copy link
Collaborator Author

To confirm and reiterate, this doesn't absolve us of or prevent us from implementing SDC properly soon too. As for actual SDC reading, the general idea is that we have SDC functions implemented with Tcl stubs, with some core Tcl functions implemented in C++. The stubs have to let Yosys know which function arguments should be captured as an object to track, and to allow Yosys to rewrite the constraints later. I have an prototype for OpenSTA to provide these stubs to reduce version mismatches. For SDC flavors other than OpenSTA, manually written stubs based on users experience with, say, FPGA vendor tools would come into the picture when we have the infrastructure in place. It would also be a good opportunity to make a call for external contributions. With non-OpenSTA EDA flows we would not be relying on OpenSTA to expand anything as we'd first limit the constraints to ones excluding some of the more annoying features. We can add those as we gather feedback from the user base for the early phases.

I left this out on purpose as it's a discussion for when I have code ready to look at and explanation of the code I do have was getting long enough. I think infrastructure centered around a permissive implementation sounds definitely interesting. The angle we're taking right now should help us confirm our ideas about what users actually expect of SDC, so it should be of benefit to alternate approaches too

@phsauter
Copy link
Contributor

phsauter commented Aug 4, 2025

I agree with @whitequark that a full SDC parser with proper annotation would be a technically better solution by itself but the main problem I am encountering daily with SDC is exactly this non-standardization.

Examples:
The obvious once are commands that some vendors add to improve the user experience (eg Vivados set_bus_skew which is a lot nicer to use than set_data_check) but on top of that you also have arguably the same commands being interpreted slightly differently by different tools. A classic is how exactly the tracing of timing arcs works and interacts with things like -hierarchical, -flat or -level. Another one is -filter which is directly dependent on the exact properties available and they differ from each tool to the next.
Then there are more subtle and dangerous things like when and how exactly set_sense -type clock (or equivalent) applies, what exactly is or can be a start/endpoint and if this does or does not belong to some cell or module or how exactly set_multicycle_path works (yes, there are tool differences in how exactly the clock edges are counted here).

The problem with SDC
In my view the biggest problem with everything here is that SDC is a pseudo standard where people essentially try to mimic the commands Synopsys laid out in their original SDC and then adding some things. However, since people clearly went off the definition of the commands in the docs instead of the code (because they didn't have it), this creates differences in the implementation.

The spherical cow in a vacuum
In an ideal world someone would sit down and instead of defining it top-down (command X does Y) you would define precisely how timings, paths and arcs are created, formatted and processed. Meaning you would have to start with the basics in the sense of "you have internal and external (named) nodes. Start and endpoints are always on internal nodes, multiple nodes can connect to the same nets on different hierarchy levels. Eg a port has an external node which is the outermost point, then there is an internal node where delays etc are applied, then it goes to a outer part of the module pin, to the internal of the module, then to the pin of a cell and then to the internal of the cell."
Except it would have to be formal and very explicit instead of this rambling. I just wanted to show that it would require a lot of work to do it the proper way.

If we can find somebody that would be interested in this I would gladly support the effort by giving feedback and testing it, I also dislike the state of SDC today.

What is my point?
My point is that it seems to be surprisingly difficult to interpret SDCs exactly the same way in all circumstances. This means every tool needs a different set of constraints. This is acceptable of you have the market share of Xilinx, Synopsys or Cadence but fracturing the open-source constraints is a really bad idea. I think the constraints for the open-source tools should ideally be as cross-compatible as humanly possible, this should be the top-most concern of any implementation.
In this sense, the OpenSTA approach does make sense just because the same thing is used to parse SDC.

Sidenote
I actually think SDC commands are just not good in general. I can see where they are coming from and what the idea behind them is but I think there most be a way to define timing constraints in particular that could more directly communicate the designers intent. Do not ask me how this would have to look like in practice, I do not know. What I do know is that SDC are often incredibly unintuitive and require lengthy comments to explain to the next guy what even the goal of something is.
I think an ideal system would more closely integrate with RTL as well, again don't ask me how exactly.

@whitequark
Copy link
Member

If we can find somebody that would be interested in this I would gladly support the effort by giving feedback and testing it, I also dislike the state of SDC today.

You might want to join #prjunnamed:catircservices.org on Matrix or #prjunnamed on Libera IRC.

@robtaylor
Copy link

Maybe an idea would be to have a structured data representation of SDC constraints, which within OSS we can represent as yaml/json etc, and leave parsing of generally source SDC files as a second problem

@phsauter
Copy link
Contributor

Maybe an idea would be to have a structured data representation of SDC constraints, which within OSS we can represent as yaml/json etc, and leave parsing of generally source SDC files as a second problem

I think I understand the intent but without some formal grammar describing exactly what is an endpoint, an arc, a path etc this would most likely still leave some room for interpretation after the intermediate representation, leading to slightly different reported timings.
Its probably still worth thinking about as it should eliminates the vagueness of how exactly the commands themself are to be interpreted (at least within the tools that would adopt this).

@widlarizer
Copy link
Collaborator Author

For more discussion of the some paths Yosys might be taking, check out https://yosyshq.discourse.group/t/sdc-support-roadmap/95

@robtaylor
Copy link

robtaylor commented Oct 7, 2025

That looks like great work, thank you!

I suspect it might prove problematic if we commit as a community to only using a proprietary format (Though of course compatibility is important)

Perhaps a start for a community owned format would be an easily parsable representation of the call graph?

@widlarizer
Copy link
Collaborator Author

Please prefer responding in the Discourse forum thread, the forum is the intended place for broader conversations, so that PRs can focus on discussing patches

@robtaylor
Copy link

Done! Thank you for the kind pointer

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

Successfully merging this pull request may close these issues.

6 participants