Levelization of circuits
Hello,
When working with benchmark circuits, it is convenient to levelize the gates and work with levels. This is useful when you want to calculate some metric for all gates or wires. It is efficient than recursively traversing through all wires, gates, and fanouts.
Here I upload a program that levelizes the iscas bench marks. It is written in perl. Use it the way you see fit and edit it if you find mistakes.
Levelization
When working with benchmark circuits, it is convenient to levelize the gates and work with levels. This is useful when you want to calculate some metric for all gates or wires. It is efficient than recursively traversing through all wires, gates, and fanouts.
Here I upload a program that levelizes the iscas bench marks. It is written in perl. Use it the way you see fit and edit it if you find mistakes.
Levelization
1. Assign level number 0 to all primary
inputs
2. For each PI fanout
- Label that circuit line with level number of the PI
- Queue the logic gate driven by that fanout line (I need a queue)
3. While queue is not empty
- dequeue the next logic gate in the queue
- If all of the gate fanins are labeled with level numbers, then label the logic gate and its fanouts with maximum of input levels + 1. Queue all fanouts of the logic gate. Otherwise requeue the logic gate.
Algorithm - Levelization
loop
inputlist - list of primary inputs
for all gates
if either of input of gates is present
in the inputlist,
add the gate to the queue
for the gates in the queue
dequeue the gate
if all the inputs of the gates have
levels assigned (level is not -1) then
level(gate)=max(level of inputs)+1,
level(output wire) = max(level of inputs)+1
push outputwire into input list
if all inputs of gate do not have
levels assigned
push the gate to the end of the
queue.
goto loop
How to run: perl levelization.plx test_3.v
Sample: test_3.v
module test_3 (A1,B1,C1,D1,O1,O2,O3);
input A1,B1,C1,D1;
output O1,O2,O3;
wire Z1,Z2,Z3,Z4;
NAND2X1 NAND2_1 (.Y(Z1),.A(C1),.B(D1));
NAND2X1 NAND2_2 (.Y(Z2),.A(B1),.B(Z1));
NAND2X1 NAND2_3 (.Y(Z3),.A(A1),.B(Z2));
NAND2X1 NAND2_4 (.Y(Z4),.A(Z2),.B(Z1));
NAND2X1 NAND2_5 (.Y(O3),.A(C1),.B(D1));
NAND2X1 NAND2_6 (.Y(O1),.A(Z3),.B(Z4));
BUFX1 BUF1_1 (.Y(O2),.A(Z4));
endmodule
Output
gate: level
NAND2_1: 1
NAND2_2: 2
NAND2_3: 3
NAND2_4: 3
NAND2_5: 1
NAND2_6: 4
BUF1_1: 4
Sample: test_3.v
module test_3 (A1,B1,C1,D1,O1,O2,O3);
input A1,B1,C1,D1;
output O1,O2,O3;
wire Z1,Z2,Z3,Z4;
NAND2X1 NAND2_1 (.Y(Z1),.A(C1),.B(D1));
NAND2X1 NAND2_2 (.Y(Z2),.A(B1),.B(Z1));
NAND2X1 NAND2_3 (.Y(Z3),.A(A1),.B(Z2));
NAND2X1 NAND2_4 (.Y(Z4),.A(Z2),.B(Z1));
NAND2X1 NAND2_5 (.Y(O3),.A(C1),.B(D1));
NAND2X1 NAND2_6 (.Y(O1),.A(Z3),.B(Z4));
BUFX1 BUF1_1 (.Y(O2),.A(Z4));
endmodule
Output
gate: level
NAND2_1: 1
NAND2_2: 2
NAND2_3: 3
NAND2_4: 3
NAND2_5: 1
NAND2_6: 4
BUF1_1: 4
#!/usr/bin/perl
#levelization.plx
use warnings;
use Data::Dumper;
use strict;
my $bench_file = $ARGV[0];
my $file_name;
my $circuit_name;
my $element;
my @input_array;
my @output_array;
my @wire_array;
my @gates;
my @sorted_gates;
my @wire_struct;
my @input_list_struct;
my @gate_queue;
#my @fanout_test;
my $num_inputs=0;
my $num_outputs=0;
my $num_wires=0;
my $num_gates=0;
my $gate_name_temp;
my $gate;
my $line;
my $role;
my $inp;
my $inp_test;
#Test netlist file
if($bench_file =~ /(.*).v/)
{
$file_name = $1;
}
else
{
print "Format of bench file name: circuit_name.v \n example : s1423.v\n";
}
#Read Netlist File
while(<>)
{
my $INPUT_DATA = $_;
chomp($INPUT_DATA);
{
#MODULE NAME
if($INPUT_DATA =~ /module (.*) (.*);/)
{
$circuit_name = $1;
print "circuit name = $circuit_name\n";
}
#INPUT OUTPUT WIRES
if($INPUT_DATA =~ /input (.*);/)
{
@input_array = split /,/, $1;
}
if($INPUT_DATA =~ /output (.*);/)
{
@output_array = split /,/, $1;
}
if($INPUT_DATA =~ /wire (.*);/)
{
@wire_array = split /,/, $1;
}
my @wire1;
my @wire2;
my @wire3;
my $gate_name_temp;
my $gate;
my $line;
my $role;
#AND, OR, NAND, NOR, XOR
if($INPUT_DATA =~ /(.*) (.*) \(\.Y\((.*)\),\.A\((.*)\),\.B\((.*)\)\);/)
{
push @gates,
{
num_inputs => 2,
gate_type => "$1",
gate_name => "$2",
output =>
{
wire_name => "$3",
sa0 => 1,
sa1 => 1,
level => 0,
},
input_1 =>
{
wire_name => "$2_$4",
sa0 => 1,
sa1 => 1,
level => 0,
},
input_2 =>
{
wire_name => "$2_$5",
sa0 => 1,
sa1 => 1,
level => 0,
},
processed => 0,
processed_ip1 => 0,
processed_ip2 => 0,
gate_level => -1,
shifted => 0
};
}
#INV, BUF
#DE - Doesnt Exist
#renaming the gates at inputs of the gates for fanouts
if($INPUT_DATA =~ /(INVX1|BUFX1) (.*) \(\.Y\((.*)\),\.A\((.*)\)\);$/)
{
$gate_name_temp = $2;
push @gates,
{
num_inputs => 1,
gate_type => "$1",
gate_name => "$2",
output =>
{
wire_name => "$3",
sa0 => 1,
sa1 => 1,
level => 0,
},
input_1 =>
{
wire_name => "$2_$4",
sa0 => 1,
sa1 => 1,
level => 0,
},
processed => 0,
processed_ip1 => 0,
gate_level => -1,
shifted => 0
};
}
}
}
#File Read complete
#wire struct holds fault data for all wires
#input_list_struct is used for levelization
for $element (@input_array){
print "input: $element\n";
push @wire_struct, { wire_name => "$element", sa0 => 1, sa1 =>1, level => 0};
push @input_list_struct, {wire_name => "$element", sa0 => 1, sa1 => 1, level => 0};
}
for $element (@wire_array){
push @wire_struct, { wire_name => "$element", sa0 => 1, sa1 =>1, level => -1};
}
for $element (@output_array){
push @wire_struct, { wire_name => "$element", sa0 => 1, sa1 =>1, level => -1};
}
print "Initial inputs\n";
for my $href ( @input_list_struct ) {
print "{ ";
for my $role ( keys %$href ) {
print "$role=$href->{$role} ";
}
print "}\n";
}
$num_gates = scalar @gates;
my $index=0;
#gate_processed = 2 then all inputs are processed
#shift gate into the queue if even one of the inputs processed
while($num_gates != 0)
{
for my $gate(@gates){
for my $inp (@input_list_struct){
my $inp_test = $inp->{wire_name};
if(($gate->{input_1})->{wire_name} =~ m/$inp_test$/){
$gate->{processed_ip1} = 1;
if($gate->{num_inputs}==1){
print "NOTE: $gate->{gate_name}:$gate->{processed}\n";
getc();
if($gate->{processed}!=$gate->{num_inputs}){
unshift(@gate_queue,$gate);
}
}
elsif($gate->{processed_ip2}==1){
$gate->{processed}=$gate->{num_inputs};
}
elsif($gate->{processed}!=$gate->{num_inputs}){
if($gate->{shifted}==0){
print "1. shifting $gate->{gate_name} to gate queue\n";
getc();
unshift(@gate_queue,$gate);
}
}
}
if(($gate->{num_inputs}!=1)){
if(($gate->{input_2})->{wire_name} =~ m/$inp_test$/){
$gate->{processed_ip2} = 1;
if($gate->{processed_ip1}==1){
$gate->{processed}=$gate->{num_inputs};
}
if($gate->{processed}!=$gate->{num_inputs}){
if($gate->{shifted}==0){
print "2. shifting $gate->{gate_name} to gate queue\n";
getc();
unshift(@gate_queue,$gate);
}
}
}
}
}
}
print "Gates in gate queue\n";
for my $line (@gate_queue)
{
for my $role (keys %$line)
{
if($role =~ m/^input_1$/)
{
print "$role: $line->{$role}->{wire_name},";
print "lvl: $line->{$role}->{level},";
}
elsif($role =~ m/^input_2$/)
{
print "$role: $line->{$role}->{wire_name},";
print "lvl: $line->{$role}->{level},";
}
elsif($role =~ m/^output$/)
{
print "$role: $line->{$role}->{wire_name},";
print "lvl: $line->{$role}->{level},";
}
else
{
print "$role:$line->{$role},";
}
}
print "\n";
}
getc();
#if both inputs of the gates are processed, then calculate the level of the gate
#if only one of the inputs are processed, then add the gate to the end
my $num_gate_queue = scalar @gate_queue;
while ($num_gate_queue != 0)
{
$gate = pop(@gate_queue);
if($gate->{num_inputs}==1){
print "Number of gates in queue: $num_gate_queue";
if($gate->{processed_ip1}==1){
$gate->{processed}=$gate->{num_inputs};
}
}
if($gate->{processed}==$gate->{num_inputs}){
if($gate->{num_inputs}==2){
if(($gate->{input_1}->{level})>($gate->{input_2}->{level})){
$gate->{gate_level} = ($gate->{input_1}->{level});
}
else{
$gate->{gate_level} = ($gate->{input_2}->{level});
}
$gate->{gate_level}++;
$gate->{output}->{level}=$gate->{gate_level};
unshift(@input_list_struct,$gate->{output});
$num_gate_queue--;
$num_gates--;
print "Number of gates left $num_gates";
getc();
}
elsif($gate->{num_inputs}==1){
print "input level: $gate->{input_1}->{level}\n";
getc();
$gate->{gate_level} = $gate->{input_1}->{level};
$gate->{gate_level}++;
$gate->{output}->{level}=$gate->{gate_level};
print "$gate->{gate_name}: $gate->{gate_level}";
unshift(@input_list_struct,$gate->{output});
$num_gate_queue--;
$num_gates--;
print "Number of gates left $num_gates";
getc();
}
}
else{
# if($gate->{shifted}==0){
print "3. shifting $gate->{gate_name} to gate queue\n";
getc();
unshift(@gate_queue,$gate);
$num_gate_queue--;
#gates that are not processed because of lack of second input being processed are shifted in here, they need not be shifted again
$gate->{shifted}=1;
# }
}
}
print "updated input list\n";
for my $href ( @input_list_struct ) {
print "{ ";
for my $role ( keys %$href ) {
print "$role=$href->{$role} ";
}
print "}\n";
}
#the updated levels of the wires are present in input_list_struct
#update the fanouts of the gate with the levels from this struct
print "modifying gate: level input of gate\n";
for $gate(@gates){
for $inp (@input_list_struct){
$inp_test = $inp->{wire_name};
if(($gate->{input_1})->{wire_name} =~ m/$inp_test$/){
$gate->{input_1}->{level} = $inp->{level};
print "$gate->{gate_name}: $gate->{input_1}->{wire_name} - $gate->{input_1}->{level}\n";
}
if($gate->{num_inputs}!=1){
if(($gate->{input_2})->{wire_name} =~ m/$inp_test$/){
$gate->{input_2}->{level} = $inp->{level};
}
}
}
}
}
print "gate: level\n";
for $gate (@gates){
print "$gate->{gate_name}: $gate->{gate_level}\n";
}
Comments
Post a Comment