* init() now also clear and resets more state including the interpolators.
If not done, this PLL unlocks/locks may lead to random interpolator state
on boot to which the CICs react badly.
* Use and expose `t_frame`
* Clarify implementation state of `read()`
Otherwise, the exception message might be allocated on a stack, and will
become a dangling pointer when the exception is raised.
This will break some code that constructs exceptions with a function by
passing the message as a parameter because we cannot know if the parameter
is a constant. A way to mitigate this would be to defer this check to
LLVM IR codegen stage, and do inlining first for those exception
allocation functions, but I am not sure if we will guarantee inlining
for certain functions, and whether this is really needed.
Note that because we changed exception representation from using string
names as exception identifier into using integer IDs, we need to
initialize the embedding map in order to allocate the integer IDs. Also,
we can no longer print the exception names and messages from the kernel,
we will need the host to map exception IDs to names, and may need the
host to map string IDs to actual strings (messages can be static strings
in the firmware, or strings stored in the host only).
We now check for exception IDs for lit tests, which are fixed because we
preallocated all builtin exceptions.
Ported from:
M-Labs/artiq-zynq#162
This includes new API for exception handling, some refactoring to avoid
code duplication for exception structures, and modified protocols to
send nested exceptions and avoid string allocation.