M-Labs does engineering contracts for physics, which is fun because it is multidisciplinary, advanced technology, and open source friendly.
Milkymist is a previous project of Sebastien, a SoC he wrote completely in Verilog. To aid the development he developed Migen FHDL (after failing with MyHDL, which is just a syntax converter + some optimisations), which is heavily based on dataflow representation. It is based on metaprogramming, i.e. you can manipulate the design from a python program, to generate the repetitive parts. Out of that grew MiSoC to build SoCs.
Migen gives python objects to assemble into a design. There is also syntactic sugar using operator overloading to compose things easily (e.g. a|b instead of _Operator(“+”, [a, b]). It adds abstractions for synchronous operations (which add a clock to the logic). Also for FSMs (which generate a lot of conditions in the Verilog), which in addition to state changes also put output signals at specific values.
Metaprogramming is very good for bus decoding and arbitration: you can easily write a python function that generates the bus logic based on some input parameters. For memory-mapped IO, there is a class AutoCSR that automatically generates the address map and corresponding C header file.
The design is then converted to Verilog for synthesis (buggy VHDL backend exists as well). The conversion will look at stacks etc. to try to give meaningful names to the Verilog design, so the output is in fact human readable. Generation is started by calling a function, so what is generated is the design after executing the preceding Python code.
Platforms integrate the HDL generation tools to immediately synthesise the generated Verilog and generate a bitstream file.
For simulation, you need some kind of multithreading because the design is running fully in parallel. In python, generators can be used for exactly that: the generator function runs until a yield is encountered, then it waits until a next() call on the generator. Generators are stacked with “yield from”, so the test framework of a module can propagate to its components. So a simulation takes a bunch of generators that toggle the signals in parts of the design. To make simulation deterministic, the convention is that reads of signals happen before the clock tick, and writes happen after the clock tick – this is the same convention as in Verilog when using non-blocking assignments <=.
MiSoC is a collection of Migen classes that make it easier to construct an SoC: wishbone bus interconnect, CSR for memory-mapped IO, streaming interfaces. It also includes a lot fo building blocks, including LM32 processor, DDR3 interfaces, UARTs, … It also includes a bootloader for the CPU so you can run bare metal software on it. It also has a lot of templates so that you can easily design a CPU and peripherals and you just add some custom FPGA fabric to it.
Migen/MiSoC are distributed as regular python packages (setuptools). You just have to add the cross-compiler. You can run it from the command line (with python -m) to instantiate one of the template platforms.
For the ARTIQ project, they have added timing annotations to have exact nanosecond delays in the desing.