summaryrefslogtreecommitdiff
path: root/tests/simple/multiplier.v
blob: 3c0aa1fcecc22f750b2a6a3ad7f874344aa73a43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Via http://www.edaplayground.com/s/6/591
// stackoverflow 20556634
// http://stackoverflow.com/questions/20556634/how-can-i-iteratively-create-buses-of-parameterized-size-to-connect-modules-also

// Code your design here
`define macro_args
`define indexed_part_select

module Multiplier_flat #(parameter M = 4, parameter N = 4)(
input [M-1:0] A, //Input A, size M
input [N-1:0] B, //Input B, size N
output [M+N-1:0] P );  //Output P (product), size M+N

/* Calculate LSB using Wolfram Alpha
 N==3 : http://www.wolframalpha.com/input/?i=0%2C+4%2C+9%2C+15%2C+...
 N==4 : http://www.wolframalpha.com/input/?i=0%2C+5%2C+11%2C+18%2C+26%2C+35%2C+...
 N==5 : http://www.wolframalpha.com/input/?i=0%2C+6%2C+13%2C+21%2C+30%2C+...
 */
`ifdef macro_args
// initial $display("Use Macro Args");
`define calc_pp_lsb(n) (((n)-1)*((n)+2*M)/2)
//`define calc_pp_msb(n) (`calc_pp_lsb(n+1)-1)
`define calc_pp_msb(n) ((n**2+(2*M+1)*n-2)/2)
//`define calc_range(n) `calc_pp_msb(n):`calc_pp_lsb(n)
`define calc_pp_range(n) `calc_pp_lsb(n) +: (M+n)

wire [`calc_pp_msb(N):0] PP;
assign PP[`calc_pp_range(1)] = { 1'b0 , { A & {M{B[0]}} } };
assign P = PP[`calc_pp_range(N)];
`elsif indexed_part_select
// initial $display("Use Indexed Part Select");
localparam MSB = (N**2+(2*M+1)*N-2)/2;
wire [MSB:0] PP;
assign PP[M:0] = { 1'b0 , { A & {M{B[0]}} } };
assign P = PP[MSB -: M+N];
`else
// initial $display("Use Worst Case");
localparam MSB = (N**2+(2*M+1)*N-2)/2;
wire [MSB:0] PP;
assign PP[M:0] = { 1'b0 , { A & {M{B[0]}} } };
assign P = PP[MSB : MSB+1-M-N];
`endif

genvar i;
generate
for (i=1; i < N; i=i+1)
begin: addPartialProduct
    wire [M+i-1:0] gA,gB,gS;
    wire Cout;
    assign gA = { A & {M{B[i]}} , {i{1'b0}} };
    `ifdef macro_args
    assign gB = PP[`calc_pp_range(i)];
    assign PP[`calc_pp_range(i+1)] = {Cout,gS};
    `elsif indexed_part_select
    assign gB = PP[(i-1)*(i+2*M)/2 +: M+i];
    assign PP[i*((i+1)+2*M)/2 +: M+i+1] = {Cout,gS};
    `else
    localparam LSB = (i-1)*(i+2*M)/2;
    localparam MSB = (i**2+(2*M+1)*i-2)/2;
    localparam MSB2 = ((i+1)**2+(2*M+1)*(i+1)-2)/2;
    assign gB = PP[MSB : LSB];
    assign PP[ MSB2 : MSB+1] = {Cout,gS};
    `endif
    RippleCarryAdder#(M+i) adder( .A(gA), .B(gB), .S(gS), .Cin (1'b0), .Cout(Cout) );
end
endgenerate

`ifdef macro_args
// Cleanup global space
`undef calc_pp_range
`undef calc_pp_msb
`undef calc_pp_lsb
`endif
endmodule

module Multiplier_2D #(parameter M = 4, parameter N = 4)(
input [M-1:0] A, //Input A, size M
input [N-1:0] B, //Input B, size N
output [M+N-1:0] P );  //Output P (product), size M+N

wire [M+N-1:0] PP [N-1:0];

// Note: bits PP[0][M+N-1:M+1] are never used. Unused bits are optimized out during synthesis
//assign PP[0][M:0] = { {1'b0} , { A & {M{B[0]}} } };
//assign PP[0][M+N-1:M+1] = {(N-1){1'b0}}; // uncomment to make probing readable
assign PP[0] = { {N{1'b0}} , { A & {M{B[0]}} } };
assign P = PP[N-1];

genvar i;
generate
for (i=1; i < N; i=i+1)
begin: addPartialProduct
    wire [M+i-1:0] gA,gB,gS; wire Cout;
    assign gA = { A & {M{B[i]}} , {i{1'b0}} };
    assign gB = PP[i-1][M+i-1:0];
    //assign PP[i][M+i:0] = {Cout,gS};
    //if (i+1<N) assign PP[i][M+N-1:M+i+1] = {(N-i){1'b0}}; // uncomment to make probing readable
    assign PP[i] = { {(N-i){1'b0}}, Cout, gS};
    RippleCarryAdder#(M+i) adder(
    	.A(gA), .B(gB), .S(gS), .Cin(1'b0), .Cout(Cout) );
end
endgenerate

//always@* foreach(S[i]) $display("S[%0d]:%b",i,S[i]);

endmodule

module RippleCarryAdder#(parameter N = 4)(A,B,Cin,S,Cout);

input [N-1:0] A;
input [N-1:0] B;
input Cin;
output [N-1:0] S;
output Cout;
wire [N:0] CC;

assign CC[0] = Cin;
assign Cout = CC[N];
genvar i;
generate
for (i=0; i < N; i=i+1)
begin: addbit
    FullAdder unit(A[i],B[i],CC[i],S[i],CC[i+1]);
end
endgenerate

endmodule

module FullAdder(input A,B,Cin, output wire S,Cout);
assign {Cout,S} = A+B+Cin;
endmodule