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:
commit
8474c5b366
44 changed files with 6247 additions and 294 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
1
tests/xilinx/.gitignore
vendored
1
tests/xilinx/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/run-test.mk
|
||||
/*_uut.v
|
||||
|
|
25
tests/xilinx/dsp_simd.ys
Normal file
25
tests/xilinx/dsp_simd.ys
Normal 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
3
tests/xilinx/macc.sh
Normal 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
84
tests/xilinx/macc.v
Normal 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
31
tests/xilinx/macc.ys
Normal 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
96
tests/xilinx/macc_tb.v
Normal 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
|
30
tests/xilinx/mul_unsigned.v
Normal file
30
tests/xilinx/mul_unsigned.v
Normal 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
|
10
tests/xilinx/mul_unsigned.ys
Normal file
10
tests/xilinx/mul_unsigned.ys
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue