On Cosmic Horizon's Verilog-to-JHDL translation project (using OpenSPARC T1 as an example of Verilog), we have achieved correct latch synthesis on Icarus Verilog's v0_8-branch. Get this Verilog compiler via anonymous Git cloning.

When Icarus Verilog moved from version 0.8 to version 0.9, the developers broke synthesis. Improvements to synthesis continue to be made on v0_8-branch. Still, there has been no commitment from Steve Williams to bring synthesis forward into the current release. That's why I say v0_8-branch is superior, that's why I promote use of that branch, and that's why I encourage all users of Icarus Verilog synthesis to make their voices heard.

Anyway, why should I care about synthesis? I'm a front-end microprocessor designer, an architecture guy. Why have I contributed to Icarus Verilog synthesis? I've answered these questions before, but I don't do it often enough. I tend to just jump into details of the project in these blog items.

Actually, there are two active Cosmic Horizon projects. The other one is FSS, a SPARC verification environment. You bring us a SPARC microprocessor design and FSS looks for bugs in its SPARC compliance. If your design is written in JHDL, then you're ready for FSS. If it's written in Verilog, then you'll need a Verilog-to-JHDL translator, the subject of this blog item. (In Alan Feldstein's Blog, I generally alternate between the two projects.)

What does Verilog-to-JHDL translation have to do with synthesis and why have these particular tools been chosen? Translating from Verilog to JHDL can be achieved through an intermediate language called Free Netlist Format (FNF), a technology-neutral target. When Icarus Verilog generates FNF, that involves synthesis. It also involves the FNF generator for Icarus (packaged with Confluence). I chose these particular tools because Tom Hawkins and others working with him on Confluence had already employed/developed these tools to form a path from Verilog to JHDL, and I knew of no other pre-existing path. The challenge for me has been to take OpenSPARC T1 down that path. The tool chain needed (and still needs some) work to be able to support that. One of the issues was support for the latches in OpenSPARC T1.

So if you have a SPARC microprocessor design written in Verilog and would benefit from knowing about bugs in its SPARC compliance, then I want to make you a user of Icarus Verilog synthesis.

Now let me tell you how we achieved correct latch synthesis on Icarus Verilog's v0_8-branch, and what I've been working on since.

Last time, I wrote that "more work is required for the latch's Q and Data pins." I finished writing that blog item on 2010-12-06. Five days later, I happened to notice the following during compilation of the compiler:

...
gcc -DHAVE_CVS_IDENT=1 -I. -I./.. -DHAVE_CONFIG_H -fPIC -Wall -g -O2 -MD -c vvp_scope.c -o vvp_scope.o
vvp_scope.c: In function `draw_net_input_drive':
vvp_scope.c:467: warning: enumeration value `IVL_LPM_LATCH' not handled in switch
mv vvp_scope.d dep
...

I notified the other Icarus Verilog developers with Bug ID 3135448, explaining that "vvp" indicates the simulator, which is unnecessary for my purposes.

Then I studied the effect I had had on the FNF with the work I had just performed on the latch's Q and Data pins. I concluded on 2010-12-12 that Q and Data were "connected better", but that "more work is required to fully convince myself that they are connected properly and to fully understand all of the FNF in [the OpenSPARC T1 bw_u1_scanlg_2x] module." Nevertheless, because Q and Data were connected better, it was time to get a patch to Steve Williams.

Before preparing a patch for the Icarus Verilog community, I always perform their testing (i.e. the test suite).

jesus% diff regression_report-v0.8.txt regression_report.txt
1219c1219
< basiclatch: ==> Failed - output does not match gold file.
---
> basiclatch: ==> Failed - running iverilog.
1578c1578
< stask_sens_null_arg: Passed.
---
> stask_sens_null_arg: ==> Failed - running iverilog.
1583c1583
< Total=1578, Passed=1000, Failed=3, Not Implemented=454, Expected Fail=121
---
> Total=1578, Passed=999, Failed=4, Not Implemented=454, Expected Fail=121
jesus%

The second mismatch was a curiosity, but I was more interested in the first. The command line had been

iverilog-0.8 -o vsim -S ./ivltests/basiclatch.v > log/basiclatch.log 2>&1

And the contents of log/basiclatch.log were

./ivltests/basiclatch.v:39: warning: Process not synthesized.
internal error: no input to nexus q
Assertion failed: 0, file vvp_scope.c, line 471
Abort - core dumped

The warning wasn't important. It was about an initial statement. Initial statements do not synthesize.

The failed assertion in vvp didn't concern me either, as I explained above.

But "no input to nexus q" was important.

I was more comfortable about causing the warning reported in Bug ID 3135448 than I was about causing new regression failures. However, I believed that all of these issues were the result of new capabilities, and that the issues were giving a false impression of degraded software. In reality, my contributions had finally gotten good enough that vvp had an itch to scratch.

Still, we had a dilemma. I wanted to submit my patch even though it appeared to be negatively affecting the basiclatch test with regard to simulation on version 0.8. We would be left with the following situation:

















v0.8 v0.9
latch synthesis passing broken
latch simulation never implemented passing


The question that remained was what the basiclatch test should be.

(Option 1) The basiclatch test both stimulates and verifies synthesis. It also tests simulation. Stimulation of synthesis can be achieved with the -S option. In order to see the broken condition of v0.9 latch synthesis in the regression results, we would need to run the test as "normal,-S" and modify regression_report-v0.9.txt accordingly. In order to see the passing condition of v0.8 latch synthesis, we need to perform verification of synthesis, which requires more work to enhance the test. The problem with this approach is that the condition of v0.8 latch simulation masks a passing synthesis result until someone (who?) implements simulation. Also, the condition of v0.9 latch simulation goes unrewarded until synthesis is fixed (e.g. by "merging" v0.8 into v0.9).

(Option 2) The basiclatch test is for simulation only. A new test is created to stimulate and verify latch synthesis. The advantage of this approach is that it allows us to properly show the condition of latch synthesis (i.e. passing on v0.8 and broken on v0.9).

I shared these concerns with [iverilog-devel].

Cary R. responded about the stask_sens_null_arg mismatch. "The second fail could be because you have not pulled the latest fixes. I added that on 11/16 to all the Icarus versions." He was correct.

With regard to what the basiclatch test should be, Cary R. was the only one who participated in the discussion, so his choice of Option 1 represents the will of the Icarus Verilog development community. Based on his input, I rewrote and shared my description of that option, to get consensus:

(Option 1) The basiclatch test both stimulates and verifies synthesis. It also tests simulation. Stimulation of synthesis can be achieved with the -S option.

I took a closer look at the internal error.

jesus% find . | xargs grep "no input to nexus"
./tgt-vvp/vvp_scope.c: fprintf(stderr, "internal error: no input to nexus %s\n",
jesus%

This error emerges from vvp and doesn't occur with

iverilog-0.8 -v -tfnf -I$DV_ROOT/design/sys/iop/include -cFlist.iop_top -g2 -sOpenSPARCT1 $DV_ROOT/lib/u1/u1.behV $DV_ROOT/design/sys/iop/common/rtl/swrvr_clib.v

Therefore, I decided to disregard the error and instead focus on what I believed at the time to be the need for one more FNF fix. But first, I privately speculated about the "no input to nexus q" error, writing the following in my notes on 2010-12-16.

It is very possible that the "input" that vvp wants to nexus q is an explicit description of function, and that such function is implied in the FNF representation. "Nathan Cain built an a FNF-to-JHDL translator. It comes with the last release of Confluence (0.10.6)." That translator would then fill in whatever explicit description needs to be conveyed to JHDL, or simply choose a JHDL primitive that already knows how to function properly.

Anyway, I want to see the patch for Bug ID 3135448 that Cary R. submitted on 2010-12-14 (Cary informed me on 2010-12-15 that "Steve has already left on his extended Christmas vacation ... he gets back, a few weeks", and we need Steve for the push.). It seems to me rather simple to return a result from function draw_net_input_drive, thereby escaping from the function before reaching the code that prints
internal error: no input to nexus q
Since that's simple (and seems consistent with Cary's description of the patch), it means Cary likely already stopped that error message. So there's nothing to debug, right?

On 2010-12-17, I added the following to my notes.

I think I'll want to go deep (i.e. FNF-to-JHDL translator) first, rather than wide (** ERROR: Inout ports not supported). Fully understand all of the FNF in module bw_u1_scanlg_2x. Make any necessary fixes. Then, isolate the module from OpenSPARC T1 and see what the FNF-to-JHDL translator does with it. Finally, write a JHDL test bench for bw_u1_scanlg_2x and prove that it is functional in the JHDL simulator (independent of FSS). If I do all that and the internal error from vvp_scope.c persists, then it isn't my problem.

The first part of that is: "Fully understand all of the FNF in module bw_u1_scanlg_2x. Make any necessary fixes." This corresponds to what I wrote above: "... disregard the error and instead focus on what I believed at the time to be the need for one more FNF fix."

So I set out to fill in the gaps in my understanding of FNF semantics. I'll spare you the details.

On 2010-12-18, I made an interesting observation.

It is strange that nexus 29150 (the output of module bw_u1_scanlg_2x) does not connect to anything. It is aliased to other names in other scopes, but it goes nowhere. This might be a symptom of a greater problem, where the other symptom is suspiciously fast OpenSPARC T1 compilation time. I may not be compiling the whole design.

But this issue is unrelated to the basiclatch test failure. The fact that the OpenSPARC T1 latch connects to a NOT gate in the FNF is proof that the latch output connects properly to external circuitry.

On 2010-12-19, I wrote the following in my notes.

Everything looks good except for the Data input. There should be a NAND gate there. FNF forms a NAND gate from an AND gate and a NOT gate. The NOT gate is present and its input nexus is 2437. Nexus 2437 is named ("_s9"), but nothing else happens to it within this scope.

Compare with a similar module containing a flip flop.










module ff (output so, input sd, ck, se);
reg so_l; // so_l is a variable.
assign so = ~so_l;
not G1 (ck_l, ck);
always @(posedge ck_l)
so_l <= ~(sd & se);
endmodule
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 "ff" "ff" (
(input 0 "ck" 1)
(select 1 1 0 0)
(input 2 "sd" 1)
(select 3 1 0 2)
(input 4 "se" 1)
(select 5 1 0 4)
(output 7 "so" 1 6)
(name 9 "so_l" 1 8)
(name 11 "ck_l" 1 10)
(name 13 "_s5" 1 12)
(name 15 "_s6" 1 14)
(name 16 "_s8" 1 12)
(not 6 1 8)
(not 10 1 1)
(and 14 1 3 5)
(not 12 1 14)
(ff 17 1 10 12)
(select 8 1 0 17)
))
   (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 43018)
(select 43013 1 0 43020)
))


I expected a lot more similarity between the two modules than that. In particular, note that there are no (input ...) or (output ...) lines in the bw_u1_scanlg_2x FNF. My first thought was that this might be an issue of the Verilog-1995 legacy style used in OpenSPARC. I posted that thought on the OpenSPARC Forum on 2010-12-19.

But I was quickly able to prove for myself that it was not an issue of Verilog-1995 legacy style, but one of hierarchical level. In the above table, the module on the left is at level 0 (i.e. root scope). The Icarus FNF code generator only produces the (input ...) and (output ...) designations for level 0. Otherwise, (name ...) is used.

Still, I was puzzled by the total lack of (input ...) or (output ...) designations in OpenSPARC T1 FNF, even for its root scope, "OpenSPARCT1". I began to investigate.

In the meantime, there was the following exchange.

2010-12-20T19:06 Cary R.: let me know if you want me to take a look at latch synthesis
2010-12-21T12:08 Alan F.: I think I have it under control.
2010-12-21T13:03 Cary R.: I rewrote the middle of the compiler regarding latch synthesis last night

But I was in the middle of an investigation. Arbitrarily choosing to focus on OpenSPARCT1 output DRAM0_RAS_L, I wanted to know why the (output ...) designation had not appeared in the FNF representation. A breakpoint conditional on "OpenSPARCT1", level 0 and "DRAM0_RAS_L" was never hit, which is consistent with the lack of (output ...) designation. The only way this can happen is if the root scope doesn't have the signal according to ivl_scope_sigs and ivl_scope_sig.

On 2010-12-25, I observed DRAM0_RAS_L getting added to the root scope. Does it later get removed?

On 2010-12-27, I watched it get removed.

(gdb) backtrace
#0 NetScope::rem_signal (this=0x2614c8, net=0x51bbd0) at net_scope.cc:312
#1 0x000d8a3c in NetNet::~NetNet (this=0x51bbd0,
__in_chrg=, __vtt_parm=)
at netlist.cc:334
#2 0x00162ee4 in nodangle_f::signal (this=0xffbff2a0, des=0x261480,
sig=0x51bbd0) at nodangle.cc:140
#3 0x000c7cbc in NetScope::run_functor (this=0x2614c8, des=0x261480,
fun=0xffbff2a0) at functor.cc:111
#4 0x000c7db4 in Design::functor (this=0x261480, fun=0xffbff2a0)
at functor.cc:122
#5 0x0016319c in nodangle (des=0x261480) at nodangle.cc:198
#6 0x0006b9c4 in main (argc=6, argv=0xffbff72c) at main.cc:690
(gdb)

/* Check to see if the signal is completely unconnected. If
all the bits are unlinked, then delete it. */


DRAM0_RAS_L is completely unconnected? It should be externally unconnected because it is a port of the root scope, but certainly there is at least one internal connection.

The OpenSPARC T1 source browser shows

DRAM0_RAS_L : OpenSPARCT1 : output
Connects down to: pad_ddr0:pad_ddr0:dram0_ras_l
Connects up to: cmp_top:iop:DRAM0_RAS_L

There is no pad_ddr0 in the FNF.

`ifdef RTL_PAD_DDR0
pad_ddr0 pad_ddr0
(
...
.dram0_ras_l (DRAM0_RAS_L), // Templated
...
); ...
`endif


I had been puzzled by the total lack of (input ...) or (output ...) designations in OpenSPARC T1 FNF, even for its root scope, "OpenSPARCT1". Having found the root cause of nonexistence of "(output ...)" for one OpenSPARC T1 output port, I was no longer "puzzled", so on 2010-12-28 I could continue with my main purpose. But I will certainly need to return to the issue of conditionally compiled instantiations eventually.

At this point, I shared my findings with the OpenSPARC community. Icarus Verilog and the Icarus Verilog FNF generator fully support the Verilog-1995 legacy style, but I stand by my recommendation that Oracle move to the Verilog-2001 style. The (input ...) and (output ...) designations in FNF are for level 0 (i.e. root scope) only. Otherwise, (name ...) is used. I also questioned the total lack of (input ...) or (output ...) designations in OpenSPARC T1 FNF, even for its root scope, "OpenSPARCT1". For example DRAM0_RAS_L: While RUNNING FUNCTORS (specifically nodangle), root scope output DRAM0_RAS_L gets removed from the scope. This happens because the signal is completely unconnected. The OpenSPARC T1 source browser shows that this output connects down to pad_ddr0:pad_ddr0:dram0_ras_l, but there is no pad_ddr0 in the FNF. And that is because of `ifdef RTL_PAD_DDR0.

main purpose: Compare with flip flop.

The Icarus FNF code generator only produces the (input ...) and (output ...) designations for level 0. Otherwise, (name ...) is used. Therefore, to minimize the differences between module ff and module bw_u1_scanlg_2x, I would create a top level module that instantiates module ff.

I decided to base that top level module on the module in OpenSPARC T1 that instantiates the bw_u1_scanlg_2x I have been examining. That is ctu_top_rptr. I can ignore the following problem for my purposes right now, but I encountered a troubling detail:

module ctu_top_rptr(/*AUTOARG*/
// Outputs
l2_dbgbus_out, enable_01, so,
// Inputs
dbgbus_b0, dbgbus_b1, rclk, si, se
);



output [39:0] l2_dbgbus_out ;
output enable_01;
input [40:0] dbgbus_b0;
input [40:0] dbgbus_b1;


input rclk;
input si, se;
output so;

wire [39:0] l2_dbgbus_out_prev ;
wire enable_01_prev;

wire int_scanout;

// connect scanout of the last flop to int_scanout.
// The output of the lockup latch is
// the scanout of this dbb (so)

bw_u1_scanlg_2x so_lockup(.so(so), .sd(int_scanout), .ck(rclk), .se(se));
...


Despite the helpful comment, int_scanout isn't actually connected to anything except for bw_u1_scanlg_2x, where it is an input!

Here is the result of creating a top level module that instantiates module ff.










module ff (output so, input sd, ck, se);
reg so_l; // so_l is a variable.
assign so = ~so_l;
not G1 (ck_l, ck);
always @(posedge ck_l)
so_l <= ~(sd & se);
endmodule
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 "ff" "so_lockup" (
(name 8 "ck" 1 3)
(name 9 "sd" 1 0)
(name 10 "se" 1 5)
(name 11 "so" 1 6)
(name 13 "so_l" 1 12)
(name 15 "ck_l" 1 14)
(name 17 "_s5" 1 16)
(name 19 "_s6" 1 18)
(name 20 "_s8" 1 16)
(not 6 1 12)
(not 14 1 3)
(and 18 1 0 5)
(not 16 1 18)
(ff 21 1 14 16)
(select 12 1 0 21)
))
   (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 43018)
(select 43013 1 0 43020)
))


Now I can compare bw_u1_scanlg_2x to ff without the distraction of (input ...) and (output ...).

One oddity in module ff is that the output of the NAND's NOT gate has two names, "_s5" and "_s8". The other oddity is the way the NAND is formed, with an AND gate one level down from the NOT gate. (Indentation is significant in FNF; it indicates hierarchical level.)

It's good that these oddities in ff are exactly in the area where the bw_u1_scanlg_2x appeared to be broken. Also good is the fact that there are no other important differences between the two modules.

In module ff, the NAND's AND gate is fed by nexus ids 0 and 5 ("sd" and "se" respectively).

Why doesn't module bw_u1_scanlg_2x have a multi-gate (i.e. a NAND formed from AND and NOT) in its FNF?

By the way, I never did investigate why the output of the NAND's NOT gate has two names. But the first sign of trouble (an FNF file is generated from top to bottom) is that I don't get that odd behavior in bw_u1_scanlg_2x.

Using GDB, I found that an IVL_LO_NAND was never recognized in bw_u1_scanlg_2x.

I concluded that
(not 43018 1 2437)
had been misidentified as IVL_LO_NOT.

To find when the decision to generate a NOT gate rather than a NAND gate was made, I had to search backward in time. It was an iterative process of moving and morphing debug code whose call looked something like this:

ivl_scope_children( ivl_design_root( &des_ ), displayLogicType, 0 );


On New Year's Day, I seemed to be getting close.

Before
// emit nodes
there are no logic devices.

After
// emit nodes
it is the wrong logic device.

Obviously, I need to inspect
// emit nodes

This was also the day that Cary R. wrote the following in Bug ID 3135448: "I have submitted a patch that adds full support for simulating a latch primitive. This should support all the functionality needed for an LPM latch. This cannot be fully tested since latch synthesis does not currently support generating asynchronous set/clear signals."

On 2011-01-02, I discovered that dll_target::logic is where the assignment of IVL_LO_NOT occurs. It is based on net->type(), which is the type of the NetLogic object passed in. This meant that I need to look even earlier. The type of the NetLogic object was wrong.

As an aside, on 2011-01-03 I noted that struct functor_t has a method (i.e. lpm_ff) that is called for each flip flop in the design, but there is no lpm_latch.

On 2011-01-04, I made a series of discoveries.

logic: not #(0,0,0) _s12 scope=OpenSPARCT1.ctu_top_rptr.so_lockup
0 O<0> O (strong0 strong1): 0xbd9250 _s11
1 I<0> I (strong0 strong1): 0xbd8fc8 _s9


The "_s12" LPM combinational logic device gets added to the Design while running functors. The nexus named "_s9" is fed by an AND gate after synth2. This AND gate survives synth and syn-rules, but is eliminated by cprop.

I would not insist that bw_u1_scanlg_2x use a multi-gate. A flat hierarchy with an AND feeding a NOT would be acceptable to me. But, at this point, I was operating under the assumption that the AND gate was necessary.

/*
* The cprop function ... invokes constant propagation where
* possible. The elaboration generates NetConst objects. I can remove
* these and replace the gates connected to it with simpler ones. I
* may even be able to replace nets with a new constant.
*/


I studied the situation with GDB and inspected the OpenSPARC T1 Verilog. On 2011-01-05, I made the final discoveries. All instances of bw_u1_scanlg_2x have se connected to the same signal. Each instance of bw_u1_scanlg_2x has a unique source for sd. OpenSPARCT1.ctu_top_rptr.so_lockup.sd in particular comes from OpenSPARCT1.ctu_top_rptr.int_scanout! (Find "int_scanout" earlier in this blog item.)

So it is reasonable that Icarus Verilog has chosen constant propagation of X (unknown, uninitialized, don't care) here. But I will need to consider FSS Requirement 1.6.2 ("Two-Value") and its implications on Verilog-to-JHDL translation.

At this point (2011-01-05), I was completely satisfied with the bw_u1_scanlg_2x FNF and ready to submit a patch. Note that my contribution had been ready since 2010-12-12. I had made no changes since then, only investigated a cause for suspicion.

By now, I understood that Cary R. had latch simulation working on v0.8. We will be left with the following situation:

















v0.8 v0.9
latch synthesis passing broken
latch simulation passing passing


I started the process of making my contribution.

...
gcc -DHAVE_CVS_IDENT=1 -I. -I./.. -DHAVE_CONFIG_H -fPIC -Wall -g -O2 -MD -c \
vvp_scope.c -o vvp_scope.o
vvp_scope.c: In function `draw_net_input_drive':
vvp_scope.c:467: warning: enumeration value `IVL_LPM_LATCH' not handled in switch
mv vvp_scope.d dep
...


That should go away when I pull the Bug ID 3135448 fix from Cary R.

FNF matched expectation, so I wanted to commit locally.

jesus% git status --short
error: unknown option `short'
...


That was annoying, so I removed package SMCgit (1.6.2.1) and replaced it with SMCgit (1.7.2). I also needed

  1  SMCossl     openssl
(sparc) 1.0.0c


Sparing you some details of my minor Git struggles, I achieved the local commit on 2011-01-07.

Next came ivtest, starting with a pull of the test suite.

jesus% diff regression_report-v0.8.txt regression_report.txt
1214c1214,1215
< case5: ==> Failed - output does not match gold file.
---
> case5: Passed.
> case5-syn-fail: ==> Failed - CE (no error reported).
1219c1220
< basiclatch: ==> Failed - output does not match gold file.
---
> basiclatch: ==> Failed - running iverilog.
1583c1584
< Total=1578, Passed=1000, Failed=3, Not Implemented=454, Expected Fail=121
---
> Total=1579, Passed=1001, Failed=3, Not Implemented=454, Expected Fail=121
jesus%


I expected a basiclatch simulation failure because I had not yet pulled the simulation fix from Cary R. The other lines in the above diff were a mystery, so I started a discussion on [iverilog-devel]. On 2011-01-08, Cary R. replied with, "The expected result file has not been updated since Steve has not applied the patches yet." That was all I needed to hear. I put the Icarus Verilog project on hold.

FNF is a technology-neutral target that one could pass to other tools. One such tool is a Confluence compiler that generates Verilog, VHDL, Python, or C.

While the Icarus Verilog project was on hold, I would take the latch FNF through Nathan Cain's FNF-to-JHDL translator. This would be the first attempt to use this part of Confluence.

jesus% cd ~/cvs/confluence/
jesus% find . -name "*jhdl*"
./src/fnflib/fnf_jhdl.ml
./src/fnflib/fnf_jhdl.mli
jesus%


That's when I made my first mistake. I found a Web site that told me about those file extensions: "primarily associated with 'F#' by Microsoft Corporation". I'm just going to skip over this part of my notes and tell you that I eventually saw the light.

On 2011-01-09 I wrote, "but XEmacs puts itself in caml mode upon opening
./src/fnflib/fnf_jhdl.ml
./src/fnflib/fnf_jhdl.mli


On 2011-01-10, Tom Hawkins confirmed that the Confluence translators were written in Objective Caml.

That's another language I didn't yet know, but at least I wouldn't find myself in the uncomfortable position of encouraging onto Microsoft Windows operating systems (or onto Mono) those with SPARC designs written in Verilog.

So I installed this:

  1  SMCocaml     ocaml
(sparc) 3.10.2


"The Objective Caml system is an industrial-strength implementation of this language, featuring a high-performance native-code compiler (ocamlopt) for 9 processor architectures (IA32, PowerPC, AMD64, Alpha, Sparc, Mips, IA64, HPPA, StrongArm), as well as a bytecode compiler (ocamlc) and an interactive read-eval-print loop (ocaml) for quick development and portability."

Naturally, I was interested in ocamlopt. Starting with
./src/fnflib/fnf_jhdl.ml
./src/fnflib/fnf_jhdl.mli

I tried compiling, had to manually search for a few dependencies and soon was successful. But I still didn't know how to use the program. I figured that I'd have to learn how to read the source code.

Then on 2011-01-12, I received a message from Cary R. informing me that the Icarus Verilog test suite was ready.

jesus% diff regression_report-v0.8.txt regression_report.txt
1215c1215
< case5-syn-fail: Passed - CE.
---
> case5-syn-fail: ==> Failed - CE (no error reported).
1220c1220
< basiclatch: Passed.
---
> basiclatch: ==> Failed - running iverilog.
1239c1239
< dffsynth: Passed.
---
> dffsynth: ==> Failed - output does not match gold file.
1584c1584
< Total=1579, Passed=1004, Failed=0, Not Implemented=454, Expected Fail=121
---
> Total=1579, Passed=1001, Failed=3, Not Implemented=454, Expected Fail=121
jesus%


case5: There is no longer a mismatch.

case5-syn-fail: This test is now expected to exist (improvement). But we expect a compilation error and don't get it with the local version of Icarus Verilog. I should pick up Cary's fix on the next Icarus Verilog pull.

basiclatch: The change is that the test is now expected to pass. Further investigation revealed the same local failures seen with the previous version of ivtest (all related to simulation, not synthesis). Cary's simulation fix should make basiclatch pass.

dffsynth: This is a new mismatch. But it's right in the area that Cary said he was working. The local actual result (Failed - output does not match gold file.) is the central repository's previous expected result. I believe that my next Icarus Verilog pull will give me the code that passes dffsynth.

Since I was, at this point, satisfied with each mismatch in regression testing (actual vs. expected results), the next step was to be an Icarus Verilog pull. That was messy.

The "details" attached to Patch ID 3161378, submitted 2011-01-19, provide a nice summary here.

On 2010-12-12, a local commit was made: "latch synthesis fix: Connect q and data pins in netlist." Testing had shown that FNF output was more correct than before this commit, but the changes were causing new ivtest failures. Exploration was begun into some apparent issues with the FNF, which was ultimately proven to be perfect, and the ivtest failures (basiclatch) were determined to be vvp-related.

Meanwhile, a parallel effort was initiated to resolve the vvp issues. That effort resulted in several patches since 2010-12-12, some of which were in the same area as the latch synthesis fix mentioned above. In fact, those patches obsoleted the 2010-12-12 local commit as described.

However, there were certain robustness improvements included in that local commit that were not obsoleted. After a pull, manual conflict resolution and thorough testing, those improvements are preserved by this patch and are as follows:

Check for zero-width vector.
Replace assertions with exceptions.
Use C++-style cast.
Use suffix for unsigned integer constants.
Catch bad_alloc exception.

Having submitted that patch, I returned to Nathan Cain's FNF-to-JHDL translator.

By 2011-01-21, my behavior had improved. I was invoking make from
~/cvs/confluence/src


I realized that, unlike the Icarus Verilog FNF generator, the FNF-to-* translators were integrated into Confluence, not standalone translators.

The build was successful, but
make install

failed. Usage of the install command in Makefile doesn't match the Solaris man page. I had had the same problem with the Icarus Verilog FNF generator in 2006.

# cp /home/alan/cvs/confluence/src/fnf /usr/local/bin/


jesus% which fnf
/usr/local/bin/fnf
jesus% fnf

NAME
fnf

SYNOPSIS
fnf [options]

DESCRIPTION
FNF (Free Netlist Format) is an elaborated, hierarchical, register transfer
level (RTL) netlist format used to communicate design information between
frontend EDA tools.

The FNF tool translates an FNF netlist to Verilog, VHDL, C, and NuSMV.

OPTIONS
Options are processed in the order they are received.

-h OR -help
Prints this information then exits.

-read_fnf file
Read in an FNF netlist.

-write_fnf file
Write out an FNF netlist.

-write_nusmv file
Write out an NuSMV description.

-write_verilog file
Write out a Verilog netlist.

-write_vhdl file
Write out a VHDL netlist.

-write_c file
Write out a C model. Appends '.c' and '.h' to file name.

-write_jhdl class
Write out a JHDL netlist. Appends .java to class name.

EXAMPLES
Building an FNF netlist from Verilog using Icarus:

$ iverilog -Wall -t fnf -o my_netlist.fnf my_verilog.v

Use FNF to produce a Verilog and C model:

$ fnf -read_fnf my_netlist.fnf -write_verilog my_netlist.v -write_c my_netlist

Use FNF to produce an NuSMV model:

$ fnf -read_fnf my_netlist.fnf -write_nusmv my_netlist.smv

Use FNF to produce another FNF netlist:

$ fnf -read_fnf my_netlist.fnf -write_fnf my_netlist2.fnf

KNOWN LIMITATIONS
General
- No tristate support.
- No memory support.
- No division or modulo operators.

Icarus Verilog FNF Code Generator
- Assumes ports and named signals have [n:0] ordering.
- "always" blocks are constrained to the Icarus Verilog synthesizable subset.
- All register clocks and asynchronous resets must be senitive on the rising
edge.
WARNING: No errors will be issued if a design contains "negedge".
- All arithmetic operations must be unsigned.
WARNING: No errors will be issued if a design contains signed operations.
- Multipliers can not be embbeded in concatenations.

Verilog and VHDL Model Writer
- Netlist is flat.

NuSMV Model Writer
- 2-value model. No X's or Z's.
- Inputs assumed to init to 0.
- Registers are initialized to 0.

VERSION
0.10.6

AUTHOR
Tom Hawkins

SEE ALSO
FNF and Confluence : http://www.confluent.org/
Icarus Verilog : http://www.icarus.com/eda/verilog/
NuSMV : http://nusmv.irst.itc.it/

COPYRIGHT
Copyright (C) 2004-2005 Tom Hawkins


jesus%


Now I knew how to use the program, and I didn't have to read source code to figure it out. I still expected to need to learn Objective Caml in order to extend the FNF-to-JHDL translator, just not yet.

By the way, don't bother visiting confluent.org. Tom Hawkins gave up that domain and it is no longer related to FNF and Confluence. Tom considers Confluence to be a "retired project". It lives on with Cosmic Horizon. When the time comes, I'll find a way to deliver the software to you.

Finally, here's what happens when I take the latch FNF that Icarus Verilog produced through Nathan Cain's FNF-to-JHDL translator.


jesus% fnf -read_fnf ~/tmp/bw_u1_scanlg_2x.fnf -write_jhdl bw_u1_scanlg_2x

** Syntax Error in /home/alan/tmp/bw_u1_scanlg_2x.fnf at line 13,8

Unrecognized character: 'l'


jesus%


Line 13 is the latch!

That was 2011-01-21.

Have I learned enough Objective Caml to be able to deal with this now? I don't think so. But I started some work on areas that were straightforward.

First of all, the issue was with FNF recognition, not JHDL. So I started with fnf_core.ml.

I made pretty good progress that first day, but I'm going to omit most of the details, at least until I'm more comfortable with Objective Caml. I will say, however, that I settled on a compromise. I decided to alternate days between learning Objective Caml and working on extending the fnf tool for latches.

Note that the addition of "latch" to the FNF language causes warnings (during compilation of the fnf tool) in
fnf_out.ml
fnf_verilog.ml
fnf_vhdl.ml
fnf_jhdl.ml
fnf_nusmv.ml
fnf_c.ml

My only concern is fnf_jhdl.ml. It is very convenient that new warnings are the only damage caused to the other translators. The warnings signal Confluence developers that there is more work to be done, while allowing me to focus on extending just FNF-to-JHDL translation.

On 2011-01-24, Steve Williams made a positive comment in Patch ID 3161378. But he specifically ruled against replacing assertions with exceptions. So I reversed just that change and provided 0001-Robustness-improvements3.patch on 2011-01-26. There has been no action taken on this patch since. Its status remains "Open".

Back to the FNF-to-JHDL translator, by 2011-01-29 I was starting to hit a wall in "working on extending the fnf tool for latches." In other words, I was acknowledging the immaturity of my Objective Caml abilities. I had to learn more before going much further.

Lexer and parser generators (ocamllex, ocamlyacc)

"This chapter assumes a working knowledge of lex and yacc: while it describes the input syntax for ocamllex and ocamlyacc and the main differences with lex and yacc, it does not explain the basics of writing a lexer or parser description in lex and yacc. Readers unfamiliar with lex and yacc are referred to 'Compilers: principles, techniques, and tools' by Aho, Sethi and Ullman (Addison-Wesley, 1986), or 'Lex & Yacc', by Levine, Mason and Brown (O'Reilly, 1992)."

For those days that I was "learning Objective Caml", I found myself immersed in "The Functional Approach to Programming".

Now that I had hit a wall in "working on extending the fnf tool for latches", the days assigned to that task would have to be spent reading too. I decided on "Compilers: principles, techniques, and tools" by Aho, Lam, Sethi and Ullman (Addison-Wesley, 2007). This started on 2011-02-02.

And that's what I've been doing ever since with my "OpenSPARC" time, alternating between the two books.

But a significant event occurred on 2011-02-17. On that date, I increased my job search effort from 10 hours per week to 40. Doing this subtracts 20 hours from my Cosmic Horizon effort (and 10 from technical reading). The purpose, of course, is to land a job quickly. If you're reading this, it is because you are impressed with what I do. Imagine then what I can achieve for your employer, and do something about it!

A flurry of discussion about Icarus Verilog synthesis broke out on [iverilog-devel] starting 2011-03-09.