On 2010-08-09 I wrote, "I seem to be going in circles!"

It's always interesting to read notes documenting a thought process before a problem is solved. Phil Connors eventually broke the time loop in Groundhog Day. I stopped going in circles too.



At the end of my 2010-08-09 blog item I "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."

On 2010-09-23 I wrote in my notes, "This is plausible. See 2010-04-02 notes: 'There are 195 pointers held by the ck nexus.' That was inside function Design::emit ... immediately after emitting nodes. That means that, when dll_target::lpm_latch is done, emitting nodes is not done. There are 84 more pointers to be held by the ck nexus. It is reasonable to assume that the NOT device is one of them." I decided not to worry about the NOT device not yet being held by the ck nexus. Instead, I would focus on what should be happening in dll_target::lpm_latch.

What should be happening in dll_target::lpm_latch and how does this relate to the Icarus FNF code generator (packaged with Confluence)? Keep an eye on the big picture. What led me to the conclusion that latch synthesis is still broken?

I had written in my 2009-09-25 blog item, "... _s6 does not appear to be connected to the latch gate [in the FNF representation]. I have reason to suspect that the FNF is wrong ...".

Here's the Verilog (from OpenSPARC T1), followed by the bad FNF:

/////////////// Scan data lock up latch ///////////////

module bw_u1_scanlg_2x (so, sd, ck, se);
output so;
input sd, ck, se;

reg so_l;

assign so = ~so_l;
always @ ( ck or sd or se )
if (~ck) so_l <= ~(sd & se) ;

endmodule

(scope "bw_u1_scanlg_2x" "so_lockup" (
(name 43009 "ck" 1 2438)
(name 43010 "sd" 1 42881)
(name 43011 "se" 1 18650)
(name 43012 "so" 1 29150)
(name 43014 "so_l" 1 43013)
(name 43016 "_s6" 1 43015)
(name 43017 "_s9" 1 2437)
(name 43019 "_s11" 1 43018)
(not 29150 1 43013)
(not 43015 1 2438)
(not 43018 1 2437)
(latch 43020 1 43022 43021)
(select 43023 1 0 43020)
))


For reference, here is the meaning of the most relevant FNF line:

(latch     Q LPM_Width Gate Data)


Note the disconnect between the latch's gate pin and the NOT device that is to feed it.

On 2010-09-28, I had an epiphany. It came about as follows.

From function build_hierarchy (in the Icarus Verilog FNF generator):
fprintf( output,
" (latch %i %i %i %i)\n",
id,
width,
id_of_nexus( gate, 0U ),
id1
);


I wanted to know where gate came from and was led to an ivl_lpm_s structure.
return netPtr->u_.latch.gatePtr;


What sets gatePtr? Functions dll_target::lpm_ff and dll_target::lpm_latch fill in an ivl_lpm_s structure.

dll_target::lpm_latch should have set gatePtr, but as of 2010-09-28 it did no such thing. That should have happened near here:

// 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();


I had been right on top of this problem for months. A couple of hours of clear thinking led me right to it!

How does dll_target::lpm_ff set clk?

assert(nex->t_cookie());
obj->u_.ff.clk = (ivl_nexus_t) nex->t_cookie();

* The t_cookie() is a void* that targets can use to store information
* in a Nexus. ivl guarantees that the t_cookie will be 0 when the
* target is invoked.


That means that after the target was invoked and before now, someone stored this information in the Nexus. Who? When?

Examine the gate Nexus after NetLatch construction.

Breakpoint 1, NetAssignBase::synth_async (this=0xcfdb60, des=0x19d708, 
scope=0x44f808, sync_flag=false, nex_ff=0x0, nex_map=0xd06b88,
nex_out=0xcfdf38, accum_in=0x2afb80, latch_inferred=true, gsig=0xcfde88)
at synth2.cc:220
220 NetLatch *const latchPtr =
new NetLatch( scope,
cur->sig()->name(),
static_cast< unsigned >( cur->sig()->msb() - cur->sig()->lsb() ) + 1U
);
(gdb) next
221 latchPtr->set_line( *this );
(gdb) print latchPtr->pin(0).nexus()->t_cookie()
$5 = (void *) 0x0
(gdb)


ivl guarantees that the t_cookie will be 0 when the target is invoked. We are still long before the target is invoked. How would I set a watchpoint on this?

A watchpoint is a special breakpoint that stops your program when the value of an expression changes. But latchPtr is only known in this try block.

Ordinarily a watchpoint respects the scope of variables in expr. The "-location" argument tells gdb to instead watch the memory referred to by expr. In this case, gdb will evaluate expr, take the address of the result, and watch the memory at that address. The type of the result is used to determine the size of the watched memory. If the expression's result does not have an address, then gdb will print an error.

(gdb) watch -location latchPtr->pin(0).nexus()->t_cookie()
No symbol "location" in current context.
(gdb)


*** Changes since GDB 7.2

* The "watch" command now accepts an optional "-location" argument.
When used, this causes GDB to watch the memory referred to by the
expression. Such a watchpoint is never deleted due to it going out
of scope.

2010-09-02: GDB 7.2 Released!

That wasn't going to be new enough. I needed to pick up a change since GDB 7.2.

Sources to the current development version are also available using FTP, CVS and WWW.

That was 2010-10-05. There were some issues building and installing GDB. I'll spare you the details. Then on 2010-10-15:

jesus% gdb -version
GNU gdb (GDB) 7.2.50.20101005-cvs
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
jesus%


(gdb) watch -location latchPtr->pin_Gate().nexus()->t_cookie()
Attempt to take address of value not located in memory.
(gdb)


If the expression's result does not have an address, then gdb will print an error.

(gdb) watch -location latchPtr->pin_Gate().nexus_->t_cookie_
Hardware watchpoint 6: -location: latchPtr->pin_Gate().nexus_->t_cookie_
(gdb)


Failed to stop.
This indicates that, when handling a latch, Icarus Verilog never changed t_cookie_. What about a flip flop?

That was 2010-10-15. Then I went into a deep dive and didn't really emerge until 2010-11-05. (Keep in mind that I was watching a lot of baseball in October. And there was the trip to Sunnyvale CA to interview with MIPS Technologies.)

What about a flip flop? Set breakpoints in synth2.cc everywhere "new NetFF" appears and see which one I hit.

Breakpoint 4, NetProcTop::synth_sync (this=0x181a08, des=0x19d708)
at synth2.cc:2542
2542 nex_set.count());
(gdb) next
2543 des->add_node(ff);
(gdb) watch -location ff->pin_Clock().nexus_->t_cookie_
Hardware watchpoint 5: -location: ff->pin_Clock().nexus_->t_cookie_
(gdb) continue
Continuing.
...
CODE GENERATION -t dll
Hardware watchpoint 5: -location: ff->pin_Clock().nexus_->t_cookie_

Old value = (void *) 0x0
New value = (void *) 0x736f5f6c
0xff3a0900 in memcpy () from /platform/SUNW,Sun-Fire-V210/lib/libc_psr.so.1
(gdb) backtrace
#0 0xff3a0900 in memcpy ()
from /platform/SUNW,Sun-Fire-V210/lib/libc_psr.so.1
#1 0x00110af8 in
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::
_S_construct<char*>
(__beg=0x19e654 "so_l", __end=0x19e658 "", __a=...)
at
/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/
../../../../include/c++/3.4.6/bits/char_traits.h
:270
#2 0x00110e24 in
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::
basic_string<char*>
(this=0xffbfefb8, __beg=0x19e654 "so_l", __end=0x19e658 "", __a=...)
at
/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/
../../../../include/c++/3.4.6/bits/basic_string.h
:1386
#3 0x000a1f44 in Nexus::name (this=0x183100)
at
/usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/
../../../../include/c++/3.4.6/ext/new_allocator.h
:62
#4 0x000f29a0 in dll_target::signal (this=0x180ebc, net=0x19da78)
at t-dll.cc:2455

#5 0x00079548 in NetScope::emit_scope (this=0x19d750, tgt=0x180ebc)
at emit.cc:338
#6 0x00079914 in Design::emit (this=0x19d708, tgt=0x180ebc) at emit.cc:404
#7 0x0007a328 in emit (des=0x19d708, type=0x182ad8 "dll") at emit.cc:567
#8 0x0004cca8 in main (argc=6, argv=0xffbff764) at main.cc:766
(gdb)


Here, we "enumerate the scopes" (before we "emit nodes").

Consider that t_cookie_ could have been used multiple times. Which time is my current concern?

assert(nex->t_cookie());
obj->u_.ff.clk = (ivl_nexus_t) nex->t_cookie();


Note that this one is cast to ivl_nexus_t. Is that what was stored in the cookie by function dll_target::signal?

Yes.

(MIPS Technologies decided not to make an offer and the San Francisco Giants won the World Series.)

 * ivl_nexus_t
* Structural links within an elaborated design are connected
* together at each bit. The connection point is a nexus, so pins
* of devices refer to an ivl_nexus_t. Furthermore, from a nexus
* there are backward references to all the device pins that point
* to it.

typedef struct ivl_nexus_s *ivl_nexus_t;


Does
obj->u_.ff.clk = (ivl_nexus_t) nex->t_cookie();

mean "set clk, which is a ivl_nexus_t, to the ivl_nexus_t (in the cookie) that already points back to the flip flop device"?

Examine the ivl_nexus_t in the cookie.

(gdb) finish
...
(gdb) finish
...
(gdb) finish
...
(gdb) finish
...
0x000f29a0 in dll_target::signal (this=0x180ebc, net=0x19da78)
at t-dll.cc:2455
2455 tmp->name_ = strings_.add(nex->name());
Value returned is $2 = 0x182ea8 "so_l"
(gdb) next
2456 nex->t_cookie(tmp);
(gdb) print tmp
$3 = (ivl_nexus_t) 0x1825b8
(gdb) print *tmp
$4 = {nptr_ = 1, ptrs_ = 0x182690, name_ = 0x19f9ec "so_l",
private_data = 0x0}
(gdb) print tmp->ptrs_[ 0 ]
$5 = {pin_ = 0, type_ = 0, drive0 = 0, drive1 = 0, l = {sig = 0x19e610,
log = 0x19e610, con = 0x19e610, lpm = 0x19e610}}
(gdb)


I had seen that pattern before. The only thing connected to this ivl_nexus_t at this point is a "sig". That's not what we're looking for. So the answer to the previous question is no. The ivl_nexus_t in the cookie doesn't already point back to the flip flop device (i.e. not at the time the ivl_nexus_t is stored in the cookie). That might be too early.

(gdb) watch -location tmp->nptr_
Hardware watchpoint 6: -location: tmp->nptr_
(gdb) continue
Continuing.
Hardware watchpoint 5: -location: ff->pin_Clock().nexus_->t_cookie_

Old value = (void *) 0x736f5f6c
New value = (void *) 0x636b5f6c
0xff3a0900 in memcpy () from /platform/SUNW,Sun-Fire-V210/lib/libc_psr.so.1
(gdb)


Expecting the ivl_nexus_t in the cookie to be modified (i.e. to point back to the flip flop device), a new ivl_nexus_t object is instead being stored in the cookie.

(gdb) print *tmp
$9 = {nptr_ = 1, ptrs_ = 0x1826c0, name_ = 0x19f9f1 "ck_l",
private_data = 0x0}
(gdb)


This is a different nexus! Come to think of it, why was so_l being stored (previously) in the cookie of the clock nexus?

What am I watching?

Hardware watchpoint 5: -location: ff->pin_Clock().nexus_->t_cookie_


ck_l is right. The only thing I can think of to explain so_l is reuse of the same memory location, a problem inherent in
watch -location


(gdb) print tmp->ptrs_[ 0 ]
$10 = {pin_ = 0, type_ = 0, drive0 = 0, drive1 = 0, l = {sig = 0x19e648,
log = 0x19e648, con = 0x19e648, lpm = 0x19e648}}
(gdb)


But the ivl_nexus_t in the cookie still doesn't point back to the flip flop device (i.e. not at the time the ivl_nexus_t is stored in the cookie). Again, that might be too early.

A couple of things were bothering me about the block of code in function dll_target::signal where the ivl_nexus_t is stored in the cookie.

      if (obj->width_ == 1) {
const Nexus*nex = net->pin(0).nexus();
if (nex->t_cookie()) {
obj->n.pin_ = (ivl_nexus_t)nex->t_cookie();
nexus_sig_add(obj->n.pin_, obj, 0);

} else {
ivl_nexus_t tmp = nexus_sig_make(obj, 0);
tmp->name_ = strings_.add(nex->name());
nex->t_cookie(tmp);
obj->n.pin_ = tmp;
}

}


First, nex is a local variable (i.e. local to this block). How could it matter that its cookie is modified if nex is meaningless once we leave the block? Second nex is a pointer to a const Nexus. Yet we attempt to modify that object's cookie.

The second concern was easiest to explain.

mutable void* t_cookie_;


For the first concern, rather than spend a little more time thinking, I decided to risk public embarrassment by asking the question on iverilog-devel (I risk further embarrassment by telling you about it). If it makes you feel any better about me, I more often demonstrate the opposite problem. That is, I tend to go too far on my own before asking for help.

But the ivl_nexus_t in the cookie still doesn't point back to the flip flop device ...

(gdb) print static_cast<ivl_nexus_t>(net->pin(0).nexus_->t_cookie_)->nptr_
$17 = 1
(gdb)


GDB now supports the C++ cast operator!

(gdb) watch -location static_cast<ivl_nexus_t>(net->pin(0).nexus_->t_cookie_)->nptr_
Hardware watchpoint 9: -location:
static_cast<ivl_nexus_t>(net->pin(0).nexus_->t_cookie_)->nptr_
(gdb) continue
Continuing.
Hardware watchpoint 5: -location: ff->pin_Clock().nexus_->t_cookie_

Old value = (void *) 0x636b5f6c
New value = (void *) 0x0
0xff3a0884 in memcpy () from /platform/SUNW,Sun-Fire-V210/lib/libc_psr.so.1
(gdb) backtrace
#0 0xff3a0884 in memcpy ()
from /platform/SUNW,Sun-Fire-V210/lib/libc_psr.so.1
#1 0xff0568f4 in realloc () from /lib/libc.so.1
#2 0x000e89c8 in nexus_log_add (nex=0x182660, net=0x19db80, pin=0)
at t-dll.cc:356
#3 0x000eac7c in dll_target::logic (this=0x180ebc, net=0x19dbb8)
at t-dll.cc:865
#4 0x0007868c in NetLogic::emit_node (this=0x19dbb8, tgt=0x180ebc)
at emit.cc:48
#5 0x00079a9c in Design::emit (this=0x19d708, tgt=0x180ebc) at emit.cc:423
#6 0x0007a328 in emit (des=0x19d708, type=0x182ad8 "dll") at emit.cc:567
#7 0x0004cca8 in main (argc=6, argv=0xffbff764) at main.cc:766
(gdb)


The cookie (a ivl_nexus_t) is being cleared before the nptr_ of the object it points to was ever incremented. This happens in function nexus_log_add. The comment there seemed to me to be very relevant:

/*
* Add the pin of the logic object to the nexus ...


As a result of realloc, the cookie (or at least the memory location that was the cookie) no longer points to the ivl_nexus_s that is being grown.

Regarding the relevancy of the comment, __NEXUS_PTR_LOG isn't the same thing as __NEXUS_PTR_LPM, so nexus_lpm_add would be the more relevant function.

It will be convenient to assume (and the assumption may indeed be correct) that the cookie somehow still points to (or the connection will somehow be reestablished to) the ivl_nexus_s that is being grown.

Look at the call stack when we get to function nexus_lpm_add.

(gdb) break nexus_lpm_add
Breakpoint 10 at 0xe8cec: file t-dll.cc, line 387.
(gdb) continue
Continuing.
Hardware watchpoint 9: -location:
static_cast<ivl_nexus_t>(net->pin(0).nexus_->t_cookie_)->nptr_

Old value = 1
New value = 2
nexus_log_add (nex=0x1826a8, net=0x19dd08, pin=0) at t-dll.cc:360
360 nex->ptrs_[top-1].type_= __NEXUS_PTR_LOG;
(gdb) continue
Continuing.
Encountered NetFF or NetLatch while emitting nodes.
inside function dll_target::lpm_ff, at beginning
Type name of this scope is ff
There are 2 pointers held by the ck nexus.
The name of the nexus at the NOT gate output is ck_l

Breakpoint 10, nexus_lpm_add (nex=0x1826a8, net=0x19dd40, pin=0,
drive0=IVL_DR_HiZ, drive1=IVL_DR_HiZ) at t-dll.cc:387
387 unsigned top = nex->nptr_ + 1;
(gdb) backtrace
#0 nexus_lpm_add (nex=0x1826a8, net=0x19dd40, pin=0, drive0=IVL_DR_HiZ,
drive1=IVL_DR_HiZ) at t-dll.cc:387
#1 0x000eeef8 in dll_target::lpm_ff (this=0x180ebc, net=0x19e010)
at t-dll.cc:1656
#2 0x00078958 in NetFF::emit_node (this=0x19e010, tgt=0x180ebc)
at emit.cc:111
#3 0x00079a9c in Design::emit (this=0x19d708, tgt=0x180ebc) at emit.cc:423
#4 0x0007a328 in emit (des=0x19d708, type=0x182ad8 "dll") at emit.cc:567
#5 0x0004cca8 in main (argc=6, argv=0xffbff764) at main.cc:766
(gdb)


... and didn't really emerge until 2010-11-05.

Now it was 2010-11-05 and here comes the moment of clarity: What's the big mystery here? Can't I just do what's done for flip flops?

Let me go back to function dll_target::lpm_latch.

My 2010-07-21 notes imply that
assert( nexPtr->t_cookie() );

passed.

(As I proofread this, I realize that I don't know how the cookie came to hold something. See above where I concluded that, "when handling a latch, Icarus Verilog never changed t_cookie_." For now, it is acceptable to me that I don't know.)

Next, I tried to prove that the cookie held something good.

Breakpoint 1, dll_target::lpm_latch (this=0x180ed4, latchPtr=0xcfe270)
at t-dll.cc:1851
1851 objPtr->u_.latch.gatePtr = static_cast< ivl_nexus_s * >( nexPtr->t_cookie() );
(gdb) print nexPtr->t_cookie()
$1 = (void *) 0xc47f08
(gdb) print typeid( nexPtr->t_cookie() ).name()
No symbol "typeid" in current context.
(gdb) print dynamic_cast< ivl_nexus_s * >( nexPtr->t_cookie() )
Argument to dynamic_cast does not have pointer to class type
(gdb)


The proof failed (i.e. inconclusive). Instead, I assumed that the cookie held something good.

(gdb) print static_cast< ivl_nexus_s * >( nexPtr->t_cookie() )
$2 = (ivl_nexus_s *) 0xc47f08
(gdb) print *static_cast< ivl_nexus_s * >( nexPtr->t_cookie() )
$3 = {nptr_ = 2, ptrs_ = 0x97e9d8, name_ = 0xe4c394 "_s6", private_data = 0x0}
(gdb) print static_cast< ivl_nexus_s * >( nexPtr->t_cookie() )->ptrs_[ 0 ]
$4 = {pin_ = 0, type_ = 0, drive0 = 0, drive1 = 0, l = {sig = 0xc57298,
log = 0xc57298, con = 0xc57298, lpm = 0xc57298}}
(gdb) print static_cast< ivl_nexus_s * >( nexPtr->t_cookie() )->ptrs_[ 1 ]
$5 = {pin_ = 0, type_ = 1, drive0 = 6, drive1 = 6, l = {sig = 0xf04050,
log = 0xf04050, con = 0xf04050, lpm = 0xf04050}}
(gdb)


# define __NEXUS_PTR_SIG 0
# define __NEXUS_PTR_LOG 1


The ivl_nexus_s pointed to by the cookie is not connected to the latch yet. If I had bothered to compare this behavior with that of the flip flop, I'm sure I would have observed the same. I just needed to go a little further:

      assert(nex->t_cookie());
obj->u_.ff.clk = (ivl_nexus_t) nex->t_cookie();
assert(obj->u_.ff.clk); // seems overly cautious

// increments nptr_ (points to ff)
nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);


By 2010-11-06, I had coded the connection of the latch's gate pin to the source circuit and looked at the resulting FNF.

Now, let's compare the FNF for this Verilog module before and after the fix.

before

    (scope "bw_u1_scanlg_2x" "so_lockup" (
(name 43009 "ck" 1 2438)
(name 43010 "sd" 1 42881)
(name 43011 "se" 1 18650)
(name 43012 "so" 1 29150)
(name 43014 "so_l" 1 43013)
(name 43016 "_s6" 1 43015)
(name 43017 "_s9" 1 2437)
(name 43019 "_s11" 1 43018)
(not 29150 1 43013)
(not 43015 1 2438)
(not 43018 1 2437)
(latch 43020 1 43022 43021)
(select 43023 1 0 43020)
))


after

    (scope "bw_u1_scanlg_2x" "so_lockup" (
(name 43009 "ck" 1 2438)
(name 43010 "sd" 1 42881)
(name 43011 "se" 1 18650)
(name 43012 "so" 1 29150)
(name 43014 "so_l" 1 43013)
(name 43016 "_s6" 1 43015)
(name 43017 "_s9" 1 2437)
(name 43019 "_s11" 1 43018)
(not 29150 1 43013)
(not 43015 1 2438)
(not 43018 1 2437)
(latch 43020 1 43015 43021)
(select 43022 1 0 43020)
))


Gate now seems to be connected properly. Although more work is required for Q and Data, it has been a long time, so get a patch to Stephen Williams sooner rather than later.

Of course, there were some steps involved in doing that. I'll discuss only the most interesting ones.

Before submitting a patch, it is a good idea to check for regression using the Icarus Verilog Test Suite (ivtest). My ivtest Git repository had disappeared during Solaris Installation Hell a year earlier and this was the first time I needed it again. So I restored it from tape.

jesus% diff regression_report-v0.8.txt regression_report.txt
436a437
> pr3078759: Passed - CO.
593a595
> pr3077640: Passed - expected fail.
1542a1545,1564
> bits: ==> Failed - running iverilog.
> ibyte_test: ==> Failed - running iverilog.
> iint_test: ==> Failed - running iverilog.
> ilongint_test: ==> Failed - running iverilog.
> ishortint_test: ==> Failed - running iverilog.
> iuint1: ==> Failed - running iverilog.
> sbyte_test: ==> Failed - running iverilog.
> simple_byte: ==> Failed - running iverilog.
> simple_int: ==> Failed - running iverilog.
> simple_longint: ==> Failed - running iverilog.
> simple_shortint: ==> Failed - running iverilog.
> sint_test: ==> Failed - running iverilog.
> slongint_test: ==> Failed - running iverilog.
> sshortint_test: ==> Failed - running iverilog.
> ubyte_test: ==> Failed - running iverilog.
> uint_test: ==> Failed - running iverilog.
> ulongint_test: ==> Failed - running iverilog.
> ushortint_test: ==> Failed - running iverilog.
> signed_equality: ==> Failed - output does not match gold file.
> pr3098439: ==> Failed - output does not match gold file.
1545c1567
< Total=1540, Passed=995, Failed=3, Not Implemented=425, Expected Fail=117
---
> Total=1562, Passed=996, Failed=23, Not Implemented=425, Expected Fail=118
jesus%


The expected results themselves were suspect. Certainly I had not broken all of that.

git checkout origin/v0_8-branch

doesn't match expected results either.

I reported this to iverilog-devel on 2010-11-10. Within a very reasonable amount of time Cary R. responded with, "I have pushed the updates needed to get V0.8 back in sync."

jesus% diff regression_report-v0.8.txt regression_report.txt
jesus%


While I was looking at the test suite, I came across the following.

basiclatch: ==> Failed - output does not match gold file.


I wonder what that is. If it's a simulation test, I'm less interested. But I'll want to take a look at it when I create a synthesis test.

It is also highly recommended that you create regression tests of your own to test the results of your own work. These tests can go into the regression test suite so that others who edit the compiler can be sure they are not breaking your code in the process.

basiclatch	normal,-S  ivltests # First Synth test


basiclatch: iverilog-0.8 -o vsim -S ./ivltests/basiclatch.v > log/basiclatch.log 2>&1
==> Failed - output does not match gold file.


I had encountered basiclatch before. It appears in my 2007-06-22 notes.

./ivltests/basiclatch.v:39: warning: Process not synthesized.
XXXX LPM not supported: tbench.u_reg.q
FAILED - initial value not 0


jesus% find ../icarus_verilog | xargs grep 'LPM not supported'
../icarus_verilog/tgt-vvp/vvp_scope.c:
fprintf(stderr, "XXXX LPM not supported: %s.%s\n",
jesus%


Note that
XXXX LPM not supported: tbench.u_reg.q

comes from
icarus_verilog/tgt-vvp/


That makes it a simulation error, so I don't care. What do I care about? For example, do I care about
==> Failed - output does not match gold file.

?

I'll come back to that, but I will say this. My goal is to find/create a latch regression test that passes on V0.8, but fails on all subsequent versions.

Next, I had some trouble with git-format-patch. The difficulty for me was in understanding/controlling which commits will be output. The key to making this clear was to view the commit graph. The gitk command can do that. Previously, I had tried to get gitk working, but gave up. Now, I revisited and solved the problems that had been preventing its launch.

jesus% git format-patch -o patches ^70007b ^origin/v0_8-branch HEAD
patches/0001-latch-synthesis-fix-Connect-gate-pin-in-netlist.patch
patches/0002-Add-h-option-to-usage-output.patch
jesus%


That was 2010-11-19 and Steve has since applied the patches to v0_8-branch.

More work is required for the latch's Q and Data pins. I'll deal with that first, then the latch synthesis regression test.

Finally, I'd like to summarize the key discoveries as I broke out of the circle.

On 2010-08-09 I had asked, "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, which is much earlier in code generation?" The answer lies in how I arrived at the two conclusions that form the question.

The NetLatch is still connected to _s6 after code generation. It actually gets connected shortly after NetLatch instantiation, while running the synth2 functor, specifically in function NetAssignBase::synth_async. It is more important to recognize that this is an observation about the Design object.

 * This class contains an entire design. It includes processes and a
* netlist, and can be passed around from function to function.
*/
class Design {


Sometime after running the synth2 functor, early in code generation while the Design object is emitting nodes (before the first call to build_hierarchy), dll_target::lpm_latch gets called (with a NetLatch object passed to it), which instantiates and initializes an ivl_lpm_s structure. This turns out to be the key to getting the latch connected to _s6 in the ivl_design_t object (see below).

How could the latch not be connected to _s6 at the first call to build_hierarchy? That was an observation about the ivl_design_t object, a distinct downstream model of the design.

 * ivl_design_t
* This object represents the entire elaborated design. Various
* global properties and methods are available from this.