olofk / fusesoc

Package manager and build abstraction tool for FPGA/ASIC development
BSD 2-Clause "Simplified" License
1.18k stars 245 forks source link

Enable use of different files depending on build environment #103

Open imphil opened 8 years ago

imphil commented 8 years ago

We're currently trying to get a Xilinx DRAM controller (MIG) to work. In the core file, we include the IP-XACT file (*.xci), which then causes Vivado to generate the code for this IP. Right now, it looks like that:

[fileset core]
usage = vivado
files =
  ip/mig_7series.xci[file_type=xci]
  ip/mig_config.prj[file_type=data]

Unfortunately, (almost) each Vivado version comes with a new version of the MIG core. Xilinx provides a upgrade_ip TCL command to upgrade between the different cores. That works well as long as the core API does not change. So using a old version of the core and then upgrading it might work for many use cases.

When the core API changes, this does not work. In these cases, we need to include different source files depending on the used Vivado version: a different xci, prj and verilog file which wraps the core.

What would be the right way to support such a feature? I propose to have "conditional filesets", e.g. like this:

[fileset core_mig_3.x]
usage = vivado
onlyif = $vivado_version == 2016.2 || $vivado_version == 2016.1
files =
  rtl/verilog/mig_wrapper.v
  ip/mig_7series.xci[file_type=xci]
  ip/mig_config.prj[file_type=data]

[fileset core_mig_2.x]
usage = vivado
onlyif = $vivado_version == 2015.1 or $vivado_version == 2015.2
files =
  rtl/verilog/mig_wrapper.v
  ip/mig_7series.xci[file_type=xci]
  ip/mig_config.prj[file_type=data]

The onlyif would be a new command which evaluates an arbitrary conditional expression. As variables we provide a set of "facts" about the system, which can be provided by different "facts" classes. The $vivado_version is just one example. This idea is taken from Puppet/facter, where this concept works really well.

@olofk , @wallento: what do you think?

olofk commented 8 years ago

This touches upon two things that I have been thinking about quite a lot but never written down.

The first thing is detecting tool versions. We have other cases where we want to work around bugs in the tools (such as $clog2 being broken in different ways in different Xilinx tool versions). For this I think we should add a function to each backend to query the version.

The second thing is conditionals. There are lots of places where we could benefit from conditional inclusions, so I don't think we want to limit this just to filesets. We could basically support this for any string list in the .core files. My idea has always been to model this around Gentoo's conditional syntax, and in the long run also add support for Gentoo style use flags in the .core files, which is somewhat related. This would for example allow us to have conditional dependencies, or setting different tool parameters depending on which flags that are set. I'm not sure however how complicated this would be to implement, and this is partly why I haven't started working on it.

I'm not stuck on my original idea, but I want something that can encompass the different potential use cases that I have thought about. We should brainstorm a bit here and try to come up with some ideas here.

wallento commented 8 years ago

I am thinking about using branches and versioning, but also that does not really lead to a good scalable solution.

olofk commented 7 years ago

Actually, I just got an idea here. In the long term I still want the useflags solution, but I got something that's easy to implement and would solve a class of problems

All filesets have a set of usage flags. The recognized values are currently which type of flow (i.e. sim, synth) or the toolname (i.e. icestorm, ise, quartus, vivado, ghdl, icarus, modelsim, verilator, xsim) These flags are set internally by FuseSoC depending on the flow. What we could do is to allow users to set extra flags on the command line, and add these to the filesets. In your example we could set usage = mig2 on one fileset and usage = mig3. It's then up to the user to set the correct flags. By using a pre-build script we could perhaps even check that one of the flags are set before running

This would solve another class of problems that I have had, where I want to switch between generic and Altera-specific implementations of some primitives when I do a modelsim simulation.

It could look something like this

fusesoc --usage=mig3,xilinx_rams,bloated_cpu build nexys4

We could perhaps even allow negations, so that certain filesets are excluded if a flag is set, like usage = sim -mig3. Probably need to define some rules for that though, so maybe later. What do you think?

Fatsie commented 7 years ago

I am now playing with some 8-bit cores on freecores (T80 and T65). Coming from a software background I am surprised/confused by how unportable RTL seems to be between different platforms. One of the things I would like to have and help implement is generic RAM, ROM, register file blocks. The proposed usage directive is possible usable for that. I would like to limit the need for command line specification of the usage though. IMO, a generic 2048x8 RAM should use optimal implementation for given FPGA or ASIC without the need of specifying a usage on the command line; or do you want to move it to a tool on a higher level than fusesoc ?

olofk commented 7 years ago

Sorry for the late reply. My answer was becoming a bit longer than I had first intended, so I decided to address this in a blog post instead http://olofkindgren.blogspot.com/2017/01/the-dream-of-hdl-standard-libraries.html

One thing that is not answered in the blog is how to make FuseSoC aware of which implementation to use without manually specifying it. As a first step, I think we could write down the use flags that should be used in the top-level core file, so we don't need to specify them on the command line. In the long run I would like to have a somewhat more clever approach, but this should at least address the most common cases.

Also, I should let you know that I've started looking into the use flags implementation now. It's on top of the priority list and will hopefully be incorporated into FuseSoC soon, if I find the time to work on it