Using Mako templates language for hardware design was an interesting experiment. It was definitely a fun hack. I am turning my attention away from this pet project to a new tool developed
by engineers at Berkeley: Chisel.
Here is a link to find out more: https://chisel.eecs.berkeley.edu/
Wednesday, November 12, 2014
Wednesday Night Hack #8 - Mako for Verilog, Moving on ...
Wednesday, October 29, 2014
Wednesday Night Hack #7 - More Experiments with Mako for Verilog
This is turning out to be a very fun experiment. In about 150 lines of Python code, I have put together a very nice tool for Verilog code generation. If there is interest in the source code, please send me an e-mail.
On an unrelated note, I recently stumbled upon the following website: http://regex101.com/#python. It is a wonderfully written online regex tester, 5/5 stars and highly recommended.
Here is the template code :
top.v.mako :
<%! from vmako import connect, ev,instance,log2 %>
module top;
bit clk = 0;
## instantiate 2x 'w'-bit wide barrel shifters
% for i in range(0, 2):
## define local variable inst
<% inst = 'u{}_bshf_{}'.format(i,w) %>
${instance('$HOME/raid/vmako/templates/bshift.v.mako',
inst,
w=w
)}
## connect dest <- src
${connect((inst, 'clk'), ('', 'clk'))}
% endfor
## example connect statement between modules
${connect(('u1_bshf_'+str(w), 'in'), ('u0_bshf_'+str(w), 'out'))}
endmodule
bshift.v.mako :
<%! from vmako import connect,ev,instance,log2 %>
module bshift_${w} (
input clk,
input [${ev(w-1)}:0] in,
input [${ev(log2(w)-1)}:0] cnt,
output reg [${ev(w-1)}:0] out
);
% for i in range(1, w):
wire [${ev(w-1)}:0] out_${i} = {in[${ev(w-i-1)}:0], in[${ev(w-1)}:${ev(w-i)}]};
% endfor
always @(*)
case (cnt)
% for i in range(1, w):
${i}: out = out_${i};
% endfor
default: out = in;
endcase
${instance('$HOME/raid/vmako/templates/dff.v.mako',
"u_dff",
w=w
)}
endmodule
dff.v.mako :
<%! from vmako import ev,log2 %>
module dff_${w} (
input clk,
input [${ev(w-1)}:0] d,
output reg [${ev(w-1)}:0] q
);
always @(posedge clk)
q <= d;
endmodule
Here is the generated code :
top.v :
module top;
bit clk = 0;
// ---- instance:u0_bshf_4 [begin] ----
wire u0_bshf_4_clk;
wire [3:0] u0_bshf_4_in;
wire [1:0] u0_bshf_4_cnt;
wire [3:0] u0_bshf_4_out;
bshift_4 u0_bshf_4 (
.clk(u0_bshf_4_clk)
,.in(u0_bshf_4_in)
,.cnt(u0_bshf_4_cnt)
,.out(u0_bshf_4_out)
);
// ---- instance:u0_bshf_4 [end] ----
// connect:dest=('u0_bshf_4', 'clk') src=('', 'clk')
assign u0_bshf_4_clk = clk;
// ---- instance:u1_bshf_4 [begin] ----
wire u1_bshf_4_clk;
wire [3:0] u1_bshf_4_in;
wire [1:0] u1_bshf_4_cnt;
wire [3:0] u1_bshf_4_out;
bshift_4 u1_bshf_4 (
.clk(u1_bshf_4_clk)
,.in(u1_bshf_4_in)
,.cnt(u1_bshf_4_cnt)
,.out(u1_bshf_4_out)
);
// ---- instance:u1_bshf_4 [end] ----
// connect:dest=('u1_bshf_4', 'clk') src=('', 'clk')
assign u1_bshf_4_clk = clk;
// connect:dest=('u1_bshf_4', 'in') src=('u0_bshf_4', 'out')
assign u1_bshf_4_in = u0_bshf_4_out;
endmodule
bshift.v :
module bshift_4 (
input clk,
input [3:0] in,
input [1:0] cnt,
output reg [3:0] out
);
wire [3:0] out_1 = {in[2:0], in[3:3]};
wire [3:0] out_2 = {in[1:0], in[3:2]};
wire [3:0] out_3 = {in[0:0], in[3:1]};
always @(*)
case (cnt)
1: out = out_1;
2: out = out_2;
3: out = out_3;
default: out = in;
endcase
// ---- instance:u_dff [begin] ----
wire u_dff_clk;
wire [3:0] u_dff_d;
wire [3:0] u_dff_q;
dff_4 u_dff (
.clk(u_dff_clk)
,.d(u_dff_d)
,.q(u_dff_q)
);
// ---- instance:u_dff [end] ----
endmodule
dff.v :
module dff_4 (
input clk,
input [3:0] d,
output reg [3:0] q
);
always @(posedge clk)
q <= d;
endmodule
On an unrelated note, I recently stumbled upon the following website: http://regex101.com/#python. It is a wonderfully written online regex tester, 5/5 stars and highly recommended.
Here is the template code :
top.v.mako :
<%! from vmako import connect, ev,instance,log2 %>
module top;
bit clk = 0;
## instantiate 2x 'w'-bit wide barrel shifters
% for i in range(0, 2):
## define local variable inst
<% inst = 'u{}_bshf_{}'.format(i,w) %>
${instance('$HOME/raid/vmako/templates/bshift.v.mako',
inst,
w=w
)}
## connect dest <- src
${connect((inst, 'clk'), ('', 'clk'))}
% endfor
## example connect statement between modules
${connect(('u1_bshf_'+str(w), 'in'), ('u0_bshf_'+str(w), 'out'))}
endmodule
bshift.v.mako :
<%! from vmako import connect,ev,instance,log2 %>
module bshift_${w} (
input clk,
input [${ev(w-1)}:0] in,
input [${ev(log2(w)-1)}:0] cnt,
output reg [${ev(w-1)}:0] out
);
% for i in range(1, w):
wire [${ev(w-1)}:0] out_${i} = {in[${ev(w-i-1)}:0], in[${ev(w-1)}:${ev(w-i)}]};
% endfor
always @(*)
case (cnt)
% for i in range(1, w):
${i}: out = out_${i};
% endfor
default: out = in;
endcase
${instance('$HOME/raid/vmako/templates/dff.v.mako',
"u_dff",
w=w
)}
endmodule
dff.v.mako :
<%! from vmako import ev,log2 %>
module dff_${w} (
input clk,
input [${ev(w-1)}:0] d,
output reg [${ev(w-1)}:0] q
);
always @(posedge clk)
q <= d;
endmodule
Here is the generated code :
top.v :
module top;
bit clk = 0;
// ---- instance:u0_bshf_4 [begin] ----
wire u0_bshf_4_clk;
wire [3:0] u0_bshf_4_in;
wire [1:0] u0_bshf_4_cnt;
wire [3:0] u0_bshf_4_out;
bshift_4 u0_bshf_4 (
.clk(u0_bshf_4_clk)
,.in(u0_bshf_4_in)
,.cnt(u0_bshf_4_cnt)
,.out(u0_bshf_4_out)
);
// ---- instance:u0_bshf_4 [end] ----
// connect:dest=('u0_bshf_4', 'clk') src=('', 'clk')
assign u0_bshf_4_clk = clk;
// ---- instance:u1_bshf_4 [begin] ----
wire u1_bshf_4_clk;
wire [3:0] u1_bshf_4_in;
wire [1:0] u1_bshf_4_cnt;
wire [3:0] u1_bshf_4_out;
bshift_4 u1_bshf_4 (
.clk(u1_bshf_4_clk)
,.in(u1_bshf_4_in)
,.cnt(u1_bshf_4_cnt)
,.out(u1_bshf_4_out)
);
// ---- instance:u1_bshf_4 [end] ----
// connect:dest=('u1_bshf_4', 'clk') src=('', 'clk')
assign u1_bshf_4_clk = clk;
// connect:dest=('u1_bshf_4', 'in') src=('u0_bshf_4', 'out')
assign u1_bshf_4_in = u0_bshf_4_out;
endmodule
bshift.v :
module bshift_4 (
input clk,
input [3:0] in,
input [1:0] cnt,
output reg [3:0] out
);
wire [3:0] out_1 = {in[2:0], in[3:3]};
wire [3:0] out_2 = {in[1:0], in[3:2]};
wire [3:0] out_3 = {in[0:0], in[3:1]};
always @(*)
case (cnt)
1: out = out_1;
2: out = out_2;
3: out = out_3;
default: out = in;
endcase
// ---- instance:u_dff [begin] ----
wire u_dff_clk;
wire [3:0] u_dff_d;
wire [3:0] u_dff_q;
dff_4 u_dff (
.clk(u_dff_clk)
,.d(u_dff_d)
,.q(u_dff_q)
);
// ---- instance:u_dff [end] ----
endmodule
dff.v :
module dff_4 (
input clk,
input [3:0] d,
output reg [3:0] q
);
always @(posedge clk)
q <= d;
endmodule
Wednesday, October 15, 2014
Wednesday Night Hack #6 - Verilog Code Generation using Python and Mako
I spent some time this evening playing with Python and Mako for the purposes of Verilog code generation. The combination of tools is pretty sweet if you ask me. Here is a worked out example for a parameterizable barrel shifter.
Mako template:
<%!
import math
def log2(x): return int(math.log(x, 2))
def e(x): return eval(str(x))
%>
module bshift_w${w} (
input [${e(w-1)}:0] in,
input [${e(log2(w)-1)}:0] shift,
output reg [${e(w-1)}:0] out
);
% for i in range(1, w):
wire [${e(w-1)}:0] out_${i} = {in[${e(w-i-1)}:0], in[${e(w-1)}:${e(w-i)}]};
% endfor
always @* begin
out = in;
case (shift)
% for i in range(1, w):
${i}: out = out_${i};
% endfor
endcase
end
endmodule
Verilog output (w=4):
Mako template:
<%!
import math
def log2(x): return int(math.log(x, 2))
def e(x): return eval(str(x))
%>
module bshift_w${w} (
input [${e(w-1)}:0] in,
input [${e(log2(w)-1)}:0] shift,
output reg [${e(w-1)}:0] out
);
% for i in range(1, w):
wire [${e(w-1)}:0] out_${i} = {in[${e(w-i-1)}:0], in[${e(w-1)}:${e(w-i)}]};
% endfor
always @* begin
out = in;
case (shift)
% for i in range(1, w):
${i}: out = out_${i};
% endfor
endcase
end
endmodule
Verilog output (w=4):
module bshift_w4 (
input [3:0] in,
input [1:0] shift,
output reg [3:0] out
);
wire [3:0] out_1 = {in[2:0], in[3:3]};
wire [3:0] out_2 = {in[1:0], in[3:2]};
wire [3:0] out_3 = {in[0:0], in[3:1]};
always @* begin
out = in;
case (shift)
1: out = out_1;
2: out = out_2;
3: out = out_3;
endcase
end
endmodule
Wednesday, September 17, 2014
Wednesday Night Hack #5 - Update
Life happened. We bought a house in Silicon Valley. Work ramped up, code freeze and verification complete of next generation Adreno GPU is on the horizon (being careful to be intentionally vague here). Thoroughly enjoyed the end of summer by camping and even attended my first personal development workshop weekend.
Last week, I checked in some code to my GIT repository https://bitbucket.org/ecote. I released an updated version of my build and run flow (barf) and associated workspace generator (wsgen). An example BARF script has also been released: analyze.barf. At the moment, I am not motivated to document the operation of the code or describe any use cases. The main reason for this is because I do not know the right forum to publish the work (blog, conference paper/presentation, YouTube, etc.). In any case, these small pet projects are about having fun, no rush ...
Last week, I checked in some code to my GIT repository https://bitbucket.org/ecote. I released an updated version of my build and run flow (barf) and associated workspace generator (wsgen). An example BARF script has also been released: analyze.barf. At the moment, I am not motivated to document the operation of the code or describe any use cases. The main reason for this is because I do not know the right forum to publish the work (blog, conference paper/presentation, YouTube, etc.). In any case, these small pet projects are about having fun, no rush ...
Tuesday, July 15, 2014
Post-Vacation Update
It seems I have not posted in about 1 month. We are in a critical phase of the project at work and my evenings have largely been consumed by my day-job responsibilities. I also took some vacation.
Since the last post, I have been playing around with a few ideas. No concrete idea for my pet project yet. I also read the two books I wrote about here, I have also re-opened The Developer's Code - What Real Programmers Do. Great book, highly recommended. The author does an outstanding job of condensing years of experience and wisdom into 50 small essays about software development.
Essay 17 in that book struck a chord with me. The essay is titled: "Just Say "No" to the Pet Project". Here's a great quote from is: "Pet project fail when there are no time constraints and nothing is on the line if we don't succeed". Certainly food for thought...
One idea I had was to revisit buildroot scripts to generate an embedded Linux system and run the system on my MIPS CPU design. I was almost successful with this years ago, but dropped the idea because it wasn't a needed for the work I was doing at the time. I am interested in seeing how the scripts have evolved over the years. I did try running the buildroot scripts running on Cygwin but faced issues. I could have used a Linux virtual machine, but instead went ahead and bought some parts to put together an inexpensive Linux box / home file server. The parts should be arriving later this week.
More later ...
Since the last post, I have been playing around with a few ideas. No concrete idea for my pet project yet. I also read the two books I wrote about here, I have also re-opened The Developer's Code - What Real Programmers Do. Great book, highly recommended. The author does an outstanding job of condensing years of experience and wisdom into 50 small essays about software development.
Essay 17 in that book struck a chord with me. The essay is titled: "Just Say "No" to the Pet Project". Here's a great quote from is: "Pet project fail when there are no time constraints and nothing is on the line if we don't succeed". Certainly food for thought...
One idea I had was to revisit buildroot scripts to generate an embedded Linux system and run the system on my MIPS CPU design. I was almost successful with this years ago, but dropped the idea because it wasn't a needed for the work I was doing at the time. I am interested in seeing how the scripts have evolved over the years. I did try running the buildroot scripts running on Cygwin but faced issues. I could have used a Linux virtual machine, but instead went ahead and bought some parts to put together an inexpensive Linux box / home file server. The parts should be arriving later this week.
More later ...
Subscribe to:
Posts (Atom)