3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-08-21 02:30:25 +00:00

Merge pull request #1359 from YosysHQ/xc7dsp

DSP inference for Xilinx (improved for ice40, initial support for ecp5)
This commit is contained in:
Eddie Hung 2019-09-29 11:26:22 -07:00 committed by GitHub
commit 8474c5b366
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 6247 additions and 294 deletions

View file

@ -13,13 +13,35 @@ reg [(A_WIDTH + B_WIDTH - 1):0] reg_tmp_c;
assign c = reg_tmp_c;
always @(posedge clk)
begin
if(set)
begin
reg_tmp_c <= 0;
end
else
begin
reg_tmp_c <= a * b + c;
end
if(set)
begin
reg_tmp_c <= 0;
end
else
begin
reg_tmp_c <= a * b + c;
end
end
endmodule
module top2(clk,a,b,c,hold);
parameter A_WIDTH = 6 /*4*/;
parameter B_WIDTH = 6 /*3*/;
input hold;
input clk;
input signed [(A_WIDTH - 1):0] a;
input signed [(B_WIDTH - 1):0] b;
output signed [(A_WIDTH + B_WIDTH - 1):0] c;
reg signed [A_WIDTH-1:0] reg_a;
reg signed [B_WIDTH-1:0] reg_b;
reg [(A_WIDTH + B_WIDTH - 1):0] reg_tmp_c;
assign c = reg_tmp_c;
always @(posedge clk)
begin
if (!hold) begin
reg_a <= a;
reg_b <= b;
reg_tmp_c <= reg_a * reg_b + c;
end
end
endmodule

View file

@ -1,13 +1,25 @@
read_verilog macc.v
proc
design -save read
hierarchy -top top
#equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40 -dsp
async2sync
equiv_opt -run prove: -assert null
equiv_opt -assert -multiclock -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top # Constrain all select calls below inside the top module
select -assert-count 1 t:SB_MAC16
select -assert-none t:SB_MAC16 %% t:* %D
design -load read
hierarchy -top top2
#equiv_opt -multiclock -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
equiv_opt -run :prove -multiclock -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check
clk2fflogic
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -set-init-zero -seq 4 -verify -prove-asserts -show-ports miter
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd top2 # Constrain all select calls below inside the top module
select -assert-count 1 t:SB_MAC16
select -assert-none t:SB_MAC16 %% t:* %D

View file

@ -1,3 +1,4 @@
/*.log
/*.out
/run-test.mk
/*_uut.v

25
tests/xilinx/dsp_simd.ys Normal file
View file

@ -0,0 +1,25 @@
read_verilog <<EOT
module simd(input [12*4-1:0] a, input [12*4-1:0] b, (* use_dsp="simd" *) output [7*12-1:0] o12, (* use_dsp="simd" *) output [2*24-1:0] o24);
generate
genvar i;
// 4 x 12-bit adder
for (i = 0; i < 4; i++)
assign o12[i*12+:12] = a[i*12+:12] + b[i*12+:12];
// 2 x 24-bit subtract
for (i = 0; i < 2; i++)
assign o24[i*24+:24] = a[i*24+:24] - b[i*24+:24];
endgenerate
reg [3*12-1:0] ro;
always @* begin
ro[0*12+:12] = a[0*10+:10] + b[0*10+:10];
ro[1*12+:12] = a[1*10+:10] + b[1*10+:10];
ro[2*12+:12] = a[2*8+:8] + b[2*8+:8];
end
assign o12[4*12+:3*12] = ro;
endmodule
EOT
proc
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx
design -load postopt
select -assert-count 3 t:DSP48E1

3
tests/xilinx/macc.sh Normal file
View file

@ -0,0 +1,3 @@
../../yosys -qp "synth_xilinx -top macc2; rename -top macc2_uut" macc.v -o macc_uut.v
iverilog -o test_macc macc_tb.v macc_uut.v macc.v ../../techlibs/xilinx/cells_sim.v
vvp -N ./test_macc

84
tests/xilinx/macc.v Normal file
View file

@ -0,0 +1,84 @@
// 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
//
module macc # (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
// Adapted variant of above
module macc2 # (parameter SIZEIN = 16, SIZEOUT = 40) (
input clk,
input ce,
input rst,
input signed [SIZEIN-1:0] a, b,
output signed [SIZEOUT-1:0] accum_out,
output overflow
);
// Declare registers for intermediate values
reg signed [SIZEIN-1:0] a_reg, b_reg, a_reg2, b_reg2;
reg signed [2*SIZEIN-1:0] mult_reg = 0;
reg signed [SIZEOUT:0] adder_out = 0;
reg overflow_reg;
always @(posedge clk) begin
//if (ce)
begin
a_reg <= a;
b_reg <= b;
a_reg2 <= a_reg;
b_reg2 <= b_reg;
mult_reg <= a_reg2 * b_reg2;
// Store accumulation result into a register
adder_out <= adder_out + mult_reg;
overflow_reg <= overflow;
end
if (rst) begin
a_reg <= 0;
a_reg2 <= 0;
b_reg <= 0;
b_reg2 <= 0;
mult_reg <= 0;
adder_out <= 0;
overflow_reg <= 1'b0;
end
end
assign overflow = (adder_out >= 2**(SIZEOUT-1)) | overflow_reg;
// Output accumulation result
assign accum_out = overflow ? 2**(SIZEOUT-1)-1 : adder_out;
endmodule

31
tests/xilinx/macc.ys Normal file
View file

@ -0,0 +1,31 @@
read_verilog macc.v
design -save read
proc
hierarchy -top macc
#equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx ### TODO
equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -seq 10 -show-inputs -show-outputs miter
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd macc # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 1 t:FDRE
select -assert-count 1 t:DSP48E1
select -assert-none t:BUFG t:FDRE t:DSP48E1 %% t:* %D
design -load read
proc
hierarchy -top macc2
#equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx ### TODO
equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -seq 10 -show-inputs -show-outputs miter
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd macc2 # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 1 t:DSP48E1
select -assert-count 1 t:FDRE
select -assert-count 1 t:LUT2
select -assert-count 41 t:LUT3
select -assert-none t:BUFG t:DSP48E1 t:FDRE t:LUT2 t:LUT3 %% t:* %D

96
tests/xilinx/macc_tb.v Normal file
View file

@ -0,0 +1,96 @@
`timescale 1ns / 1ps
module testbench;
parameter SIZEIN = 16, SIZEOUT = 40;
reg clk, ce, rst;
reg signed [SIZEIN-1:0] a, b;
output signed [SIZEOUT-1:0] REF_accum_out, accum_out;
output REF_overflow, overflow;
integer errcount = 0;
reg ERROR_FLAG = 0;
task clkcycle;
begin
#5;
clk = ~clk;
#10;
clk = ~clk;
#2;
ERROR_FLAG = 0;
if (REF_accum_out !== accum_out) begin
$display("ERROR at %1t: REF_accum_out=%b UUT_accum_out=%b DIFF=%b", $time, REF_accum_out, accum_out, REF_accum_out ^ accum_out);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
if (REF_overflow !== overflow) begin
$display("ERROR at %1t: REF_overflow=%b UUT_overflow=%b DIFF=%b", $time, REF_overflow, overflow, REF_overflow ^ overflow);
errcount = errcount + 1;
ERROR_FLAG = 1;
end
#3;
end
endtask
initial begin
//$dumpfile("test_macc.vcd");
//$dumpvars(0, testbench);
#2;
clk = 1'b0;
ce = 1'b0;
a = 0;
b = 0;
rst = 1'b1;
repeat (10) begin
#10;
clk = 1'b1;
#10;
clk = 1'b0;
#10;
clk = 1'b1;
#10;
clk = 1'b0;
end
rst = 1'b0;
repeat (10000) begin
clkcycle;
ce = 1; //$urandom & $urandom;
//rst = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
a = $urandom & ~(1 << (SIZEIN-1));
b = $urandom & ~(1 << (SIZEIN-1));
end
if (errcount == 0) begin
$display("All tests passed.");
$finish;
end else begin
$display("Caught %1d errors.", errcount);
$stop;
end
end
macc2 ref (
.clk(clk),
.ce(ce),
.rst(rst),
.a(a),
.b(b),
.accum_out(REF_accum_out),
.overflow(REF_overflow)
);
macc2_uut uut (
.clk(clk),
.ce(ce),
.rst(rst),
.a(a),
.b(b),
.accum_out(accum_out),
.overflow(overflow)
);
endmodule

View file

@ -0,0 +1,30 @@
/*
Example from: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug901-vivado-synthesis.pdf [p. 89].
*/
// Unsigned 16x24-bit Multiplier
// 1 latency stage on operands
// 3 latency stage after the multiplication
// File: multipliers2.v
//
module mul_unsigned (clk, A, B, RES);
parameter WIDTHA = /*16*/ 6;
parameter WIDTHB = /*24*/ 9;
input clk;
input [WIDTHA-1:0] A;
input [WIDTHB-1:0] B;
output [WIDTHA+WIDTHB-1:0] RES;
reg [WIDTHA-1:0] rA;
reg [WIDTHB-1:0] rB;
reg [WIDTHA+WIDTHB-1:0] M [3:0];
integer i;
always @(posedge clk)
begin
rA <= A;
rB <= B;
M[0] <= rA * rB;
for (i = 0; i < 3; i = i+1)
M[i+1] <= M[i];
end
assign RES = M[3];
endmodule

View file

@ -0,0 +1,10 @@
read_verilog mul_unsigned.v
proc
hierarchy -top mul_unsigned
equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx # equivalency check
design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
cd mul_unsigned # Constrain all select calls below inside the top module
select -assert-count 1 t:BUFG
select -assert-count 1 t:DSP48E1
select -assert-count 30 t:FDRE
select -assert-none t:DSP48E1 t:FDRE t:BUFG %% t:* %D