Rudi wrote:
Curious: What is the cycle time of the generated code versus native verilog code ?
hi rudi, nice to see you around, i haven't forgotten you :)
it's exactly the same, as it's clk-based.
the layout however with nmigen is... well... it's auto-generated in nmigen via yosys, where migen has its own built-in back-end, and goes to some lengths to generate verilog that looks reasonably similar to the migen it came from: that's gone in nmigen.
so, in nmigen, each signal that is assigned is separated out into its own auto-generated code-section (migen keeps them all together). resetting is auto-generated and need not be added manually. declaring a signal "resetless" may be done if it is definitely known that it requires no reset; the value of the reset may be over-ridden at declaration time: x = Signal(32, reset=0xf00baa)
in nmigen, all tests, subexpressions and consequently most assignments are done with combinatorial auto-generated wires / registers (of the correct / required / calculated / auto-calculated width), with the original python line number and file name inserted as a comment next to the expression assignment "$483 = x[1:0] // foo.py:135"
in nmigen, all if elif elif elif statements are translated to casez statements comprising a concatenated sequence of tests (derived from the if part of every single if-elif-elif-elif statement), followed by case 0b1zzzzzz case 0bz1zzzzzz case 0bzz1zzzzz and so on.
three quirks which are down to python:
* n/migen works through operator overloading of python syntax. assignment of python variables does *not* have an operator over-ride, so, annoyingly, an "eq" function had to be provided. "m.d.sync += x.eq(y)" instead of "x = y", because "x = y" would make the *PYTHON* variable x equal to y.
* operator-overloading of the "not", "and" and "or" operators unfortunately returns a boolean rather than an object. however the "&" and "|" bit-wise operators, when overloaded, *do* actually return the objects that are returned from the overload-function. consequently, you *have* to do tests as "m.If((modulus[0:31] == 0x0) & (exponent == -127))" of course including the brackets because & and | operators take higher precedence.
* python slices go from *LSB* on the left to *MSB PLUS ONE* on the right, where verilog goes from MSB (inclusive) *down* to LSB (inclusive). this so that you can do consecutive slices without needing to subtract one: "x = x[y:] + x[:y]" is a barrel-shifter for example. note the lack of use of "y-1".
so... it's... quirky. however, the prevalence and huge adoption of python, the advantages of OO, the fact that to generate online documentation i can use a single command from a 20-year-old tried-and-tested program named "epydoc" (or any of its maaaany Not-Invented-Here quotes replacements quotes), these for me *far* outweigh the quirks and inconveniences.
on a separate note: multiply was added yesterday, along with the original unit test process that jon dawson developed (which hilariously was as python programs). i cut out the use of a c++ program and replaced it with sfpy (berkeley softfloat 3 python bindings).
so, that's *all* of add, add64, div, div64, mul and mul64, all done, all converted to nmigen, and all unit tests passing.
i've run up to 250,000 add and add64 random-input unit tests.
the reason for using sfpy is to avoid having to call out to a subprocess (nmigen contains its own simulator), and also, sfpy supports setting of different overflow modes, which is one of the next things to add.
also, now we can add FP16, which is supported by sfpy, *without* dependence on a particular feature of a c / c++ compiler (not all c / c++ compilers *have* an FP16 type). adding FP16 is literally a matter of adding a few lines in the base class to tell it what to do when FPAdd(16) is instantiated.
l.