I’ve managed to get a lot done this week, so far. As I mentioned last time, I finished implementing Verilog-A buses. I thought that would be the last feature needed before launching, but I was wrong. Buses by themselves aren’t terribly useful. The real power comes from looping over them. So I had to implement for loops! Also, I discovered that I introduced a new bug: by implementing buses, I broke arrays. The language itself is ambiguous: buses and arrays look exactly the same. Fortunately, the parser maintains a symbol table, so you can determine what something is by looking it up in the symbol table.
For loops ended up being pretty easy. The French guy implemented everything for them, except for the part where you use them, which is strange. I had to make a few tweaks, but they were trivial things like removing an extra semicolon. Of course, once I created tests that looped over buses, I discovered a new problem…
There are filter functions (ie: functions that operate on signals, rather than normal values) that have to maintain state. Things like extrapolating between piece-wise linear inputs, or integrals with respect to time. The state needs to be stored somewhere, and you need to hold onto a reference to the state. I was previously using the location of the function call within the source file to distinguish between instances of the functions’ state variables. This worked pretty well until I started looping over the same line with different input signals. As I was walking back to the office from Tim Hortons, I realized that these functions will always be used in contributions statements, and each instance will contribute to a different source. (Gah, I really hope this is a sound assumption!) So I can put the names of the source nodes in the name of the state pointer (in addition to the file location), and index into a 2D array with the nodes’ bus indexes.
Now, I’ve got to make sure that variables work correctly for indexing into buses and arrays. The French guy set up the parser to only accept integers from the lexer. We need to allow arbitrary expressions that evaluate to integers. Fixing the parser was easy enough. Fixing the ADMS code seemed like it should be easy, but I managed to break something. Also, the way that the simulator is set up, I need to know how many “pins” my module has before I’ve had a chance to initialize everything. So that has to be determine at compile-time, rather than run-time. This isn’t a big deal normally, but if you want to use a parameter to change the number of pins for different instances (for example, making n-bit ADCs, where you specify n when you instantiate them), you can’t. Blah. I’m sure I can hack around that, but it’s a low priority for now.
I really need to write more tests for all of this. For the most part, I’ve been testing just enough to ensure that basic ideas work. I’m not terribly happy with the way I’m testing either. Basically, I create a module, run it through the simulator, and then diff the output to my “known good” version. It’s useful for catching regressions, but creating tests and ensuring their output is correct can be very time consuming. It’s almost impossible to determine what the correct line-by-line output is when several language features are interacting…
It doesn’t help that there’s no real reference implementation either. I’ve asked a guy who is on the committee for specifying Verilog-AMS (the superset of Verilog-A) about conformance tests, but he hasn’t gotten around to making them yet. The spec is 4 years old… The previous version is 16 years old! The guy said that he would provide reference output from HSpice and Spectre, which are commerical simulators. It just seems strange that a committee would gather to define a language, but not provide a means for validating implementations. How do we know that HSpice and Spectre got it right?
My version 1 won’t be fully-functional. I’ve been targeting a specific feature set as a the minimum viable product. I don’t even know if this the the most-used subset of the language, but I do know there is at least one potential customer out there that wants this and is willing to pay for it. I expect that I’ll be taking lots of feature requests to finish off whatever isn’t supported yet, and a couple orders of magnitude more bug reports.