Skip to content

Instantly share code, notes, and snippets.

@buttercutter
Last active January 22, 2019 03:54
Show Gist options
  • Save buttercutter/0f46d5478735960b9efed32c0c4254f2 to your computer and use it in GitHub Desktop.
Save buttercutter/0f46d5478735960b9efed32c0c4254f2 to your computer and use it in GitHub Desktop.
Signed Multiplier verilog code from https://github.com/ZipCPU/fwmpy
////////////////////////////////////////////////////////////////////////////////
//
// Filename: bimpy
//
// Project: A multiply core generator
//
// Purpose: An unsigned 2-bit multiply based upon the fact that LUT's allow
// 6-bits of input, but a 2x2 bit multiply will never carry more
// than one bit. While this multiply is hardware independent, it is
// really motivated by trying to optimize for a specific piece of
// hardware (Xilinx-7 series ...) that has 4-input LUT's with carry
// chains.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017-2019, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/> for a
// copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
module bimpy(i_clk, i_reset, i_ce, i_a, i_b, o_r);
parameter BW=2, LUTB=2;
input i_clk, i_reset, i_ce;
input [(LUTB-1):0] i_a;
input [(BW-1):0] i_b;
output reg [(BW+LUTB-1):0] o_r;
// See https://stackoverflow.com/questions/54247731/understanding-a-binary-multiplier-using-gate-level-diagram
// for general overview of this module
/* wire [(BW+LUTB-2):0] w_r;
wire [(BW+LUTB-3):1] c;
assign w_r = { ((i_a[1])?i_b:{(BW){1'b0}}), 1'b0 }
^ { 1'b0, ((i_a[0])?i_b:{(BW){1'b0}}) };
assign c = { ((i_a[1])?i_b[(BW-2):0]:{(BW-1){1'b0}}) }
& ((i_a[0])?i_b[(BW-1):1]:{(BW-1){1'b0}});
*/
initial o_r = 0;
always @(posedge i_clk)
if (i_reset)
o_r <= 0;
else if (i_ce)
o_r <= (i_a[0] ? i_b : 2'b0) + ((i_a[1] ? i_b : 2'b0)<<1);//o_r <= w_r + { c, 2'b0 };
// similar to 2 bits by 2 bits multiplication as in o_r <= (i_a[0]*i_b) + ((i_a[1]*i_b)<< 1)
endmodule
[*]
[*] GTKWave Analyzer v3.3.86 (w)1999-2017 BSI
[*] Fri Jan 18 07:53:14 2019
[*]
[dumpfile] "/home/phung/Documents/phung/multiplier/multiply_2x2.vcd"
[dumpfile_mtime] "Fri Jan 18 02:14:27 2019"
[dumpfile_size] 2026
[savefile] "/home/phung/Documents/phung/multiplier/multiply_2x2.gtkw"
[timestart] 0
[size] 1920 1115
[pos] -39 -39
*-5.274622 45 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] test.
[treeopen] test.s2_2.
[treeopen] test.s2_2.umpy.
[sst_width] 229
[signals_width] 434
[sst_expanded] 1
[sst_vpaned_height] 319
@420
test.i_a[1:0]
@28
test.i_aux
@420
test.i_b[1:0]
@28
test.i_ce
test.i_clk
test.i_reset
test.o_aux
@420
test.o_p[3:0]
@28
test.s2_2.i_a[1:0]
test.s2_2.i_aux
test.s2_2.i_b[1:0]
test.s2_2.i_ce
test.s2_2.i_clk
test.s2_2.i_l[1:0]
test.s2_2.i_reset
test.s2_2.i_s[1:0]
test.s2_2.o_aux
@22
test.s2_2.o_p[3:0]
@28
test.s2_2.u_aux
test.s2_2.u_l[1:0]
@22
test.s2_2.u_r[3:0]
@28
test.s2_2.u_s[1:0]
test.s2_2.u_sgn[1:0]
test.s2_2.w_aux
test.s2_2.umpy.A_0
@22
test.s2_2.umpy.S_0_00[3:0]
@28
test.s2_2.umpy.i_a[1:0]
test.s2_2.umpy.i_aux
test.s2_2.umpy.i_b[1:0]
test.s2_2.umpy.i_ce
test.s2_2.umpy.i_clk
test.s2_2.umpy.i_l[1:0]
test.s2_2.umpy.i_reset
test.s2_2.umpy.i_s[1:0]
test.s2_2.umpy.o_aux
@22
test.s2_2.umpy.o_p[3:0]
@25
test.s2_2.umpy.initialmpy_0_0.c[1]
test.s2_2.umpy.initialmpy_0_0.i_a[1:0]
test.s2_2.umpy.initialmpy_0_0.i_b[1:0]
@28
test.s2_2.umpy.initialmpy_0_0.i_ce
test.s2_2.umpy.initialmpy_0_0.i_clk
test.s2_2.umpy.initialmpy_0_0.i_reset
@25
test.s2_2.umpy.initialmpy_0_0.o_r[3:0]
test.s2_2.umpy.initialmpy_0_0.w_r[2:0]
[pattern_trace] 1
[pattern_trace] 0
$date
Fri Jan 18 18:39:41 2019
$end
$version
Icarus Verilog
$end
$timescale
1s
$end
$scope module test $end
$var wire 4 ! o_p [3:0] $end
$var wire 1 " o_aux $end
$var reg 2 # i_a [1:0] $end
$var reg 1 $ i_aux $end
$var reg 2 % i_b [1:0] $end
$var reg 1 & i_ce $end
$var reg 1 ' i_clk $end
$var reg 1 ( i_reset $end
$scope module s2_2 $end
$var wire 2 ) i_a [1:0] $end
$var wire 1 $ i_aux $end
$var wire 2 * i_b [1:0] $end
$var wire 1 & i_ce $end
$var wire 1 ' i_clk $end
$var wire 1 ( i_reset $end
$var wire 1 + w_aux $end
$var wire 4 , u_r [3:0] $end
$var wire 2 - i_s [1:0] $end
$var wire 2 . i_l [1:0] $end
$var reg 1 " o_aux $end
$var reg 4 / o_p [3:0] $end
$var reg 1 0 u_aux $end
$var reg 2 1 u_l [1:0] $end
$var reg 2 2 u_s [1:0] $end
$var reg 2 3 u_sgn [1:0] $end
$scope begin genblk2 $end
$upscope $end
$scope module umpy $end
$var wire 2 4 i_a [1:0] $end
$var wire 1 0 i_aux $end
$var wire 2 5 i_b [1:0] $end
$var wire 1 & i_ce $end
$var wire 1 ' i_clk $end
$var wire 1 ( i_reset $end
$var wire 1 + o_aux $end
$var wire 4 6 o_p [3:0] $end
$var wire 2 7 i_s [1:0] $end
$var wire 2 8 i_l [1:0] $end
$var wire 4 9 S_0_00 [3:0] $end
$var reg 1 : A_0 $end
$scope begin genblk2 $end
$upscope $end
$scope module initialmpy_0_0 $end
$var wire 2 ; i_a [1:0] $end
$var wire 2 < i_b [1:0] $end
$var wire 1 & i_ce $end
$var wire 1 ' i_clk $end
$var wire 1 ( i_reset $end
$var reg 4 = o_r [3:0] $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$enddefinitions $end
#0
$dumpvars
b0 =
b0 <
b0 ;
0:
b0 9
b0 8
b0 7
b0 6
b0 5
b0 4
b0 3
b0 2
b0 1
00
b0 /
b0 .
b0 -
b0 ,
0+
b0 *
b0 )
0(
0'
0&
b0 %
0$
b0 #
0"
b0 !
$end
#5
1'
#10
0'
#15
1(
1'
#20
0'
#25
0(
1'
#30
0'
#35
1'
#40
0'
#45
10
b10 7
b10 ;
b10 1
b10 5
b1 8
b1 <
b1 2
b1 4
b1 3
1$
b1 -
b1 %
b1 *
b10 .
b10 #
b10 )
1&
1'
#50
0'
#55
b11 3
1+
1:
b10 ,
b10 6
b10 9
b10 =
1'
#60
0'
#65
b1110 !
b1110 /
1"
1'
#70
0'
#75
1'
#80
0'
#85
1'
#90
0'
#95
1'
#100
0'
#105
1'
#110
0'
#115
1'
#120
0'
#125
1'
[*]
[*] GTKWave Analyzer v3.3.94 (w)1999-2018 BSI
[*] Thu Jan 17 13:56:12 2019
[*]
[dumpfile] "/home/phung/Documents/Grive/Personal/Digital/verification_example/multiplier/multiply_3x3.vcd"
[dumpfile_mtime] "Thu Jan 17 13:27:50 2019"
[dumpfile_size] 2498
[savefile] "/home/phung/Documents/Grive/Personal/Digital/verification_example/multiplier/multiply_3x3.gtkw"
[timestart] 0
[size] 1920 995
[pos] -1 -1
*-5.266698 45 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] test.
[treeopen] test.s3_3.
[treeopen] test.s3_3.umpy.
[sst_width] 228
[signals_width] 380
[sst_expanded] 1
[sst_vpaned_height] 279
@421
test.i_a[2:0]
@420
test.i_aux
@421
test.i_b[2:0]
@420
test.i_ce
test.i_clk
test.i_reset
test.o_aux
@421
test.o_p[5:0]
@420
test.s3_3.i_a[2:0]
test.s3_3.i_aux
test.s3_3.i_b[2:0]
test.s3_3.i_ce
test.s3_3.i_clk
test.s3_3.i_l[2:0]
test.s3_3.i_reset
test.s3_3.i_s[2:0]
test.s3_3.o_aux
test.s3_3.o_p[5:0]
test.s3_3.u_aux
test.s3_3.u_l[2:0]
test.s3_3.u_r[5:0]
test.s3_3.u_s[2:0]
test.s3_3.u_sgn[2:0]
test.s3_3.w_aux
test.s3_3.umpy.A_0
test.s3_3.umpy.A_1
test.s3_3.umpy.S_0_00[4:0]
test.s3_3.umpy.S_0_01[4:0]
test.s3_3.umpy.S_1_00[5:0]
test.s3_3.umpy.i_a[2:0]
test.s3_3.umpy.i_aux
test.s3_3.umpy.i_b[2:0]
test.s3_3.umpy.i_ce
test.s3_3.umpy.i_clk
test.s3_3.umpy.i_l[2:0]
test.s3_3.umpy.i_reset
test.s3_3.umpy.i_s[2:0]
test.s3_3.umpy.o_aux
test.s3_3.umpy.o_p[5:0]
test.s3_3.umpy.unused
test.s3_3.umpy.initialmpy_0_0.c[2:1]
test.s3_3.umpy.initialmpy_0_0.i_a[1:0]
test.s3_3.umpy.initialmpy_0_0.i_b[2:0]
test.s3_3.umpy.initialmpy_0_0.i_ce
test.s3_3.umpy.initialmpy_0_0.i_clk
test.s3_3.umpy.initialmpy_0_0.i_reset
test.s3_3.umpy.initialmpy_0_0.o_r[4:0]
test.s3_3.umpy.initialmpy_0_0.w_r[3:0]
test.s3_3.umpy.initialmpy_1_0.c[2:1]
test.s3_3.umpy.initialmpy_1_0.i_a[1:0]
test.s3_3.umpy.initialmpy_1_0.i_b[2:0]
test.s3_3.umpy.initialmpy_1_0.i_ce
test.s3_3.umpy.initialmpy_1_0.i_clk
test.s3_3.umpy.initialmpy_1_0.i_reset
test.s3_3.umpy.initialmpy_1_0.o_r[4:0]
test.s3_3.umpy.initialmpy_1_0.w_r[3:0]
[pattern_trace] 1
[pattern_trace] 0
$date
Thu Jan 17 21:27:50 2019
$end
$version
Icarus Verilog
$end
$timescale
1s
$end
$scope module test $end
$var wire 6 ! o_p [5:0] $end
$var wire 1 " o_aux $end
$var reg 3 # i_a [2:0] $end
$var reg 1 $ i_aux $end
$var reg 3 % i_b [2:0] $end
$var reg 1 & i_ce $end
$var reg 1 ' i_clk $end
$var reg 1 ( i_reset $end
$scope module s3_3 $end
$var wire 3 ) i_a [2:0] $end
$var wire 1 $ i_aux $end
$var wire 3 * i_b [2:0] $end
$var wire 1 & i_ce $end
$var wire 1 ' i_clk $end
$var wire 1 ( i_reset $end
$var wire 1 + w_aux $end
$var wire 6 , u_r [5:0] $end
$var wire 3 - i_s [2:0] $end
$var wire 3 . i_l [2:0] $end
$var reg 1 " o_aux $end
$var reg 6 / o_p [5:0] $end
$var reg 1 0 u_aux $end
$var reg 3 1 u_l [2:0] $end
$var reg 3 2 u_s [2:0] $end
$var reg 3 3 u_sgn [2:0] $end
$scope begin genblk2 $end
$upscope $end
$scope module umpy $end
$var wire 3 4 i_a [2:0] $end
$var wire 1 0 i_aux $end
$var wire 3 5 i_b [2:0] $end
$var wire 1 & i_ce $end
$var wire 1 ' i_clk $end
$var wire 1 ( i_reset $end
$var wire 1 + o_aux $end
$var wire 6 6 o_p [5:0] $end
$var wire 1 7 unused $end
$var wire 3 8 i_s [2:0] $end
$var wire 3 9 i_l [2:0] $end
$var wire 5 : S_0_01 [4:0] $end
$var wire 5 ; S_0_00 [4:0] $end
$var reg 1 < A_0 $end
$var reg 1 = A_1 $end
$var reg 6 > S_1_00 [5:0] $end
$scope begin genblk2 $end
$upscope $end
$scope module initialmpy_0_0 $end
$var wire 2 ? c [2:1] $end
$var wire 2 @ i_a [1:0] $end
$var wire 3 A i_b [2:0] $end
$var wire 1 & i_ce $end
$var wire 1 ' i_clk $end
$var wire 1 ( i_reset $end
$var wire 4 B w_r [3:0] $end
$var reg 5 C o_r [4:0] $end
$upscope $end
$scope module initialmpy_1_0 $end
$var wire 2 D c [2:1] $end
$var wire 2 E i_a [1:0] $end
$var wire 3 F i_b [2:0] $end
$var wire 1 & i_ce $end
$var wire 1 ' i_clk $end
$var wire 1 ( i_reset $end
$var wire 4 G w_r [3:0] $end
$var reg 5 H o_r [4:0] $end
$upscope $end
$upscope $end
$upscope $end
$upscope $end
$enddefinitions $end
#0
$dumpvars
b0 H
b0 G
b0 F
b0 E
b0 D
b0 C
b0 B
b0 A
b0 @
b0 ?
b0 >
0=
0<
b0 ;
b0 :
b0 9
b0 8
07
b0 6
b0 5
b0 4
b0 3
b0 2
b0 1
00
b0 /
b0 .
b0 -
b0 ,
0+
b0 *
b0 )
0(
0'
0&
b0 %
0$
b0 #
0"
b0 !
$end
#5
1'
#10
0'
#15
1(
1'
#20
0'
#25
0(
1'
#30
0'
#35
1'
#40
0'
#45
b101 B
b1 ?
b11 @
10
b11 8
b11 1
b11 5
b11 9
b11 A
b11 F
b11 2
b11 4
b1 3
1$
b101 -
b101 %
b101 *
b11 .
b11 #
b11 )
1&
1'
#50
0'
#55
b11 3
1<
b1001 ;
b1001 C
1'
#60
0'
#65
b1001 ,
b1001 6
b1001 >
1+
1=
b111 3
1'
#70
0'
#75
1"
b110111 !
b110111 /
1'
#80
0'
#85
1'
#90
0'
#95
1'
#100
0'
#105
1'
#110
0'
#115
1'
#120
0'
#125
1'
////////////////////////////////////////////////////////////////////////////////
//
// Filename: sgnmpy_2x2.v
//
// Project: A multiply core generator
//
// Purpose: Turns a signed multiply into an unsigned multiply, at the cost
// of two clocks and a negation.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/> for a
// copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
module sgnmpy_2x2(i_clk, i_reset, i_ce, i_a, i_b, i_aux, o_p, o_aux);
parameter NA=2, NB=2, DLY=2;
input i_clk, i_reset, i_ce;
input signed [(NA-1):0] i_a;
input signed [(NB-1):0] i_b;
input i_aux;
output reg signed [(NA+NB-1):0] o_p;
output reg o_aux;
localparam NS = (NA < NB) ? NA : NB;
localparam NL = (NA < NB) ? NB : NA;
wire [(NS-1):0] i_s; // Smaller input
wire [(NL-1):0] i_l; // larger input
//
// Adjust our inputs so that i_s has the fewest bits, and i_b the most
generate if (NA < NB)
begin : BITADJ
assign i_s = i_a;
assign i_l = i_b;
end else begin
assign i_s = i_b;
assign i_l = i_a;
end endgenerate
reg [(NS-1):0] u_s;
reg [(NL-1):0] u_l;
reg [(DLY-1):0] u_sgn;
reg u_aux;
initial u_aux = 1'b0;
always @(posedge i_clk)
if(i_reset)
u_aux <= 1'b0;
else if (i_ce)
u_aux <= i_aux;
initial u_s = 0;
initial u_l = 0;
always @(posedge i_clk)
if(i_reset)
begin
u_s <= 0;
u_l <= 0;
end else if (i_ce)
begin
u_s <= (i_s[NS-1])?(-i_s):i_s;
u_l <= (i_l[NL-1])?(-i_l):i_l;
end
initial u_sgn = 0;
always @(posedge i_clk)
if(i_reset)
u_sgn <= 0;
else if (i_ce)
u_sgn <= { u_sgn[(DLY-2):0], ((i_s[NS-1])^(i_l[NL-1])) };
wire [(NA+NB-1):0] u_r;
wire w_aux;
umpy_2x2 umpy(i_clk, i_reset, i_ce, u_s, u_l, u_aux, u_r, w_aux);
initial o_p = 0;
always @(posedge i_clk)
if(i_reset)
o_p <= 0;
else if (i_ce)
o_p <= (u_sgn[DLY-1])?(-u_r):u_r;
initial o_aux = 1'b0;
always @(posedge i_clk)
if(i_reset)
o_aux <= 1'b0;
else if (i_ce)
o_aux <= w_aux;
endmodule
////////////////////////////////////////////////////////////////////////////////
//
// Filename: sgnmpy_3x3.v
//
// Project: A multiply core generator
//
// Purpose: Turns a signed multiply into an unsigned multiply, at the cost
// of two clocks and a negation.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017-2019, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/> for a
// copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
module sgnmpy_3x3(i_clk, i_reset, i_ce, i_a, i_b, i_aux, o_p, o_aux);
parameter NA=3, NB=3, DLY=3;
input i_clk, i_reset, i_ce;
input signed [(NA-1):0] i_a;
input signed [(NB-1):0] i_b;
input i_aux;
output reg signed [(NA+NB-1):0] o_p;
output reg o_aux;
localparam NS = (NA < NB) ? NA : NB;
localparam NL = (NA < NB) ? NB : NA;
wire [(NS-1):0] i_s; // Smaller input
wire [(NL-1):0] i_l; // larger input
//
// Adjust our inputs so that i_s has the fewest bits, and i_b the most
generate if (NA < NB)
begin : BITADJ
assign i_s = i_a;
assign i_l = i_b;
end else begin
assign i_s = i_b;
assign i_l = i_a;
end endgenerate
reg [(NS-1):0] u_s;
reg [(NL-1):0] u_l;
reg [(DLY-1):0] u_sgn;
reg u_aux;
initial u_aux = 1'b0;
always @(posedge i_clk)
if(i_reset)
u_aux <= 1'b0;
else if (i_ce)
u_aux <= i_aux;
initial u_s = 0;
initial u_l = 0;
always @(posedge i_clk)
if(i_reset)
begin
u_s <= 0;
u_l <= 0;
end else if (i_ce)
begin
u_s <= (i_s[NS-1])?(-i_s):i_s;
u_l <= (i_l[NL-1])?(-i_l):i_l;
end
initial u_sgn = 0;
always @(posedge i_clk)
if(i_reset)
u_sgn <= 0;
else if (i_ce)
u_sgn <= { u_sgn[(DLY-2):0], ((i_s[NS-1])^(i_l[NL-1])) };
wire [(NA+NB-1):0] u_r;
wire w_aux;
umpy_3x3 umpy(i_clk, i_reset, i_ce, u_s, u_l, u_aux, u_r, w_aux);
initial o_p = 0;
always @(posedge i_clk)
if(i_reset)
o_p <= 0;
else if (i_ce)
o_p <= (u_sgn[DLY-1])?(-u_r):u_r;
initial o_aux = 1'b0;
always @(posedge i_clk)
if(i_reset)
o_aux <= 1'b0;
else if (i_ce)
o_aux <= w_aux;
endmodule
// Testbench
module test;
parameter NA=2, NB=2, DLY=2;
reg i_clk;
reg i_reset;
reg i_ce;
reg signed[(NA-1):0] i_a;
reg signed[(NB-1):0] i_b;
reg i_aux;
wire signed[(NA+NB-1):0] o_p;
wire o_aux;
// Instantiate design under test
sgnmpy_2x2 s2_2(.i_clk(i_clk), .i_reset(i_reset), .i_ce(i_ce), .i_a(i_a), .i_b(i_b), .i_aux(i_aux), .o_p(o_p), .o_aux(o_aux));
initial begin
// Dump waves
$dumpfile("multiply_2x2.vcd");
$dumpvars(0);
$display("Reset flop.");
i_clk = 0;
i_reset = 0;
i_ce = 0;
i_a = 0;
i_b = 0;
i_aux = 0;
end
always #5 i_clk = !i_clk;
initial begin
@(posedge i_clk);
@(posedge i_clk);
i_reset = 1;
@(posedge i_clk);
i_reset = 0;
@(posedge i_clk);
@(posedge i_clk);
i_ce = 1;
i_a = 2;
i_b = 1;
i_aux = 1;
#80 $finish;
end
endmodule
// Testbench
/*
iverilog -o multiply_3x3.vvp -Wall -g2012 testbench_3x3.v sgnmpy_3x3.v umpy_3x3.v bimpy.v
vvp multiply_3x3.vvp
gtkwave multiply_3x3.gtkw
*/
module test;
parameter NA=3, NB=3, DLY=3;
reg i_clk;
reg i_reset;
reg i_ce;
reg signed[(NA-1):0] i_a;
reg signed[(NB-1):0] i_b;
reg i_aux;
wire signed[(NA+NB-1):0] o_p;
wire o_aux;
// Instantiate design under test
sgnmpy_3x3 s3_3(.i_clk(i_clk), .i_reset(i_reset), .i_ce(i_ce),
.i_a(i_a), .i_b(i_b), .i_aux(i_aux), .o_p(o_p), .o_aux(o_aux));
initial begin
// Dump waves
$dumpfile("multiply_3x3.vcd");
$dumpvars(0);
$display("Reset flop.");
i_clk = 0;
i_reset = 0;
i_ce = 0;
i_a = 0;
i_b = 0;
i_aux = 0;
end
always #5 i_clk = !i_clk;
initial begin
@(posedge i_clk);
@(posedge i_clk);
i_reset = 1;
@(posedge i_clk);
i_reset = 0;
@(posedge i_clk);
@(posedge i_clk);
i_ce = 1;
i_a = 'b011;
i_b = 'b101;
i_aux = 1;
#80 $finish;
end
endmodule
////////////////////////////////////////////////////////////////////////////////
//
// Filename: umpy_2x2.v
//
// Project: A multiply core generator
//
// Purpose: This verilog file multiplies two unsigned numbers together,
// without using any hardware acceleration. This file is
// computer generated, so please (for your sake) don't make any edits
// to this file lest you regenerate it and your edits be lost.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/> for a
// copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
module umpy_2x2(i_clk, i_reset, i_ce, i_a, i_b, i_aux, o_p, o_aux);
parameter NA=2, NB=2;
input i_clk, i_reset, i_ce;
input signed [(NA-1):0] i_a;
input signed [(NB-1):0] i_b;
input i_aux;
output reg signed [(NA+NB-1):0] o_p;
output reg o_aux;
localparam NS = (NA < NB) ? NA : NB;
localparam NL = (NA < NB) ? NB : NA;
wire [(NS-1):0] i_s; // Smaller input
wire [(NL-1):0] i_l; // larger input
//
// Adjust our inputs so that i_s has the fewest bits, and i_b the most
generate if (NA < NB)
begin : BITADJ
assign i_s = i_a;
assign i_l = i_b;
end else begin
assign i_s = i_b;
assign i_l = i_a;
end endgenerate
// Clock zero: build our Tableau only.
// There will be one row for every pair of bits in i_a, and each
// row will contain (AW+3) bits, to allow
// for signed arithmetic manipulation.
//
reg A_0;
wire [3:0] S_0_00;
bimpy #(NB) initialmpy_0_0(i_clk, i_reset, i_ce, i_s[1:0], i_l, S_0_00);
initial A_0 = 0;
always @(posedge i_clk)
if(i_reset)
A_0 <= 1'b0;
else if (i_ce)
A_0 <= i_aux;
assign o_p = S_0_00[(NA+NB-1):0];
assign o_aux = A_0;
// Make verilator happy
// verilator lint_off UNUSED
//wire [0-1:0] unused;
//assign unused = { };
// verilator lint_on UNUSED
`ifdef FORMAL
reg f_past_valid;
initial f_past_valid = 0;
always @(posedge i_clk)
f_past_valid <= 1'b1;
wire [0+1:0] f_auxpipe;
assign f_auxpipe = { A_0, i_aux };
initial assume(!i_aux);
always @(posedge i_clk)
if ((i_reset)||((f_past_valid)&&($past(i_reset))))
assume(!i_aux);
initial assert(f_auxpipe == 0);
always @(posedge i_clk)
if ((f_past_valid)&&($past(i_reset)))
assert(f_auxpipe == 0);
always @(posedge i_clk)
if ((f_past_valid)&&(!$past(i_reset))&&($past(i_ce)))
assert(f_auxpipe[0+1:1] == $past(f_auxpipe[0:0]));
always @(posedge i_clk)
if ((f_past_valid)&&(!$past(i_reset))&&(!$past(i_ce)))
assert(f_auxpipe[0+1:1] == $past(f_auxpipe[0+1:1]));
localparam F_DELAY = 0;
reg [NA+NB-1:0] f_result;
integer ik;
initial f_result = 0;
always @(posedge i_clk)
if(i_reset)
f_result = 0;
else if (i_ce)
begin
f_result = 0;
for(ik=0; ik<NS; ik=ik+1)
if(i_a[ik])
f_result = f_result + { {(NL-ik-1){1'b0}},
i_b, { (ik){1'b0} } };
end
reg [F_DELAY*(NA+NB)-1:0] f_result_pipe;
initial f_result_pipe = 0;
always @(posedge i_clk)
if(i_reset)
f_result_pipe <= 0;
else if (i_ce)
f_result_pipe <= { f_result, f_result_pipe[((F_DELAY)*(NA+NB)-1):(NA+NB)] };
always @(posedge i_clk)
assert(o_p == f_result_pipe[(NA+NB-1):0]);
always @(posedge i_clk)
assume((i_ce)
||((f_past_valid)&&($past(i_ce)))
// ||(($past(f_past_valid))&&($past(i_ce,2)))
);
`endif
endmodule
////////////////////////////////////////////////////////////////////////////////
//
// Filename: umpy_3x3.v
//
// Project: A multiply core generator
//
// Purpose: This verilog file multiplies two unsigned numbers together,
// without using any hardware acceleration. This file is
// computer generated, so please (for your sake) don't make any edits
// to this file lest you regenerate it and your edits be lost.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2017-2019, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/> for a
// copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
module umpy_3x3(i_clk, i_reset, i_ce, i_a, i_b, i_aux, o_p, o_aux);
parameter NA=3, NB=3;
input i_clk, i_reset, i_ce;
input signed [(NA-1):0] i_a;
input signed [(NB-1):0] i_b;
input i_aux;
output reg signed [(NA+NB-1):0] o_p;
output reg o_aux;
localparam NS = (NA < NB) ? NA : NB;
localparam NL = (NA < NB) ? NB : NA;
wire [(NS-1):0] i_s; // Smaller input
wire [(NL-1):0] i_l; // larger input
//
// Adjust our inputs so that i_s has the fewest bits, and i_b the most
generate if (NA < NB)
begin : BITADJ
assign i_s = i_a;
assign i_l = i_b;
end else begin
assign i_s = i_b;
assign i_l = i_a;
end endgenerate
// Clock zero: build our Tableau only.
// There will be one row for every pair of bits in i_a, and each
// row will contain (AW+3) bits, to allow
// for signed arithmetic manipulation.
//
reg A_0;
wire [4:0] S_0_00;
bimpy #(NB) initialmpy_0_0(i_clk, i_reset, i_ce, i_s[1:0], i_l, S_0_00);
//Extra (odd) row
wire [4:0] S_0_01;
bimpy #(NB) initialmpy_1_0(i_clk, i_reset, i_ce, { {(1){1'b0}}, i_s[2:2]}, i_l, S_0_01);
initial A_0 = 0;
always @(posedge i_clk)
if(i_reset)
A_0 <= 1'b0;
else if (i_ce)
A_0 <= i_aux;
//
// Round #1, clock = 1, nz = 2, nbits = 5, nrows_in = 2
//
reg [(6-1):0] S_1_00; // maxbits = 6
reg A_1;
initial S_1_00 = 0;
always @(posedge i_clk)
if(i_reset)
begin
S_1_00 <= 0;
end else if (i_ce)
begin
S_1_00 <= { 1'b0, S_0_00 } + { S_0_01// Adding to unused: 8, 6
[3:0], 2'b0 };
// unused = 1, ustr = S_0_01[4:4]
end
initial A_1 = 0;
always @(posedge i_clk)
if(i_reset)
A_1 <= 1'b0;
else if (i_ce)
A_1 <= A_0;
assign o_p = S_1_00[(NA+NB-1):0];
assign o_aux = A_1;
// Make verilator happy
// verilator lint_off UNUSED
wire [1-1:0] unused;
assign unused = { S_0_01[4:4] };
// verilator lint_on UNUSED
`ifdef FORMAL
reg f_past_valid;
initial f_past_valid = 0;
always @(posedge i_clk)
f_past_valid <= 1'b1;
wire [1+1:0] f_auxpipe;
assign f_auxpipe = { A_1,A_0, i_aux };
initial assume(!i_aux);
always @(posedge i_clk)
if ((i_reset)||((f_past_valid)&&($past(i_reset))))
assume(!i_aux);
initial assert(f_auxpipe == 0);
always @(posedge i_clk)
if ((f_past_valid)&&($past(i_reset)))
assert(f_auxpipe == 0);
always @(posedge i_clk)
if ((f_past_valid)&&(!$past(i_reset))&&($past(i_ce)))
assert(f_auxpipe[1+1:1] == $past(f_auxpipe[1:0]));
always @(posedge i_clk)
if ((f_past_valid)&&(!$past(i_reset))&&(!$past(i_ce)))
assert(f_auxpipe[1+1:1] == $past(f_auxpipe[1+1:1]));
localparam F_DELAY = 1;
reg [NA+NB-1:0] f_result;
integer ik;
initial f_result = 0;
always @(posedge i_clk)
if(i_reset)
f_result = 0;
else if (i_ce)
begin
f_result = 0;
for(ik=0; ik<NS; ik=ik+1)
if(i_a[ik])
f_result = f_result + { {(NL-ik-1){1'b0}},
i_b, { (ik){1'b0} } };
end
reg [F_DELAY*(NA+NB)-1:0] f_result_pipe;
initial f_result_pipe = 0;
always @(posedge i_clk)
if(i_reset)
f_result_pipe <= 0;
else if (i_ce)
f_result_pipe <= { f_result, f_result_pipe[((F_DELAY)*(NA+NB)-1):(NA+NB)] };
always @(posedge i_clk)
assert(o_p == f_result_pipe[(NA+NB-1):0]);
always @(posedge i_clk)
assume((i_ce)
||((f_past_valid)&&($past(i_ce)))
// ||(($past(f_past_valid))&&($past(i_ce,2)))
);
`endif
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment