Unverified Commit f1b8eba8 by Eddie Hung Committed by GitHub

Merge pull request #70 from YosysHQ/xc7dsp

Supporting tests for Xilinx DSP -- YosysHQ/yosys#1359
parents c1ffdf2f b2e8c22d
......@@ -77,6 +77,7 @@ $(eval $(call template,xilinx_srl,xilinx_srl_minlen xilinx_srl_fixed xilinx_srl_
ifeq ($(ENABLE_HEAVY_TESTS),1)
$(eval $(call template,synth_xilinx_srl,synth_xilinx_srl))
$(eval $(call template,synth_xilinx_mux,synth_xilinx_mux))
$(eval $(call template,synth_xilinx_dsp,synth_xilinx_dsp))
endif
#xilinx_ug901_synthesis_examples
......
#!/usr/bin/python3
import glob
import re
import os
re_mux = re.compile(r'mul_(\d+)(s?)_(\d+)(s?)_(A?B?P?)_A?B?P?\.v')
for fn in glob.glob('*.v'):
m = re_mux.match(fn)
if not m: continue
macc = False
A,B = map(int, m.group(1,3))
Asigned, Bsigned = m.group(2,4)
Areg = 'A' in m.group(5)
Breg = 'B' in m.group(5)
Preg = 'P' in m.group(5)
X = (A+14) // 16
Y = (B+14) // 16
count_MAC = X * Y
count_DFF = 0
if A % 16 > 1 and B % 16 > 1 and (A % 16 + B % 16) < 11:
count_MAC -= 1
if Areg or Breg:
count_DFF += A%16 + B%16
else:
# TODO: Tighter bounds on count_DFF
if (Areg or Breg) and (A % 16 == 1 or B % 16 == 1):
count_DFF += A + B
if Preg and (A > 16 or B > 16):
count_DFF += A + B
if macc:
count_DFF += 5 # In my testcases, accumulator is always
# 5bits bigger than multiplier result
elif (A > 16) ^ (B > 16):
count_DFF -= 1 # For pure multipliers with just one big dimension,
# expect last slice to absorb at least one register
# TODO: More assert on number of CARRY and LUTs
count_CARRY = ''
if (A <= 16 or B <= 16) and A % 16 != 1 and B % 16 != 1:
count_CARRY = '; select t:SB_CARRY -assert-none; select t:SB_LUT -assert-none';
count_DFF = 0
bn,_ = os.path.splitext(fn)
with open(fn, 'a') as f:
print('''
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd {0}; select t:SB_MAC16 -assert-count {1}; select t:SB_DFF* -assert-max {2}{3}";
endmodule
`endif
'''.format(os.path.splitext(fn)[0], count_MAC, count_DFF, count_CARRY), file=f)
#!/usr/bin/env python3
from common_mul import gen_mul
ARange = ['16','16s','17','17s','24','24s','31','31s','32','32s','33','33s','47','47s','48','48s','49','49s']
BRange = ['15','15s','16','16s','17','17s','24','24s','31','31s','32','32s']
if __name__ == "__main__":
gen_mul(ARange, BRange, "ABP")
(* top *)
module mul_16_16_keepABP_ #(parameter AW=16, BW=16, AREG=1, BREG=1, PREG=1) (input clk, CEA, CEB, CEP, input [AW-1:0] A, input [BW-1:0] B, (* keep *) output reg [AW+BW-1:0] P);
(* keep *) reg [AW-1:0] Ar;
(* keep *) reg [BW-1:0] Br;
generate
if (AREG) begin
always @(posedge clk) if (1) Ar <= A;
end
else
always @* Ar <= A;
if (BREG) begin
always @(posedge clk) if (1) Br <= B;
end
else
always @* Br <= B;
if (PREG) begin
always @(posedge clk) if (1) P <= Ar * Br;
end
else
always @* P <= Ar * Br;
endgenerate
endmodule
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd mul_16_16_keepABP_; select t:SB_MAC16 -assert-count 1; select t:SB_DFF* -assert-count 32";
endmodule
`endif
(* top *)
module mul_32_32_keepB_ #(parameter AW=32, BW=32, AREG=1, BREG=1, PREG=0) (input clk, CEA, CEB, CEP, input [AW-1:0] A, input [BW-1:0] B, output reg [AW+BW-1:0] P);
reg [AW-1:0] Ar;
(* keep *) reg [BW-1:0] Br;
generate
if (AREG) begin
always @(posedge clk) if (1) Ar <= A;
end
else
always @* Ar <= A;
if (BREG) begin
always @(posedge clk) if (1) Br <= B;
end
else
always @* Br <= B;
if (PREG) begin
always @(posedge clk) if (1) P <= Ar * Br;
end
else
always @* P <= Ar * Br;
endgenerate
endmodule
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd mul_32_32_keepB_; select t:SB_MAC16 -assert-count 4; select t:SB_DFF* -assert-count 32";
endmodule
`endif
#!/bin/bash
set -e
OPTIND=1
seed="" # default to no seed specified
while getopts "S:" opt
do
case "$opt" in
S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space
seed="SEED=$arg" ;;
esac
done
shift "$((OPTIND-1))"
# check for Icarus Verilog
if ! which iverilog > /dev/null ; then
echo "$0: Error: Icarus Verilog 'iverilog' not found."
exit 1
fi
wget https://raw.githubusercontent.com/YosysHQ/yosys-bench/master/verilog/benchmarks_small/mul/common.py -O common_mul.py -o /dev/null
cp ~/yosys/yosys-bench/verilog/benchmarks_small/mul/common.py common_mul.py
PYTHONPATH=".:$PYTHONPATH" python3 ../generate_mul.py
python3 ../assert_area.py
cp ../*.v .
${MAKE:-make} -f ../../../../tools/autotest.mk $seed *.v EXTRA_FLAGS="\
-p 'design -copy-to __test __test; \
synth_ice40 -dsp; \
design -copy-from __test *; \
select -assert-any __test; \
script -scriptwire __test/w:assert_area'\
-l ../../../../../techlibs/ice40/cells_sim.v"
#!/usr/bin/python3
import glob
import re
import os
re_mux = re.compile(r'(mul|muladd|macc)_(\d+)(s?)_(\d+)(s?)(_(\d+)(s?))?_(A?B?C?M?P?)_A?B?C?M?P?\.v')
for fn in glob.glob('*.v'):
m = re_mux.match(fn)
if not m: continue
macc = m.group(1) == 'macc'
A,B = map(int, m.group(2,4))
Asigned,Bsigned = m.group(3,5)
if m.group(6):
C = map(int, m.group(7))
Csigned = m.group(8)
Areg = 'A' in m.group(9)
Breg = 'B' in m.group(9)
Mreg = 'M' in m.group(9)
Preg = 'P' in m.group(9) or macc
if A < B:
A,B = B,A
Asigned,Bsigned = Bsigned,Asigned
if not (Asigned and Bsigned):
A += 1
B += 1
Asigned = Bsigned = 1
X = 1 + max(0,A-25+16) // 17
Y = 1 + max(0,B-18+16) // 17
count_MAC = X * Y
count_DFF = 0
if Mreg and (A > 25 or B > 18):
count_DFF += A + B
if not macc and (A > 25) ^ (B > 18):
count_DFF -= 1 # For pure multipliers with just one big dimension,
# expect last slice to absorb at least one register
if Preg and (A > 25 or B > 18):
count_DFF += A + B
if macc:
count_DFF += 5 # In my testcases, accumulator is always
# 5bits bigger than multiplier result
elif (A > 25) ^ (B > 18):
count_DFF -= 1 # For pure multipliers with just one big dimension,
# expect last slice to absorb at least one register
# TODO: More assert on number of CARRY and LUTs
count_CARRY = ''
if not macc and (A <= 25 or B <= 18):
count_CARRY = '; select t:XORCY -assert-none; select t:LUT* -assert-none';
bn,_ = os.path.splitext(fn)
with open(fn, 'a') as f:
print('''
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd {0}; select t:DSP48E1 -assert-max {1}; select t:FD* -assert-max {2}{3}";
endmodule
`endif
'''.format(os.path.splitext(fn)[0], count_MAC, count_DFF, count_CARRY), file=f)
#!/usr/bin/env python3
from common_macc import gen_macc
ARange = ['17','17s','18','18s','19','19s','24','24s','25','25s','36','36s','49','49s','50','50s','75','75s']
BRange = ['17','17s','18','18s','19','19s','27','27s','34','34s','35','35s','36','36s']
if __name__ == "__main__":
gen_macc(ARange, BRange, reg="ABM")
#!/usr/bin/env python3
from common_mul import gen_mul
ARange = ['17','17s','18','18s','19','19s','24','24s','25','25s','36','36s','49','49s','50','50s','75','75s']
BRange = ['17','17s','18','18s','19','19s','27','27s','34','34s','35','35s','36','36s']
if __name__ == "__main__":
gen_mul(ARange, BRange, reg="ABMP")
#!/usr/bin/env python3
from common_muladd import gen_muladd
ARange = ['24','24s','25','25s','36','36s']
BRange = ['17','17s','18','18s','19','19s']
CRange = ['32','32s','40','40s','48','48s']
if __name__ == "__main__":
gen_muladd(ARange, BRange, CRange, reg="ABMP")
(* top *)
module macc_25s_18s__49bitaccum #(parameter AW=25, BW=18, AREG=0, BREG=0, MREG=0) (input clk, CEA, CEB, CEM, CEP, input signed [AW-1:0] A, input signed [BW-1:0] B, output reg signed [49-1:0] P);
reg signed [AW-1:0] Ar;
reg signed [BW-1:0] Br;
reg signed [AW+BW-1:0] Mr;
generate
if (AREG) begin
always @(posedge clk) if (1) Ar <= A;
end
else
always @* Ar <= A;
if (BREG) begin
always @(posedge clk) if (1) Br <= B;
end
else
always @* Br <= B;
if (MREG) begin
always @(posedge clk) if (1) Mr <= Ar * Br;
end
else
always @* Mr <= Ar * Br;
always @(posedge clk) if (1) P <= P + Mr;
endgenerate
endmodule
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd macc_25s_18s__49bitaccum; select t:DSP48E1 -assert-count 1; select t:FD* -assert-count 49; select t:XORCY -assert-count 49; select t:LUT2 -assert-count 97";
endmodule
`endif
(* top *)
module mul_25s_18s_keepABP_ #(parameter AW=25, BW=18, AREG=1, BREG=1, PREG=1) (input clk, CEA, CEB, CEP, input signed [AW-1:0] A, input signed [BW-1:0] B, (* keep *) output reg signed [AW+BW-1:0] P);
(* keep *) reg signed [AW-1:0] Ar;
(* keep *) reg signed [BW-1:0] Br;
generate
if (AREG) begin
always @(posedge clk) if (1) Ar <= A;
end
else
always @* Ar <= A;
if (BREG) begin
always @(posedge clk) if (1) Br <= B;
end
else
always @* Br <= B;
if (PREG) begin
always @(posedge clk) if (1) P <= Ar * Br;
end
else
always @* P <= Ar * Br;
endgenerate
endmodule
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd mul_25s_18s_keepABP_; select t:DSP48E1 -assert-count 1; select t:FD* -assert-count 43";
endmodule
`endif
(* top *)
module mul_32_32_keepB_ #(parameter AW=32, BW=32, AREG=1, BREG=1, PREG=0) (input clk, CEA, CEB, CEP, input [AW-1:0] A, input [BW-1:0] B, output reg [AW+BW-1:0] P);
reg [AW-1:0] Ar;
(* keep *) reg [BW-1:0] Br;
generate
if (AREG) begin
always @(posedge clk) if (1) Ar <= A;
end
else
always @* Ar <= A;
if (BREG) begin
always @(posedge clk) if (1) Br <= B;
end
else
always @* Br <= B;
if (PREG) begin
always @(posedge clk) if (1) P <= Ar * Br;
end
else
always @* P <= Ar * Br;
endgenerate
endmodule
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd mul_32_32_keepB_; select t:DSP48E1 -assert-count 4; select t:FD* -assert-count 32";
endmodule
`endif
#!/bin/bash
set -e
OPTIND=1
seed="" # default to no seed specified
while getopts "S:" opt
do
case "$opt" in
S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space
seed="SEED=$arg" ;;
esac
done
shift "$((OPTIND-1))"
# check for Icarus Verilog
if ! which iverilog > /dev/null ; then
echo "$0: Error: Icarus Verilog 'iverilog' not found."
exit 1
fi
EXTRA_FLAGS="\
-p 'design -copy-to __test __test; \
synth_xilinx; \
design -copy-from __test *; \
select -assert-any __test; \
script -scriptwire __test/w:assert_area'\
-l ../../../../../techlibs/xilinx/cells_sim.v"
cp ../*.v .
${MAKE:-make} -f ../../../../tools/autotest.mk $seed *.v EXTRA_FLAGS="$EXTRA_FLAGS"
wget https://raw.githubusercontent.com/YosysHQ/yosys-bench/master/verilog/benchmarks_small/mul/common.py -O common_mul.py -o /dev/null
wget https://raw.githubusercontent.com/YosysHQ/yosys-bench/master/verilog/benchmarks_small/macc/common.py -O common_macc.py -o /dev/null
wget https://raw.githubusercontent.com/YosysHQ/yosys-bench/master/verilog/benchmarks_small/muladd/common.py -O common_muladd.py -o /dev/null
PYTHONPATH=".:$PYTHONPATH" python3 ../generate_mul.py
PYTHONPATH=".:$PYTHONPATH" python3 ../generate_macc.py
PYTHONPATH=".:$PYTHONPATH" python3 ../generate_muladd.py
python3 ../assert_area.py
${MAKE:-make} -f ../../../../tools/autotest.mk $seed mul_*.v EXTRA_FLAGS="$EXTRA_FLAGS"
${MAKE:-make} -f ../../../../tools/autotest.mk $seed macc_*.v EXTRA_FLAGS="$EXTRA_FLAGS"
${MAKE:-make} -f ../../../../tools/autotest.mk $seed muladd_*.v EXTRA_FLAGS="$EXTRA_FLAGS"
// Signed 40-bit streaming accumulator with 16-bit inputs
// File: HDL_Coding_Techniques/multipliers/multipliers4.v
//
// Source:
// https://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_2/ug901-vivado-synthesis.pdf p.90
//
(* top *)
module ug901a # (parameter SIZEIN = 16, SIZEOUT = 40) (
input clk, ce, sload,
input signed [SIZEIN-1:0] a, b,
output signed [SIZEOUT-1:0] accum_out
);
// Declare registers for intermediate values
reg signed [SIZEIN-1:0] a_reg, b_reg;
reg sload_reg;
reg signed [2*SIZEIN-1:0] mult_reg;
reg signed [SIZEOUT-1:0] adder_out, old_result;
always @* /*(adder_out or sload_reg)*/ begin // Modification necessary to fix sim/synth mismatch
if (sload_reg)
old_result <= 0;
else
// 'sload' is now active (=low) and opens the accumulation loop.
// The accumulator takes the next multiplier output in
// the same cycle.
old_result <= adder_out;
end
always @(posedge clk)
if (ce)
begin
a_reg <= a;
b_reg <= b;
mult_reg <= a_reg * b_reg;
sload_reg <= sload;
// Store accumulation result into a register
adder_out <= old_result + mult_reg;
end
// Output accumulation result
assign accum_out = adder_out;
endmodule
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd ug901a; select t:DSP48E1 -assert-count 1; select t:FDRE -assert-count 1; select -assert-none t:DSP48E1 t:BUFG t:FDRE %% t:* %D";
endmodule
`endif
// 8-Tap Even Symmetric Systolic FIR
//
// Source:
// https://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_2/ug901-vivado-synthesis.pdf p.93
//
(* top *)
module ug901b #(parameter nbtap = 4, dsize = 16, psize = 2*dsize) (
input clk,
input signed [dsize-1:0] datain,
output signed [2*dsize-1:0] firout
);
wire signed [dsize-1:0] h [nbtap-1:0];
wire signed [dsize-1:0] arraydata [nbtap-1:0];
wire signed [psize-1:0] arrayprod [nbtap-1:0];
wire signed [dsize-1:0] shifterout;
reg signed [dsize-1:0] dataz [nbtap-1:0];
assign h[0] = 7;
assign h[1] = 14;
assign h[2] = -138;
assign h[3] = 129;
assign firout = arrayprod[nbtap-1]; // Connect last product to output
sfir_shifter #(dsize, nbtap) shifter_inst0 (
clk,
datain,
shifterout);
generate
genvar I;
for (I=0; I<nbtap; I=I+1)
if (I==0)
sfir_even_symmetric_systolic_element #(dsize) fte_inst0 (
clk,
h[I],
datain,
shifterout,
{32{1'b0}},
arraydata[I],
arrayprod[I]);
else
sfir_even_symmetric_systolic_element #(dsize) fte_inst (
clk,
h[I],
arraydata[I-1],
shifterout,
arrayprod[I-1],
arraydata[I],
arrayprod[I]);
endgenerate
endmodule
(* gentb_skip *) // Prevents Yosys' test_autotb from operating on this module
(* dont_touch = "yes" *)
module sfir_shifter #(parameter dsize = 16, nbtap = 4) (
input clk,
input [dsize-1:0] datain,
output [dsize-1:0] dataout
);
(* srl_style = "srl_register" *) reg [dsize-1:0] tmp [0:2*nbtap-1];
integer i;
always @(posedge clk)
begin
tmp[0] <= datain;
for (i=0; i<=2*nbtap-2; i=i+1)
tmp[i+1] <= tmp[i];
end
assign dataout = tmp[2*nbtap-1];
endmodule
(* gentb_skip *) // Prevents Yosys' test_autotb from operating on this module
module sfir_even_symmetric_systolic_element #(parameter dsize = 16) (
input clk,
input signed [dsize-1:0] coeffin, datain, datazin,
input signed [2*dsize-1:0] cascin,
output signed [dsize-1:0] cascdata,
output reg signed [2*dsize-1:0] cascout
);
reg signed [dsize-1:0] coeff;
reg signed [dsize-1:0] data;
reg signed [dsize-1:0] dataz;
reg signed [dsize-1:0] datatwo;
reg signed [dsize:0] preadd;
reg signed [2*dsize-1:0] product;
assign cascdata = datatwo;
always @(posedge clk)
begin
coeff <= coeffin;
data <= datain;
datatwo <= data;
dataz <= datazin;
preadd <= datatwo + dataz;
product <= preadd * coeff;
cascout <= product + cascin;
end
endmodule
`ifndef _AUTOTB
module __test ;
wire [4095:0] assert_area = "cd ug901b; flatten; select t:DSP48E1 -assert-count 4; select t:FDRE -assert-count 128; select t:SRL16E -assert-count 16; select -assert-none t:DSP48E1 t:BUFG t:FDRE t:SRL16E %% t:* %D";
endmodule
`endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment