This document is a work in progress.
At work, we had a large spreadsheet of 140+ instructions, signals, opcodes, and comments that needed to be turned into a decoder and other things, so instead of manually creating the verilog files, I used a python script and mako to generate them. It was pretty easy and straightforward to do, so I made this guide to share the basics of how to use mako to save yourself some time. You can read further or just jump into the examples I've included in this repo.
Edmond Cote has a tool for verilog templating using mako here that might be helpful, but I ended up not using it because I was doing one-off file generations.
I'm using Python 3.7, mako docs also state Python 2.7 and Python 3.5+ are supported.
$ pip install mako
Official mako docs here.
Item | Description |
---|---|
## comment |
Comments in mako are denoted with '##' |
<%! ## python module level code here %> |
Use these for imports and function declaration |
<% ## python render level code here %> |
Use these for other python code, stuff that needs the variables you pass into the mako render function |
\ |
Every line not using the mako python wrappers/control structures will get rendered, and sometimes you'll have unwanted newlines due to how you format your <% %> 's. Using \ at the end of any line will ignore the newline character before continuing to the next line. |
${variable_name} |
Expression escaping, access the variables from your python blocks |
% for i in range(5): ${i} \ % endfor |
For loop that outputs 0 1 2 3 4 after being rendered. Mako "control structures" are denoted by the % marker and the python expression, and closed by % and end<name> where <name> is the name of the expression, in this case % endfor |
% if example_var == True : It's true! % else : Nope % endif |
Example of if-else statement. You can do % while % endwhile , layered if/elif/else statements and try/except too. |
If you have an instance that you want to generate 'n' times, you can do so by creating a file, like parameterize_inst.v.mako
, that looks something like this:
<%!
import math
from collections import deque
def log2(x): return int(math.ceil(math.log(x, 2)))
%>
# THIS CODE WAS AUTO GENERATED BY 'parameterize_inst.v.mako'
module example (
input clk
input rst
input i_ex
output o_ex
)
% for i in range (n):
//------------------------
// Instance ${i}
// Input-Output declarations
reg [31:0] EXAMPLE_${i};
...
% endfor
To run, cd to the directory containing example.v.mako
, and enter:
$ python3 -c "from mako.template import Template; import sys; sys.stdout.write(Template(filename='parameterize_inst.v.mako').render(n=4))" > example_output.v
Change the value of n
in render(n=4)
to change the number of instances.
After it has run, the generated file, example_output.v
should be in the same directory.
Output should be:
# THIS CODE WAS AUTO GENERATED BY 'parameterize_inst.v.mako'
module example (
input clk
input rst
input i_ex
output o_ex
)
//------------------------
// Instance 0
// Input-Output declarations
reg [31:0] EXAMPLE_0;
...
//------------------------
// Instance 1
// Input-Output declarations
reg [31:0] EXAMPLE_1;
...
//------------------------
// Instance 2
// Input-Output declarations
reg [31:0] EXAMPLE_2;
...
//------------------------
// Instance 3
// Input-Output declarations
reg [31:0] EXAMPLE_3;
...