A library to generate parameterized Verilog code from C++.
Now you can construct Verilog modules in C++, use C++ syntax to dynamically generate complex connections, parameterize code, and finally get the Verilog code automatically generated.
The library contains all the gates implemented. Furthermore, a Carry Ripple Adder, a Carry Lookahead Adder (Pipelined and flat), and a Wallace Tree Multiplier (Pipelined) also come as part of the core. All modules are parameterized. Both dataflow and behavior models are supported.
To compile everything including, the example code src/main.cpp
run,
make all
Contributions are welcome to improve the usability and flexibility of the library. This code was written as a part of my coursework, and as of now, is very basic. Further developments are not likely to occur unless I am really bored of watching Netflix.
Every Verilog module exists as a Chip Object in C++. All modules derive from the Chip Parent. There are also wire objects, which is basically a string. The Chips can have any number of wires or other Chips inside them. The Verilog file is automatically generated by recursing through all sub Chips and wires. I have already implemented some basic logic gates. The The chip also provides other useful functions like transistor count and painless insertion of other sub Chips.
The following example (./src/example.cpp) shows how to create a module for computing OUT=A&(B^C):
#include <iostream>
#include <verilog.h>
#include <vector>
using namespace std;
class MyChip : public Chip{
public:
MyChip(string name, vector<wire> input_wires, wire output_wires);
};
MyChip::MyChip(string name, vector<wire>input_wires, wire output_wires){
/*------------------------------------------------------------------------------------------
We do the basic setups.
This chip takes multiple inputs and has only one output. However, our chip objects require setup as various inputs and multiple outputs. So we push the outputs to the null vector.
------------------------------------------------------------------------------------------*/
this->name = name;
this->inputs = input_wires;
this->outputs.push_back(output_wires);
/*------------------------------------------------------------------------------------------
We need to tell the Chip Object, which ones are our inputs and our outputs.
------------------------------------------------------------------------------------------*/
this->declare("A", CHIP_INPUTS);
this->declare("B", CHIP_INPUTS);
this->declare("C", CHIP_INPUTS);
this->declare("OUT", CHIP_OUTPUTS);
/*------------------------------------------------------------------------------------------
Now we do the wiring part. We need to create a wire to store temp outputs from XOR. Then we create instances of an XOR and an AND gate. Basic logic gates are already implemented.
------------------------------------------------------------------------------------------*/
wire temp_wire = "temp_wire";
XOR my_xor_gate("MyChipSubXOR1", // Name
{"B", "C"}, // Inputs
temp_wire); // Outputs
AND my_and_gate("MyChipSubAND1",
{temp_wire, "A"},
"OUT");
/*------------------------------------------------------------------------------------------
Then we attach these individual instances to the parent chip.
------------------------------------------------------------------------------------------*/
this->add_wire(temp_wire);
this->add_submodule(my_xor_gate);
this->add_submodule(my_and_gate);
/*------------------------------------------------------------------------------------------
Now we automatically generate the module definitions using the auto_gen() function.
------------------------------------------------------------------------------------------*/
this->definition = this->auto_gen("module MyChip");
/*------------------------------------------------------------------------------------------
Now we need to specify the syntax to instantiate this chip. For example :
MyChip my_instance_1("instance_name", "my_a", "my_b", "my_c", "my_out");
}
------------------------------------------------------------------------------------------*/
this->generate = "MyChip " + this->name + " (" + this->inputs.at(0) + ", " + this->inputs.at(1) + ", "
+ this->inputs.at(2) + ", " + this->outputs.at(0) + ");";
}
int main(){
MyChip instance_1("my_instance_1",
{"input_1", "input_2", "input_3"},
"output");
cout<<instance_1.generate_verilog();
cout<<"\n--------------------------------------------------\n";
cout<<instance_1.generate<<"\n";
}