You Want a Perl Script to Simplify Verilog Code

Almost at the end of 2023... openAI wants you to pay for using their Web UI to access GPT-4 - like $20/month - probably worth it. But.. first off - should you move to GPT-4? Yes, not worth spending time on 3.5 anymore.. You're wasting time. Then, is Bard anywhere near chatGPT? Nope. Sorry. It can do some things, but they have a lot of catching up to do.. Worst of all, chatGPT (just 3.5) was able to fix Bard's outputs.. One regex for example : \s+(\w+)\s+\( went to \s+(\w+)\s*\( for a very good reason that Bard didn't see..

So, what did I use to get this built with GPT-4?  Typingmind.com - thanks Arun. And a paid openAI key - pay as you go - so it's about a cent for 1000 tokens. In an hour of intensive use, I ran up about 12 cents - so you can judge :)

What was I trying to do? Flatten verilog code - you have a design made up of multiple instances of modules that are connected by wires. Can we flatten this design into a single module so that a script can then go through and find out what input ports a specified output port depends on?

Bard struggled with the flattening thing - and partly it was my own fault - I had an error in my verilog. But, this also threw it off :

Both these are valid module definitions - pay attention to the port declarations :

module nd(input a, input b, output out);
    nand(out, a, b );
endmodule

module nd(a, b, out);
    input a;
    input b;
    output out;
    nand(out, a, b );
endmodule

You'd prefer to restrict the input format as much as possible to simplify the analysis. Right? So why not a perl script that can take the second one and spit out the first? I used to be able to do stuff like that in my sleep 20 years ago. Rusty now. I figured this one would be a breeze for the leading LLM. Boy was I wrong. Prompt engineering is work baby.. The saddest thing is, after nine iterations telling it what was broken (it kept fixing and breaking - what was very helpful was having a simple test-case and being able to show it its output and the desired output) - I still don't know what the perfect starting prompt would be to get this one correct right off the bat. I'm sure there are people out there who can hack this though.. They can really harness LLM coding power.

So, I started off with :

Can you give me a perl script that can take a verilog code file and give a new version in which all the port direction (input, output, inout) declarations are inline, rather than on separate lines? For example :

original verilog code : 

module nd(input a, input b, output out);
    nand(out, a, b );
endmodule

module xor_gate_nand(a, b, c, d, out, output out2);
 input a, b;
 output out;
 
 // rest of the xor_gate_nand module definition

revised verilog code : 

module nd(input a, input b, output out);
    nand(out, a, b );
endmodule

module xor_gate_nand(input a, input b, input c, input d, output out, output out2);

 // rest of the xor_gate_nand module definition

And, finally, after strugging with 3.5 and Bard, settled on :


We want to take something like :

module nd(a, b, out);
    input a;
    input b;
    output out;
    nand(out, a, b );
endmodule

Where the port names within parantheses don't have direction (input, output, inout) information and revise it to look like : 

module nd(input a, input b, output out);
    nand(out, a, b );
endmodule

Note that 

module nd(
input a, 
input b, 
output out);
    nand(out, a, b );
endmodule

is already in the desired format - whitespace can include newlines. 

So, we want port name and direction together in one shot. 

To accomplish this, when we read the input file, and encounter the module keyword, we now enter a state where we start building up a list of pins. For each pin that does not have direction information, we add that pin to a list of needy pins. After the closing right paranthesis, we now look for direction information which could be of the form :

input a, b, c; 

Where the direction information for three pins has been specified on a single line.

If, after the line containing the word module, we encounter a closing right paranthesis and there are some pins without direction information, then we expect every non blank line to start with a direction word (input, output, inout) and specify the names of one or more pins that this direction applies to.

When we have have direction information for all pins for this module, we update the module declaration, print it and move on to looking for the next module.

Can you give me a perl script to do that? Assume that the input file is the first argument.


The moral of the story is that, for coding, you want to be specific and sort of, tell it how to think. That helps, I think. 

And the final script (click to select, then CTRL-C to copy): 

#!/usr/bin/perl
use strict;
use warnings;

my $filename = $ARGV[0];                  # input file from command line argument
open my $fh, '<', $filename or die "Could not open '$filename' $!\n";

my $module_name = "";
my %pin_directions = ();
my @lines = ();
my @pin_order = ();
my $inside_module = 0;

while (my $line = <$fh>) {
    chomp $line;
    if ( $line =~ /^module\s+(\w+)\s*\((.*?)\)\;/) {
        $inside_module = 1;
        $module_name = $1;
        my @pins = split /,/, $2;
        foreach my $pin (@pins) {
            $pin =~ s/^\s+|\s+$//g; # trim whitespace
            $pin_directions{$pin} = "";
            push @pin_order, $pin;
        }

    } elsif($line =~ /^\s*(input|output|inout)\s+(.*?);/) {
        my $direction = $1;
        my @pins = split /,/, $2;
        foreach my $pin (@pins) {
            $pin =~ s/^\s+|\s+$//g; # trim whitespace
            if(exists $pin_directions{$pin}) {
                $pin_directions{$pin} = $direction;
            }
        }

    } elsif($line =~ /^endmodule/ || eof) {
        if($inside_module) {
            my $new_module_line = "";
            foreach my $pin (@pin_order) {
                my $direction = $pin_directions{$pin};
                $new_module_line .= "$direction $pin, ";
            }
            $new_module_line =~ s/, $//; # remove the trailing comma and space
            print "module $module_name ($new_module_line);\n";
            print join("\n", @lines);
            print "\n$line\n";

            $module_name = "";
            %pin_directions = ();
            @lines = ();
            @pin_order = ();
            $inside_module = 0;
        }

    } else {
        push @lines, $line;
    }
}

close $fh;

Comments

Popular posts from this blog

How You Can Solve Lumosity's Pet Detective Puzzle with chatGPT and OpenCV Without Writing a Single Line of Code

Modern Magic - How Do They Do It?

Why Does chatGPT Fail Utterly with this One?