3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-14 19:25:40 +00:00
This commit is contained in:
Johan Olby 2026-07-14 22:02:59 +03:00 committed by GitHub
commit 75741b2337
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 195 additions and 0 deletions

View file

@ -52,4 +52,5 @@ yosys_pass(synth_gowin
lutrams_map.v
lutrams.txt
dsp_map.v
dsp_map_gw5a.v
)

View file

@ -0,0 +1,95 @@
module \$__MUL27X18 (input [26:0] A, input [17:0] B, output [44:0] Y);
parameter A_WIDTH = 27;
parameter B_WIDTH = 18;
parameter Y_WIDTH = 45;
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
wire [47:0] dout_w;
MULTALU27X18 #(
.MULT12X12_EN("FALSE"),
.MULT_RESET_MODE("SYNC"),
.AREG_CLK("BYPASS"),
.BREG_CLK("BYPASS"),
.PREG_CLK("BYPASS"),
.OREG_CLK("BYPASS")
) __TECHMAP_REPLACE__ (
.DOUT(dout_w),
.CASO(),
.SOA(),
.A(A),
.SIA(27'd0),
.B(B),
.C(48'd0),
.D(26'd0),
.CASI(48'd0),
.ACCSEL(1'b0),
.PSEL(1'b0),
.ASEL(1'b0),
.PADDSUB(1'b0),
.CSEL(1'b0),
.CASISEL(1'b0),
.ADDSUB(2'b00),
.CLK(2'b00),
.CE(2'b00),
.RESET(2'b00)
);
assign Y = dout_w[44:0];
endmodule
module \$__MUL12X12 (input [11:0] A, input [11:0] B, output [23:0] Y);
parameter A_WIDTH = 12;
parameter B_WIDTH = 12;
parameter Y_WIDTH = 24;
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
MULT12X12 #(
.MULT_RESET_MODE("SYNC"),
.AREG_CLK("BYPASS"),
.BREG_CLK("BYPASS"),
.PREG_CLK("BYPASS"),
.OREG_CLK("BYPASS")
) __TECHMAP_REPLACE__ (
.DOUT(Y),
.A(A),
.B(B),
.CLK(2'b00),
.CE(2'b00),
.RESET(2'b00)
);
endmodule
module \$__MUL27X36 (input [26:0] A, input [35:0] B, output [62:0] Y);
parameter A_WIDTH = 27;
parameter B_WIDTH = 36;
parameter Y_WIDTH = 63;
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
MULT27X36 #(
.MULT_RESET_MODE("SYNC"),
.AREG_CLK("BYPASS"),
.BREG_CLK("BYPASS"),
.PREG_CLK("BYPASS"),
.OREG_CLK("BYPASS")
) __TECHMAP_REPLACE__ (
.DOUT(Y),
.A(A),
.B(B),
.D(26'd0),
.PSEL(1'b0),
.PADDSUB(1'b0),
.CLK(2'b00),
.CE(2'b00),
.RESET(2'b00)
);
endmodule

View file

@ -44,6 +44,12 @@ struct SynthGowinPass : public ScriptPass
{9, 9, 4, 4, "$__MUL9X9"},
};
const std::vector<DSPRule> gw5a_dsp_rules = {
{27, 36, 2, 19, "$__MUL27X36"},
{27, 18, 13, 13, "$__MUL27X18"},
{12, 12, 2, 2, "$__MUL12X12"},
};
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@ -285,6 +291,8 @@ struct SynthGowinPass : public ScriptPass
if (help_mode) {
run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp and if -family gw1n or gw2a)");
run("techmap -map +/gowin/dsp_map.v", "(unless -nodsp and if -family gw1n or gw2a)");
run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp and if -family gw5a)");
run("techmap -map +/gowin/dsp_map_gw5a.v", "(unless -nodsp and if -family gw5a)");
} else if (!nodsp && (family == "gw1n" || family == "gw2a")) {
for (const auto &rule : dsp_rules) {
run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s",
@ -292,6 +300,14 @@ struct SynthGowinPass : public ScriptPass
run("chtype -set $mul t:$__soft_mul");
}
run("techmap -map +/gowin/dsp_map.v");
} else if (!nodsp && family == "gw5a") {
for (const auto &rule : gw5a_dsp_rules) {
run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d "
"-D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_SIGNEDONLY -D DSP_NAME=%s",
rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim));
run("chtype -set $mul t:$__soft_mul");
}
run("techmap -map +/gowin/dsp_map_gw5a.v");
}
run("alumacc");

View file

@ -0,0 +1,11 @@
// Signed multiply for GW5A DSP boundary tests (the GW5A multipliers are
// signed-only, so signed operands exercise the routing boundaries cleanly).
module top
#(parameter X_WIDTH=8, Y_WIDTH=8, A_WIDTH=16)
(
input signed [X_WIDTH-1:0] x,
input signed [Y_WIDTH-1:0] y,
output signed [A_WIDTH-1:0] A
);
assign A = x * y;
endmodule

View file

@ -0,0 +1,72 @@
# GW5A DSP multiply boundary tests. Probes each routing edge:
# 12x12 small-cell max (fits MULT12X12)
# 13x13 MINWIDTH=13 cutoff (-> MULTALU27X18)
# 27x18 large-cell exact fit (B<=18 -> MULTALU27X18)
# 27x19 B overflows 18 -> MULT27X36 cascade
# 28x18 A overflows 27 -> decomposition
# 12x12 -> 1 MULT12X12 (small cell, below MINWIDTH=13)
read_verilog mul_gw5a.v
chparam -set X_WIDTH 12 -set Y_WIDTH 12 -set A_WIDTH 24
hierarchy -top top
proc
synth_gowin -family gw5a
cd top
select -assert-count 1 t:MULT12X12
# 13x13 -> 1 MULTALU27X18 (MINWIDTH=13 cutoff routes to the large cell)
design -reset
read_verilog mul_gw5a.v
chparam -set X_WIDTH 13 -set Y_WIDTH 13 -set A_WIDTH 26
hierarchy -top top
proc
synth_gowin -family gw5a
cd top
select -assert-count 1 t:MULTALU27X18
# 27x18 -> 1 MULTALU27X18 (exact fit of the large cell)
design -reset
read_verilog mul_gw5a.v
chparam -set X_WIDTH 27 -set Y_WIDTH 18 -set A_WIDTH 45
hierarchy -top top
proc
synth_gowin -family gw5a
cd top
select -assert-count 1 t:MULTALU27X18
# 28x18 -> A overflows 27: 1 MULTALU27X18 + MULT12X12 partials
design -reset
read_verilog mul_gw5a.v
chparam -set X_WIDTH 28 -set Y_WIDTH 18 -set A_WIDTH 46
hierarchy -top top
proc
synth_gowin -family gw5a
cd top
select -assert-count 1 t:MULTALU27X18
select -assert-count 2 t:MULT12X12
# 27x19 -> B overflows 18: routes to MULT27X36 (2 cascaded DSPs)
design -reset
read_verilog mul_gw5a.v
chparam -set X_WIDTH 27 -set Y_WIDTH 19 -set A_WIDTH 46
hierarchy -top top
proc
synth_gowin -family gw5a
cd top
select -assert-count 1 t:MULT27X36
# Make sure that DSPs are not inferred with -nodsp option
design -reset
read_verilog mul_gw5a.v
chparam -set X_WIDTH 27 -set Y_WIDTH 18 -set A_WIDTH 45
hierarchy -top top
proc
synth_gowin -family gw5a -nodsp
cd top
select -assert-none t:MULTALU27X18
select -assert-none t:MULT12X12