Monday, March 18, 2013

Templating with web.py for Circuit Design

When describing circuits to computers, have you ever felt that the languages for EDA, be it SPICE or Verilog or whatever are not flexible enough ? Well, I have. Coding regular structures such as adders, ring oscillators, multipliers etc. with popular languages in EDA can be a pain. A couple of weeks ago, I was checking out a synthesized ring oscillator to build a time-to-digital converter (TDC) [1]. Building long chains of inverters by hand is drudgery and SPICE does precious little to help in automation. At first, I tried writing a python program with string manipulations that generates verilog code, but quickly came to realize that its way more natural to have snippets of python inside verilog. Now, that needs a bit of work to get going. Thankfully, web developers solved this problem long ago for programmatically generating HTML. I used web.py 's templating engine to write verilog code that describes a ring oscillator (in case you are surprised by the fact that I used verilog rather than SPICE, the whole idea is to create the TDC with standard cells).


The following snippet causes web.py to create a HTML page of verilog code that describes a loaded ring oscillator. The loading and the number of inverters can be easily changed by setting variables M and N below.

<body>
    module ringosc(clk); </br></br>

    output clk; </br>

    </br>

    <div id="body">
        $# first add the AND gates
        $for i in range(M+1):
            ND2CHD U$us (.I1(en),.I2(n$ns),.O(n$(ns+1))); </br>
            $ us += 1
        $ ns += 1
        </br>
        $# now complete the ring with buffers
        $for i in range(N-1):
            $ no = ns + 1
            $if no==N:
                $ no = 0
            INVTCHD U$us (.I(n$ns), .E(high), .O(n$no) ); </br>
            $ us += 1
            $for j in range(M):
                INVTCHD U$us (.I(n$ns), .E(control[$cb]), .O(n$no) ); </br>
                $ us += 1
                $ cb += 1
            $ ns += 1
       
        $# now put clock buffers before sending it out.
        </br>
        INVCKDHD UCK1( .I(n1), .O(nc1) ); </br>
        INVCKJHD UCK2( .I(nc1), .O(nc2) ); </br>
        INVCKQHD UCK3( .I(nc2), .O(clk) ); </br>
       
        </br>
        TIE0DHD Ulo( .O(low) ); </br>
        TIE1DHD Uhigh( .O(high) ); </br>

        </br></br></br>
    </div>

    <div id="declare">
        wire
        $for i in range(N-1):
            n$i,
        n$(N-1),en,nc1,nc2,high,low;

        </br></br>
    </div>

    endmodule
</body>


The resulting HTML page is

module ringosc(clk);

output clk;


wire n0, n1, n2, n3, n4,en,nc1,nc2,high,low;
ND2CHD U0 (.I1(en),.I2(n0),.O(n1));
ND2CHD U1 (.I1(en),.I2(n0),.O(n1));
ND2CHD U2 (.I1(en),.I2(n0),.O(n1));
ND2CHD U3 (.I1(en),.I2(n0),.O(n1));
ND2CHD U4 (.I1(en),.I2(n0),.O(n1));
ND2CHD U5 (.I1(en),.I2(n0),.O(n1));
ND2CHD U6 (.I1(en),.I2(n0),.O(n1));
ND2CHD U7 (.I1(en),.I2(n0),.O(n1));
ND2CHD U8 (.I1(en),.I2(n0),.O(n1));

INVTCHD U9 (.I(n1), .E(high), .O(n2) );
INVTCHD U10 (.I(n1), .E(control[0]), .O(n2) );
INVTCHD U11 (.I(n1), .E(control[1]), .O(n2) );
INVTCHD U12 (.I(n1), .E(control[2]), .O(n2) );
INVTCHD U13 (.I(n1), .E(control[3]), .O(n2) );
INVTCHD U14 (.I(n1), .E(control[4]), .O(n2) );
INVTCHD U15 (.I(n1), .E(control[5]), .O(n2) );
INVTCHD U16 (.I(n1), .E(control[6]), .O(n2) );
INVTCHD U17 (.I(n1), .E(control[7]), .O(n2) );
INVTCHD U18 (.I(n2), .E(high), .O(n3) );
INVTCHD U19 (.I(n2), .E(control[8]), .O(n3) );
INVTCHD U20 (.I(n2), .E(control[9]), .O(n3) );
INVTCHD U21 (.I(n2), .E(control[10]), .O(n3) );
INVTCHD U22 (.I(n2), .E(control[11]), .O(n3) );
INVTCHD U23 (.I(n2), .E(control[12]), .O(n3) );
INVTCHD U24 (.I(n2), .E(control[13]), .O(n3) );
INVTCHD U25 (.I(n2), .E(control[14]), .O(n3) );
INVTCHD U26 (.I(n2), .E(control[15]), .O(n3) );
INVTCHD U27 (.I(n3), .E(high), .O(n4) );
INVTCHD U28 (.I(n3), .E(control[16]), .O(n4) );
INVTCHD U29 (.I(n3), .E(control[17]), .O(n4) );
INVTCHD U30 (.I(n3), .E(control[18]), .O(n4) );
INVTCHD U31 (.I(n3), .E(control[19]), .O(n4) );
INVTCHD U32 (.I(n3), .E(control[20]), .O(n4) );
INVTCHD U33 (.I(n3), .E(control[21]), .O(n4) );
INVTCHD U34 (.I(n3), .E(control[22]), .O(n4) );
INVTCHD U35 (.I(n3), .E(control[23]), .O(n4) );
INVTCHD U36 (.I(n4), .E(high), .O(n0) );
INVTCHD U37 (.I(n4), .E(control[24]), .O(n0) );
INVTCHD U38 (.I(n4), .E(control[25]), .O(n0) );
INVTCHD U39 (.I(n4), .E(control[26]), .O(n0) );
INVTCHD U40 (.I(n4), .E(control[27]), .O(n0) );
INVTCHD U41 (.I(n4), .E(control[28]), .O(n0) );
INVTCHD U42 (.I(n4), .E(control[29]), .O(n0) );
INVTCHD U43 (.I(n4), .E(control[30]), .O(n0) );
INVTCHD U44 (.I(n4), .E(control[31]), .O(n0) );

INVCKDHD UCK1( .I(n1), .O(nc1) );
INVCKJHD UCK2( .I(nc1), .O(nc2) );
INVCKQHD UCK3( .I(nc2), .O(clk) );

TIE0DHD Ulo( .O(low) );
TIE1DHD Uhigh( .O(high) );

endmodule
 
Now, it takes hardly a second to jump from a 5 tap ring oscillator described above to a 105 tap ring oscillator.

References
1. Youngmin Park and David D. Wentzloff, A cyclic vernier time-to-digital converter synthesized from a 65nm CMOS standard library.

No comments:

Post a Comment