byuccl / spydrnet

A flexible framework for analyzing and transforming FPGA netlists. Official repository.
https://byuccl.github.io/spydrnet
BSD 3-Clause "New" or "Revised" License
91 stars 22 forks source link

Minimal example script? #121

Closed JensRestemeier closed 3 years ago

JensRestemeier commented 4 years ago

It would be useful to see a minimal example script to create a design like the one in the documentation (https://byuccl.github.io/spydrnet/docs/stable/reference/classes/index.html#fig-exampleir) from scratch in python, i.e. start with netlist = sdn.ir.Netlist() and end with sdn.compose('.edf', netlist). The examples included seem to be more complicated designs created with design software, and the example scripts seem to be more advanced.

Also, is it possible to add a physical pin constraint (i.e. pin on actual hardware) to a port?

thunder-hammer commented 4 years ago

It would be useful to see a minimal example script to create a design like the one in the documentation (https://byuccl.github.io/spydrnet/docs/stable/reference/classes/index.html#fig-exampleir) from scratch in python, i.e. start with netlist = sdn.ir.Netlist() and end with sdn.compose('.edf', netlist). The examples included seem to be more complicated designs created with design software, and the example scripts seem to be more advanced.

We have been interested in improving our documentation, and I think this is a great suggestion. We will likely implement something along those lines in the near future.

Until we get that, some of the unit test files do create a design and then populate it. For example:

https://github.com/byuccl/spydrnet/blob/master/spydrnet/tests/test_flatten.py

I know this isn't nearly as helpful as a real example file, but hopefully it's better than nothing.

Also, is it possible to add a physical pin constraint (i.e. pin on actual hardware) to a port?

Currently we don't support constraints (we have discussed it but it is on the backlog)

As a possible work around: There is a metadata dictionary associated with the top instance. physical pin constraints could be added there and written to a constraints file in the compose step. a simple example netlist = sdn.ir.Netlist() library = netlist.create_library() definition = library.create_definition() instance = sdn.ir.Instance() instance.reference = definition # make the instance an instance of definition netlist.top_instance = instance netlist.top_instance["constraint_key"] = "constraint_value" # where key and value are a pin or port name and physical pin location The constraints could then be accessed before or after compose and written to a constraints file.

Adding constraints on wires like false path would be a little more complex when it comes to writing the file. but could be done in a similar way with the metadata field on the cables.

JensRestemeier commented 3 years ago

I finally finished some other stuff which gave me the chance to look at his a bit more. Attached is "minimal.py", which should replicate the diagram from https://byuccl.github.io/spydrnet/docs/stable/reference/classes/index.html#fig-exampleir . I had to dig through the code in areas where the documentation is incomplete.

Thoughts:

minimal.zip

thunder-hammer commented 3 years ago

These are some great recommendations, and some good looking code. I'm glad you were able to figure it out.

Thanks again for the insight. It's nice to get a fresh perspective.

thunder-hammer commented 3 years ago

Also do you have any specific suggestions where we can improve the documentation?

JensRestemeier commented 3 years ago

When people people arrive at a library like this they usually have zero knowledge - maybe they have a vague idea for an application, their manager wants them to integrate it into another system, or their professor sent them to implement an optimisation or fitting algorithm for a paper. Additionally a lot of EDIF-specific information has fallen off the internet by now, or is behind a sizeable paywall. (AFAIK you can get the EDIF 3+4 specifications only on a CD-ROM (!) for hundreds of pounds.)

For a start: https://byuccl.github.io/spydrnet/docs/stable/install.html https://byuccl.github.io/spydrnet/docs/stable/tutorial.html https://byuccl.github.io/spydrnet/docs/stable/reference/introduction.html https://byuccl.github.io/spydrnet/docs/stable/reference/classes/index.html Contain a lot of duplicate information - installing a python package, loading it, and creating an instance of the top level classes are common operations for python users, so they can be mentioned once in the installation instructions and then just referenced.

What you need to know (and what I had to work out):

Yes, in hindsight these are obvious, and the library handles them well, but it is not easy to extract this knowledge from a large script that does an advanced operation.

On the API there is lots of missing knowledge about function arguments, for example: https://byuccl.github.io/spydrnet/docs/stable/reference/classes/cable.html What are properties? What properties are supported on different object types? Which ones are just meta data, which ones are written to the output file? Which ones are interpreted by functions or other tools? Which ones are written by other applications?

People rarely read documentation from beginning to end, so if there is a common parameter or an example there should be a link back.

Or: https://byuccl.github.io/spydrnet/docs/stable/reference/classes/port.html How do I set the direction? I had to browse the code to find that, also which values are supported.

Now that I have a working example I can focus on other parts of my project that generate a netlist. (You're welcome to keep it, btw.)

JensRestemeier commented 3 years ago

If it helps, this is my test code for the properties:

# quick property test:
edif_properties = {
    "INIT":"64'h7FFF8000FFFE0001",
    "CHIP_PIN_LC":"chip1@2" # https://www.intel.com/content/www/us/en/programmable/support/support-resources/design-software/max_plus-ii/plcassn.html
}
instance3["EDIF.properties"] = [{"identifier":key, "value":value} for key,value in edif_properties.items()]
top_instance["EDIF.properties"] = [{"identifier":key, "value":value} for key,value in edif_properties.items()]
widget_in_A["EDIF.properties"] = [{"identifier":key, "value":value} for key,value in edif_properties.items()]
widget_def["EDIF.properties"] = [{"identifier":key, "value":value} for key,value in edif_properties.items()]

I am going to close this issue now, as my problem is resolved.