Adv. Verilog Parametric Code Snippets

Who needs those fangled Scala-HDLs, when they can use generate in Verilog2001.

— Sun Tzu

TOC / Nov.25.2021

  1. Parallel Combinational Maxima Function
  2. SAR Controller
  3. CLA
  4. Combinational Leading Zero Counter
  5. Barrel Shifter

Key Points:

  • Recursion is possible
  • Functional programming mindset helps (dig up your copy of SICP!)
  • Use the netlist optimization functionality of your toolchain effectively (we can safely assume that all unused outputs, and all constant inputs can be optimized-out post synthesis)

  1. Parallel Combinational Maxima Function
// max_parallel
//
// Generates a parallel combinational maximum value function 
// Synthesizable
module max_parallel #(
    parameter NARGLOG = 5,
    parameter ISIZE   = 32
)(
    input [ISIZE-1:0]           A [2**NARGLOG-1:0],
    output reg [NARGLOG-1:0]    maxn,
    output reg [ISIZE-1:0]      maxval
);
    wire [ISIZE-1:0]   t  [2**(NARGLOG+1)-1:0];
    wire [NARGLOG-1:0] tn [2**(NARGLOG+1)-1:0];
    assign t[2**(NARGLOG+1)-1:2**NARGLOG] = A;
    assign maxval = t [1];
    assign maxn   = tn[1];
    // t[0] and tn[0] are unused.
    genvar gi, gj;
    generate
    for(gi=0;gi<2**NARGLOG;gi=gi+1) begin : gen_assign_cell_id
        assign tn[2**NARGLOG-1+gi] = gi;
    end
    
    for(gi=0;gi<NARGLOG;gi=gi+1) begin : gen_cell_layer
        for(gj=0;gj<2**gi;gj=gj+1) begin : gen_cells
            integer bias = 2**gi;
            max2 umax(
                .a0     (t [bias+gj+bias]),
                .maxn0  (tn[bias+gj+bias]),
                .a1     (t [bias+gj+bias*2]),
                .maxn1  (tn[bias+gj+bias*2]),
                .maxval (t [2**gi+gj]),         // VCS doesn't like this
                .maxn   (tn[2**gi+gj])
            );
        end
    end
    endgenerate
endmodule

// max2
//
//
module max2 #(
    parameter NLOGMAX = 5,
    parameter ISIZE   = 32
)(
    input  [ISIZE-1:0]      a0,
    input  [NLOGMAX-1:0]    maxn0,
    input  [ISIZE-1:0]      a1,
    input  [NLOGMAX-1:0]    maxn1,
    output [ISIZE-1:0]      maxval,
    output [NLOGMAX-1:0]    maxn
);
    wire   maxsel = (a1>a0);
    assign maxsel ? maxn1 : maxn0;
    assign maxval ? a1    : a0;
endmodule

2.SAR Controller

module sarcell #(parameter init = 0)(
    input       start_n,
    input       clk,
    input       a,
    input       shift,
    input       en_n,
    output reg  k
    );
    reg d;
    always @ * begin
        casex ({en_n, k})
            2'b1x:      d = k;
            2'b01:      d = a;
            2'b00:      d = shift;
            default:    d = 1'bx;
        endcase
    end
    always @ (posedge clk or negedge start_n) begin
        if(!start_n)    k <= init;
        else            k <= d;
    end

endmodule // sarcell

module sar_test #(parameter DEPTH = 8)(
    input               start_n,
    input               comp,
    input               clk_sar,
    input               locked,
    output [DEPTH:0]    bits,
    output              stop
    );

    wire [DEPTH:0]  en_n;
    wire term_q;

    DFF_ENAR cell_termination(
        .D  (|{bits[0], term_q, locked}),
        .CLK(clk_sar),
        .EN (1),
        .RST(!start_n),
        .QP (term_q)
        );

    sarcell cell_0 (
        .start_n(start_n),
        .clk    (clk_sar),
        .a      (comp),
        .shift  (bits[1]),
        .en_n   (en_n[0]),
        .k      (bits[0])
    );
    genvar i;
    generate
        for(i=1; i<DEPTH; i=i+1) begin: gen_sarcell
            sarcell cell_i (
                .start_n(start_n),
                .clk    (clk_sar),
                .a      (comp),
                .shift  (bits[i+1]),
                .en_n   (en_n[i]),
                .k      (bits[i])
            );
            assign en_n[i] = |{bits[i-1], en_n[i-1]};
        end
    endgenerate
    assign en_n[DEPTH] = |{bits[DEPTH-1], en_n[DEPTH-1]};
    assign en_n[0] = stop;
    assign stop = term_q | locked;

    sarcell #(1) cell_last (
        .start_n(start_n),
        .clk    (clk_sar),
        .a      (comp),
        .shift  (1),
        .en_n   (en_n[DEPTH]),
        .k      (bits[DEPTH])
    );

endmodule // sar_test

 

3. CLA

// fpga4student.com FPGA projects, Verilog projects, VHDL projects 
// Verilog code for carry look-ahead adder
module cla_adder #(
	parameter DATA_WID = 32
)(
	input wire  [DATA_WID - 1:0]  in1,
	input wire  [DATA_WID - 1:0]  in2,
	input wire                    carry_in,
	output wire [DATA_WID - 1:0]  sum,
	output wire                   carry_out
);
	//assign {carry_out, sum} = in1 + in2 + carry_in;
	wire [DATA_WID - 1:0] gen;
	wire [DATA_WID - 1:0] pro;
	wire [DATA_WID:0] carry_tmp;
	genvar j, i;
	generate
		//assume carry_tmp in is zero
		assign carry_tmp[0] = carry_in;
		//carry generator
		for(j = 0; j < DATA_WID; j = j + 1) begin: carry_generator
			assign gen[j] = in1[j] & in2[j];
			assign pro[j] = in1[j] | in2[j];
			assign carry_tmp[j+1] = gen[j] | pro[j] & carry_tmp[j];
		end 
		//carry out 
		assign carry_out = carry_tmp[DATA_WID];
		//calculate sum 
		//assign sum[0] = in1[0] ^ in2 ^ carry_in;
		for(i = 0; i < DATA_WID; i = i+1) begin: sum_without_carry
			assign sum[i] = in1[i] ^ in2[i] ^ carry_tmp[i];
		end 
	endgenerate 
endmodule

4. Combinational Leading Zero Counter

// Counting Lead Zero using a tree structure
// https://electronics.stackexchange.com/questions/196914/verilog-synthesize-high-speed-leading-zero-count
module count_lead_zero #(
    parameter W_IN = 32,           // Must be power of 2, >=2
    parameter W_OUT = $clog2(W_IN) // Let this default
) (
    input wire  [W_IN-1:0] in,
    output wire [W_OUT-1:0] out
);

generate
	if (W_IN == 2) begin : gen_base
		assign out = !in[1];
	end else begin : gen_recurse
		wire [W_OUT-2:0] half_count;
		wire [W_IN / 2-1:0] lhs = in[W_IN / 2 +: W_IN / 2];
		wire [W_IN / 2-1:0] rhs = in[0        +: W_IN / 2];
		wire left_empty = ~|lhs;

		count_lead_zero #(
			.W_IN (W_IN / 2)
		) inner (
			.in  (left_empty ? rhs : lhs),
			.out (half_count)
		);
		assign out = {left_empty, half_count};
	end
endgenerate

endmodule /* count_lead_zero */

5. Barrel Shifter

// Parametrized Barrel Shifter : Right Shift
module bsr #(
	parameter SWIDTH = 5
)(
	input [(2**SWIDTH)-1:0]     din,
	input [SWIDTH-1:0]          s,
	input                       filler, // 0:        SRL Logic  Shift Right
										// din[MSB]: SRA Arith. Shift Right (preserve sign)
	output [(2**SWIDTH)-1:0]    dout
);

wire [(2**SWIDTH)-1:0]	temp [SWIDTH:0];

assign temp[0] = din;
assign dout    = temp[SWIDTH];

genvar gi;
generate
	for(gi=0;gi<SWIDTH;gi=gi+1) begin : gen_brshift
		assign temp[gi+1] = s[gi] ? \
			{{(2**gi){filler}},temp[gi]>>(2**gi)} : temp[gi];
	end
endgenerate

endmodule   /* bsr */

// Parametrized Barrel Shifter: Left Shift
module bsl #(
	parameter SWIDTH = 5
)(
	input [(2**SWIDTH)-1:0]     din,
	input [SWIDTH-1:0]          s,
	input                       filler, // 0: SLL Logic  Shift Left
	output [(2**SWIDTH)-1:0]    dout
);

wire [(2**SWIDTH)-1:0]	temp [SWIDTH:0];

assign temp[0] = din;
assign dout    = temp[SWIDTH];

genvar gi;
generate
	for(gi=0;gi<SWIDTH;gi=gi+1) begin : gen_brshift
		assign temp[gi+1] = s[gi] ? \
			{temp[gi],{(2**gi){filler}}} : temp[gi];
	end
endgenerate

endmodule   /* bsl */

Leave a Reply