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