Oh VHDL, you make my life so wonderful. I just want to be able to enable or disable different debugging features at compile time. But no, there’s no real preprocessor support in the VHDL world.
So my solution was to write a wrapper script that fakes out GCC into using its preprocessor and then generating a new VHDL file. It takes two files as input: the [cci]prj[/cci] file you would use for XST and a [cci]config[/cci] file that has a bunch of key=value pairs that get passed as directives for the GCC preprocessor.
For each file, it then invokes the following magic:
[cc lang=”bash”]gcc -Dwhatever=whatever -traditional-cpp -E -x c -P -C file.vhd[/cc]
This causes GCC to treat the VHDL file as just a generic C file and only processes the standard preprocessor directives like [cci lang=”c”]#if[/cci].
It then saves the result to a new file. So if you were processing [cci]file.vhd[/cci], it would generate (by default) [cci]file.gen.vhd[/cci]. It stores these files in the same directory as their pre-preprocessed versions.
Finally it creates a new [cci]prj[/cci] file that you should pass into XST.
So, it’s super easy to use. All you need to do is run [cci lang=”bash”]vhd-preproc.py -p /path/to/project.prj -c /path/to/config[/cci] and all your files will be preprocessed.
One of the biggest problems with the Xilinx workflow is that it doesn’t adhere to the way that people typically work on their projects nowadays. The Xilinx tools basically vomit intermediate build files and log files all over your build directory, making it hard to tell which files are the ones that are important (i.e. modifiable by you) and which ones are just debris.
Can we fix this? Mostly, yeah. Here’s how. These are the things I wanted to have happen:
- Compatible with version control software — all build files should go in a separate directory from config files and source files
- Completely command-line build and programming process (so that I can easily automate what I’m doing)
- Easily-available logs and reports
So, I have a directory structure that goes like this:
- gen/ — Coregen-generated files
- hdl/ — VHDL sourcecode
- proj/ — project config files
- xil/ — build files generated by Xilinx tools
- xil/xst — I’ll get to these later
- xil/reports — Final spot for all logfiles generated
- other crap
This way, I can just add xil to my .gitignore file and all the build files will be ignored, but everything else will be tracked. I can easily switch between code branches without having to worry that my project files will be stale. Perfect!
All right, now to tackle the next problem: how do you actually make Xilinx follow these standards? Well, I created a build script (note: I am ashamed to say that I still have pretty much no clue how Makefiles work, so I just wrote a shellscript). Here’s how I built it. Knowing this process will help you to set up your own projects for command-line building.
- The first step is to just make your project with the Xilinx ISE GUI. It will automatically set up all the files you need for building. Yes, you can make all these config files yourself, but that’s a huge pain and you only need to do this once.
- After you set up a project with the GUI, build it all the way through generating a bitfile. This will allow you to figure out what commands ISE actually runs in order to produce your buildfiles. You can find these commands in the logs that are generated (search for “Command Line:”).
- Now check out this build script. You should be able to roughly match each command that ISE runs with a command here. Basically, the process for going from HDL to a bitfile is this:
- xst takes your sourcefiles and generates an NGC file
- ngdbuild takes your NGC file and generates an NGD file
- map takes the NGD file and makes an NCD file
- par takes that NCD file and does placement and routing, producing another NCD file
- trce uses that NCD file to check timing constraints and stuff
- bitgen also uses the NCD file to create a BIT file
By passing some special flags into each of the programs, we can tell them where to store all their intermediate files, making things nice and neat!
- The build script I included needs some modification so that it works with your project. Based on what you see from ISE and from this buildscript, you should be able to modify the command line switches to get what you want. Also, take a look at the Xilinx Command Line Tools reference guide.
- You’ll need the following project configuration files from the project you generated with ISE (projname being the name of your project). Put these in your proj/ folder.
You should also put your UCF file in your proj/ folder.
- Check projname.prj to make sure that the HDL source files are with relation to your base directory (if you follow my design, they should look like hdl/something.hdl).
- projname.xst needs to be modified a bit.
- tmpdir should be xil/xst/tmp
- xsthdpdir should be xil/xst
- Make sure there is a line that looks like -lso proj/projname.lso after the run command. If not, add it.
- Finally, I have a batch script for Impact for programming my device (ML605 for me). This is highly dependent on what board you have, but here’s my batch file. To make your own, consult the Impact documentation and also run the Impact GUI and watch for the commands it runs in the command window when you program your board.
Yeah, it’s a bit of a process for getting things to work, but once they do, your productivity should go up quite a bit. Once you get used to this design anyways, it’s easy to create new projects that look similar. Best of all, they’re very compatible with version-control programs.
Yay, now Xilinx ISE sucks a little less! 🙂
I’ve spent January doing some initial work on my thesis. I’m working on channel emulation for the Airborne Networks Group of MIT Lincoln Lab. My work involves the use of a sweet FPGA eval board (Xilinx ML605, which has a Virtex 6) and an even sweeter addon board that has two high-speed (i.e. expensive) ADCs and DACs on it.
Unfortunately, interfacing the addon board (called FMC110) is a complete pain in the ass thanks to the complete lack of implementation specifications. It’s been a lot of reverse-engineering 4DSP’s reference design and taking guesses and I’m still having no luck with even the most basic aspects of interfacing the board, but nevertheless I’m still trying.
I use Chipscope a lot since I don’t have a logic analyzer. Chipscope is an FPGA-integrated logic analyzer that lets you capture data on your FPGA and view the waveforms on your computer using their software.
It works pretty well. I’ve found that you have to put everything into registers before you send the data out (pipelining everything), but other than that, integration is very easy.
What sucks, though, is the Chipscope software. The waveform viewer is written in Java and doesn’t even support horizontal scrolling. Come on. Seriously? Like literally the most important thing you should ever have in a waveform viewer is the ability to easily scroll around. Chipscope lacks a whole bunch of other features so I’ve been anxious to get rid of it. I didn’t know that you could until I discovered that if you go to File -> Export, you get this window:
Turns out, there are waveform viewers that are free and are actually reasonable! For example, GTKWave! So, by exporting all the buses to a VCD file, you can import this file into GTKWave and view your signals without the misery of having to use Chipscope. Check it out: