Let me say a little about choice of compilers for Icarus Verilog development. Then I'll bring you up to date on latch synthesis.

In my last blog item about Icarus Verilog, I wrote:

...
CC -DHAVE_CONFIG_H -I. -I. -g -xMD -c net_scope.cc -o net_scope.o
"net_scope.cc", line 228: Error: __rwstd::__rb_tree, __rwstd::__select1st, perm_string>, std::less, std::allocator>>::iterator::iterator(__rwstd::__rb_tree, __rwstd::__select1st, perm_string>, std::less, std::allocator>>::__rb_tree_node*) is not accessible from NetScope::find_parameter(perm_string).
1 Error(s) detected.
make: *** [net_scope.o] Error 1
jesus%

See the iverilog-devel email archive for the presentation of the above failure and the discussion that ensued.


Since then, Cary R. has taken this further. See OpenSolaris support using Sun compiler. He later wrote, "This is completed minus some compiler flag tweaking/checking that I need to do at some time. Both the latest development and V0.9 from git compile and pass the test suite as expected using OpenSolaris. It would be nice if [someone] could verify that everything works as expected using normal Solaris and a real SPARC CPU."

The problem is that "V0.8 is [still] best for synthesis." That keeps me on V0.8 (and on GCC).

Nevertheless, I stated previously that "I have Solaris/SPARC machines available ... An acceptable alternative would be to create an account for Steve [Williams]; VPN is already in place ...". My offer still stands.

As for latch synthesis, I wrote last time that, "next, I would focus my attention on code generation. Does the FNF Icarus code generator fail to recognize NetLatch (where it recognizes NetFF)?".

I had written a similar Verilog module, called "ff", containing a flip flop rather than a latch and wanted to make some comparisons. Some temporary debug code needed to be encapsulated in a function suitable for both OpenSPARCT1 and ff. This would avoid the recompilations of Icarus Verilog that I had already performed a few times just to switch between the two hardware designs.

Design::emit
/*
* The emit process uses a target_t driver to send the completed
* design to a file. It is up to the driver object to follow along in
* the iteration through the design, generating output as it can.
*/


In this case, the "driver object" is the FNF Icarus code generator. Well, technically the driver object is a DLL target type.

/*
* The DLL target type loads a named object file to handle the process
* of scanning the netlist. When it is time to start the design, I
* locate and link in the desired DLL, then start calling methods. The
* DLL will call me back to get information out of the netlist in
* particular.
*/


The "named object file" is the FNF Icarus code generator (i.e. the "DLL", if you prefer).

build_hierarchy is initially called like this:
build_hierarchy(ivl_design_root(design), 0);
then recursively.

I wanted to prove that, at the first call to build_hierarchy, ivl_design_root(design) can be used to find the ck signal, which can be followed through a NOT gate to a flip flop in ff. Also prove that ivl_design_root(design) can be used to find the ck signal, which can be followed through a NOT gate to a latch in OpenSPARCT1.

I was able to find an IVL_LPM_FF this way in ff. Similarly, I proceeded to search for a latch in OpenSPARCT1. In this more complex design, it was best to get some programmatic assistance (along with use of the gdb tool). To find the ck signal, I wrote some code to perform a pre-order traversal of the ivl_design_root(design) tree. In a pre-order traversal, I examine the value in a node and then recursively traverse each of the subtrees.

There were 195 objects connected to the ck nexus. To find a NOT gate of interest connected to that nexus, I would loop through an array programmatically, printing information about connected objects that fall within the bw_u1_scanlg_2x scope.

I programmatically found the nexus at the output of the NOT gate (the name of the nexus at the NOT gate output is _s6), placed a breakpoint and explored with the debugger from there. I quickly proved that, in OpenSPARCT1, ivl_design_root(design) can be used to find the ck signal. This signal can be followed through a NOT gate in bw_u1_scanlg_2x, but there was no latch to be found at that nexus.

The flip flop does not have the same problem (i.e. successfully found a flip flop at that nexus).

My method for writing this blog item is to read my notes and try to share the thought process with you (while omitting a lot of details). At this point, I'm reading in my 2010-03-29 notes, where I'm about to conclude that I need look earlier in the processing of OpenSPARCT1. But consider also what I wrote at the end of my last blog item on OpenSPARC on 2010-03-12:

...
after CODE GENERATION -t dll
Type name of object connected to ck in latch scope is 8NetLogic
Name of nexus on output side of NOT gate is _s6
Type name of object connected to _s6 is 8NetLatch
...


If the NetLatch is connected to _s6 after code generation, then how can it not be connected to _s6 at the first call to build_hierarchy? I seem to be going in circles! This may warrant further investigation (after I finish writing this blog item).

Back to my March thinking, I need look earlier in the processing of OpenSPARCT1. Granted that the following backtrace was taken while probing the ff design, but here it is for reference anyway:

(gdb) backtrace
#0 build_hierarchy (scope=0x181e88, cd=0x0) at fnf.c:259
#1 0xff162b7c in target_design (des=0x181e88) at fnf.c:570
#2 0x000db7f0 in dll_target::end_design (this=0x164db0) at t-dll.cc:631
#3 0x0007424c in Design::emit (this=0x181600, tgt=0x164db0) at emit.cc:411
#4 0x00074314 in emit (des=0x181600, type=0x1669d0 "dll") at emit.cc:513
#5 0x00047e30 in main (argc=6, argv=0xffbff764) at main.cc:766
(gdb)


Looking inside function dll_target::end_design, before the call to target_design, the latch could not be found from the NOT output nexus in OpenSPARCT1 (but the flip flop could be found in the other design at this point in the program).

Inside function Design::emit, before the call to dll_target::end_design, the story was the same.

inside function emit before the call to Design::emit
Assertion failed: des->nroots_, file t-dll-api.cc, line 56

Program received signal SIGABRT, Aborted.
0xff0caa58 in _lwp_kill () from /lib/libc.so.1

This happens with both designs. It would seem that it is simply too early to call function ivl_design_root.

I decided to explore function Design::emit more thoroughly. There were various assertion errors each time I tried to probe too early. Immediately after emitting nodes wasn't too early. At this point, the flip flop design representation is good, but the OpenSPARCT1 design representation is not. I decided to take a closer look at emitting nodes.

For the flip flop design, what are all of the NetNode objects visited? I was looking for something identifiable as a NetFF. The theory is that, for OpenSPARCT1, either the NetLatch will not be visited, or the right thing will not be done on the visit. I used operator typeid.

CODE GENERATION -t dll
current node type:8NetLogic
current node type:8NetLogic
current node type:5NetFF
current node type:8NetLogic
current node type:8NetLogic

And now OpenSPARCT1:

...
current node type:8NetLatch


The theory is that, for OpenSPARCT1, the right thing will not be done on the visit.

CODE GENERATION -t dll
current node type:8NetLogic
current node type:8NetLogic
current node type:5NetFF

Breakpoint 1, Design::emit (this=0x193290, tgt=0x176a44) at emit.cc:422
422 cout << "Encountered NetFF or NetLatch while emitting nodes." << endl; // DELETE ME
(gdb) next
Encountered NetFF or NetLatch while emitting nodes.
424 rc = rc && cur->emit_node(tgt);
(gdb) step
NetFF::emit_node (this=0x193b98, tgt=0x176a44) at emit.cc:111
111 tgt->lpm_ff(this);
(gdb) step
dll_target::lpm_ff (this=0x176a44, net=0x193b98) at t-dll.cc:1625
1625 ivl_lpm_t obj = new struct ivl_lpm_s;
(gdb)


Comparing the implementation of dll_target::lpm_ff with that of dll_target::lpm_latch, the former is much longer. That must be where I left off in my development. It is very possible that this is the source of my troubles.

With the assistance of gdb, I came to understand that it is dll_target::lpm_ff that connects a flip flop to the NOT gate output nexus.

Functions dll_target::lpm_ff and dll_target::lpm_latch fill in an ivl_lpm_s structure.

// Set the gate signal to point to the nexus,
// and the nexus to point back to this device.
const Nexus *const nexPtr = latchPtr->pin_Gate().nexus();


The code doesn't match the comment. First, the code assumes the gate signal points to the nexus. Second (and this is the problem I've been experiencing), there is no code setting the nexus to point back to this device. In fact, nexPtr is an unused variable. Again, it simply appears that this is where I left off.

...
inside function dll_target::lpm_latch, at beginning
Type name of this scope is bw_u1_scanlg_2x
There are 111 pointers held by the ck nexus.
Assertion failed: foundNotGate, file preOrderTraversal.cc, line 33

Program received signal SIGABRT, Aborted.
0xff0caa58 in _lwp_kill () from /lib/libc.so.1
(gdb)

Are we emitting the latch before the NOT gate? I decided not to attempt preOrderTraversal inside function dll_target::lpm_latch, at its beginning.

Next, I wanted to examine nexPtr using gdb.

At this point, it seems that I did absolutely nothing on this project for about three months. I resumed 2010-07-09.

But it wasn't until 2010-07-14 that I was making forward progress:

(gdb) print nexPtr
$1 = (const Nexus * const) 0x2da050
(gdb)


cout << "Type name of something connected to the gate nexus is "
<< typeid( *somethingPtr ).name() << endl;


inside function dll_target::lpm_latch, at beginning
Type name of something connected to the gate nexus is 8NetLatch
Type name of something connected to the gate nexus is 8NetLogic
Type name of something connected to the gate nexus is 6NetNet


And a little bit more validation of my sanity:

inside function dll_target::lpm_latch, at beginning
Type name of something connected to the gate nexus is 8NetLatch
Type name of something connected to the gate nexus is 8NetLogic
type_ is NOT
Type name of something connected to the gate nexus is 6NetNet


This all looked good. All I'm doing here is examining the nexus pointed to by nexPtr.

const Nexus *const nexPtr = latchPtr->pin_Gate().nexus();


This unused variable is declared (and assigned) essentially at the end of function dll_target::lpm_latch. The only other thing of consequence that I do in this function stub is to call function preOrderTraversal. The result of that is:

(gdb) next
Type name of this scope is bw_u1_scanlg_2x
There are 111 pointers held by the ck nexus.
Assertion failed: foundNotGate, file preOrderTraversal.cc, line 33

Program received signal SIGABRT, Aborted.
0xff0caa58 in _lwp_kill () from /lib/libc.so.1
(gdb)


In OpenSPARCT1, we never found the NOT device starting from the ck nexus, but it was found starting from the gate nexus of the latch device. I don't expect any problems with NOT devices, just latches.

But in ff, I had previously concluded that dll_target::lpm_ff added the flip flop device so that preOrderTraversal could find it (at the output of the NOT device that was obviously found).

I investigated the assertion failure in preOrderTraversal while processing OpenSPARCT1 and concluded that the NOT device found starting from the gate nexus of the latch device in dll_target::lpm_latch, wasn't one of the 111 pointers held by the ck nexus when dll_target::lpm_latch finished.

Now what?