4 comments

[ 3.2 ms ] story [ 17.1 ms ] thread
This is one of those repeatedly solved problems in chip design... Here is my solution:

https://github.com/jhallen/joes-sandbox/tree/master/verilog-...

My solution allows you to define registers as module instantiations throughout the design hierarchy. Parameters give the address and bit positions of each register. A tool extracts the registers and generates documentation and a C header file for the chip. The tool has to elaborate the design to determine the parameter values- so it also handles derived addresses by handling math involving parameters. It generates C names for the registers which match the register instantiation path in the design hierarchy (and tries to simplify it by providing just enough of the path to make the names unique). Field names are derived from the names of the wires connected to the register bits.

I've seen other tools which work the other way: the master is a C header file, and the Verilog is derived. I'm not a fan of this, since it means you are have to plumb signals to a central register file module, which creates a big mess.

I like to use an OR-tree for the on-chip register bus- I think it's the optimal design for FPGAs. I have a library which includes simple registers and modules which allow the internal bus to cross clock domains. Look at bus*.v here:

https://github.com/jhallen/joes-sandbox/tree/master/fpga/hdl...

You have to plumb just two identifiers throughout the design for the registers: bus_in and bus_out.

Yes, you are absolutely right about "repeatedly solved problems", so it is definitly one in the series of "yet another ...". I'll try your program on our project files to see what registers it can extract from it. I'm assuming that there is no perfect universal solution, and I agree that Verilog-to-C (just having C in the back of your mind while working on the FPGA) is better here than C-to-Verilog. So in our case there is no automatic generator, code just helps you to avoid errors. Python program imports Verilog parameters/localparams (just constants and the the ones derived from them using expressions) and catches most of the typos when I write the generator code (not dramatically shorter than what it generates). This allows me to be flexible - the instantiated modules are not very uniform and not all have exactly the same interface - many were developed a long time ago starting as early as 2002. Not many are that old, but there are still many interface variations, and I do not mind going once more through them before switching to the C work from Verilog. I want just two things:

- reduce the number of possible errors as a result of the manual translation and

- make this (somewhat hand-crafted) converter be able to synchronize future changes in Verilog code to the C code that uses it, so five years from now it will be easy to add functionality to the system.

And thanks again for the links - I'll look more into your code.

First, I've never programmed Verilog before. But I see this breaks the DRY principle. If I'm in your position, I may put the information into data, and interpreter the data in Verilog, C, python.

Again, I don't have Verilog experience before and I might be totally wrong.

Yes, I'm guilty in DRY violation and I mentioned it in the post - I still manually translate Verilog to Python when go from simulation/debugging to hardware testing/debugging. And we are looking to use a more productive way to do this - write the simulation code (that replaces the CPU activity of the real hardware) in the programming language (Python) rather than switching to System Verilog that is somewhat in between the hardware description language and a software programming one. That is in our future plans, not there yet.

Other than that - DRY is always in our agenda, and there is only one place that holds the parameters/ preprocessor macros that define the hardware and its software interface. Python code reads Verilog files and extracts all the parameter names and values (names/types are automatically added to the Python source to allow checking). That Python code allows to run tests on the target system, do some calibration and save results in the same Verilog parameters format (same as here https://github.com/Elphel/x393/blob/master/includes/x393_cur... , just no header). Same program uses Verilog data to export C files, it uses hand-crafted code to allow flexibility - it is not always possible to fit everything in the same format, but here the focus is again on the DRY - new code to do what is different, and use common code that processes multiple data items as much as possible. And when it is not - provide checks to catch differences when you do have to repeat yourself.

Only part of the Python code is a "translation" of the Verilog tests (and this we plan to eliminate in the future), the rest is just a continuation of the project, and when writing (not just running) that code I'm re-using data exported from the Verilog (and re-exported when there are changes that influence data). Same with C - code continues the project, re-using Verilog+Python data.