mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-20 14:15:49 +00:00
Merge from main
This commit is contained in:
commit
2b247d165b
30 changed files with 722 additions and 125 deletions
|
|
@ -12,3 +12,4 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map_gw5a.v))
|
|||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt))
|
||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v))
|
||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt))
|
||||
$(eval $(call add_share_file,share/gowin,techlibs/gowin/dsp_map.v))
|
||||
|
|
|
|||
70
techlibs/gowin/dsp_map.v
Normal file
70
techlibs/gowin/dsp_map.v
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
module \$__MUL9X9 (input [8:0] A, input [8:0] B, output [17:0] Y);
|
||||
|
||||
parameter A_WIDTH = 9;
|
||||
parameter B_WIDTH = 9;
|
||||
parameter Y_WIDTH = 18;
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
|
||||
MULT9X9 __TECHMAP_REPLACE__ (
|
||||
.CLK(1'b0),
|
||||
.CE(1'b0),
|
||||
.RESET(1'b0),
|
||||
.A(A),
|
||||
.SIA({A_WIDTH{1'b0}}),
|
||||
.ASEL(1'b0),
|
||||
.ASIGN(A_SIGNED ? 1'b1 : 1'b0),
|
||||
.B(B),
|
||||
.SIB({B_WIDTH{1'b0}}),
|
||||
.BSEL(1'b0),
|
||||
.BSIGN(B_SIGNED ? 1'b1 : 1'b0),
|
||||
.DOUT(Y)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
|
||||
|
||||
parameter A_WIDTH = 18;
|
||||
parameter B_WIDTH = 18;
|
||||
parameter Y_WIDTH = 36;
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
|
||||
MULT18X18 __TECHMAP_REPLACE__ (
|
||||
.CLK(1'b0),
|
||||
.CE(1'b0),
|
||||
.RESET(1'b0),
|
||||
.A(A),
|
||||
.SIA({A_WIDTH{1'b0}}),
|
||||
.ASEL(1'b0),
|
||||
.ASIGN(A_SIGNED ? 1'b1 : 1'b0),
|
||||
.B(B),
|
||||
.SIB({B_WIDTH{1'b0}}),
|
||||
.BSEL(1'b0),
|
||||
.BSIGN(B_SIGNED ? 1'b1 : 1'b0),
|
||||
.DOUT(Y)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
module \$__MUL36X36 (input [35:0] A, input [35:0] B, output [71:0] Y);
|
||||
|
||||
parameter A_WIDTH = 36;
|
||||
parameter B_WIDTH = 36;
|
||||
parameter Y_WIDTH = 72;
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
|
||||
MULT36X36 __TECHMAP_REPLACE__ (
|
||||
.CLK(1'b0),
|
||||
.RESET(1'b0),
|
||||
.CE(1'b0),
|
||||
.A(A),
|
||||
.ASIGN(A_SIGNED ? 1'b1 : 1'b0),
|
||||
.B(B),
|
||||
.BSIGN(B_SIGNED ? 1'b1 : 1'b0),
|
||||
.DOUT(Y)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
@ -29,6 +29,21 @@ struct SynthGowinPass : public ScriptPass
|
|||
{
|
||||
SynthGowinPass() : ScriptPass("synth_gowin", "synthesis for Gowin FPGAs") { }
|
||||
|
||||
struct DSPRule {
|
||||
int a_maxwidth;
|
||||
int b_maxwidth;
|
||||
int a_minwidth;
|
||||
int b_minwidth;
|
||||
std::string prim;
|
||||
};
|
||||
|
||||
const std::vector<DSPRule> dsp_rules = {
|
||||
{36, 36, 22, 22, "$__MUL36X36"},
|
||||
{18, 18, 10, 4, "$__MUL18X18"},
|
||||
{18, 18, 4, 10, "$__MUL18X18"},
|
||||
{9, 9, 4, 4, "$__MUL9X9"},
|
||||
};
|
||||
|
||||
void help() override
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
|
|
@ -97,13 +112,16 @@ struct SynthGowinPass : public ScriptPass
|
|||
log(" -setundef\n");
|
||||
log(" set undriven wires and parameters to zero\n");
|
||||
log("\n");
|
||||
log(" -nodsp\n");
|
||||
log(" do not infer DSP multipliers\n");
|
||||
log("\n");
|
||||
log("The following commands are executed by this synthesis command:\n");
|
||||
help_script();
|
||||
log("\n");
|
||||
}
|
||||
|
||||
string top_opt, vout_file, json_file, family;
|
||||
bool retime, nobram, nolutram, flatten, nodffe, strict_gw5a_dffs, nowidelut, abc9, noiopads, noalu, no_rw_check, setundef;
|
||||
bool retime, nobram, nolutram, flatten, nodffe, strict_gw5a_dffs, nowidelut, abc9, noiopads, noalu, no_rw_check, setundef, nodsp;
|
||||
|
||||
void clear_flags() override
|
||||
{
|
||||
|
|
@ -123,6 +141,7 @@ struct SynthGowinPass : public ScriptPass
|
|||
noalu = false;
|
||||
no_rw_check = false;
|
||||
setundef = false;
|
||||
nodsp = false;
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
|
|
@ -209,6 +228,10 @@ struct SynthGowinPass : public ScriptPass
|
|||
setundef = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nodsp") {
|
||||
nodsp = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
@ -239,17 +262,40 @@ struct SynthGowinPass : public ScriptPass
|
|||
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt));
|
||||
}
|
||||
|
||||
if (flatten && check_label("flatten", "(unless -noflatten)"))
|
||||
{
|
||||
run("proc");
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
}
|
||||
|
||||
if (check_label("coarse"))
|
||||
{
|
||||
run("synth -run coarse" + no_rw_check_opt);
|
||||
run("proc");
|
||||
if (flatten || help_mode)
|
||||
run("flatten", "(unless -noflatten)");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
run("opt_expr");
|
||||
run("opt_clean");
|
||||
run("check");
|
||||
run("opt -nodffe -nosdff");
|
||||
run("fsm");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
run("share");
|
||||
|
||||
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)");
|
||||
} 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",
|
||||
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.v");
|
||||
}
|
||||
|
||||
run("alumacc");
|
||||
run("opt");
|
||||
run("memory -nomap" + no_rw_check_opt);
|
||||
run("opt_clean");
|
||||
}
|
||||
|
||||
if (check_label("map_ram"))
|
||||
|
|
|
|||
|
|
@ -263,6 +263,7 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
|
|||
log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp));
|
||||
|
||||
log_debug("preAdd: %s\n", log_id(st.preAdd, "--"));
|
||||
log_debug("preSub: %s\n", log_id(st.preSub, "--"));
|
||||
log_debug("ffAD: %s\n", log_id(st.ffAD, "--"));
|
||||
log_debug("ffA2: %s\n", log_id(st.ffA2, "--"));
|
||||
log_debug("ffA1: %s\n", log_id(st.ffA1, "--"));
|
||||
|
|
@ -278,17 +279,22 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
|
|||
|
||||
Cell *cell = st.dsp;
|
||||
|
||||
if (st.preAdd) {
|
||||
log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type));
|
||||
bool A_SIGNED = st.preAdd->getParam(ID::A_SIGNED).as_bool();
|
||||
bool D_SIGNED = st.preAdd->getParam(ID::B_SIGNED).as_bool();
|
||||
if (st.sigA == st.preAdd->getPort(ID::B))
|
||||
if (st.preAdd || st.preSub) {
|
||||
Cell* preAdder = st.preAdd ? st.preAdd : st.preSub;
|
||||
|
||||
log(" preadder %s (%s)\n", log_id(preAdder), log_id(preAdder->type));
|
||||
bool A_SIGNED = preAdder->getParam(ID::A_SIGNED).as_bool();
|
||||
bool D_SIGNED = preAdder->getParam(ID::B_SIGNED).as_bool();
|
||||
if (st.sigA == preAdder->getPort(ID::B))
|
||||
std::swap(A_SIGNED, D_SIGNED);
|
||||
st.sigA.extend_u0(30, A_SIGNED);
|
||||
st.sigD.extend_u0(25, D_SIGNED);
|
||||
cell->setPort(ID::A, st.sigA);
|
||||
cell->setPort(ID::D, st.sigD);
|
||||
cell->setPort(ID(INMODE), Const::from_string("00100"));
|
||||
if (preAdder->type == ID($add))
|
||||
cell->setPort(ID(INMODE), Const::from_string("00100"));
|
||||
else
|
||||
cell->setPort(ID(INMODE), Const::from_string("01100"));
|
||||
|
||||
if (st.ffAD) {
|
||||
if (st.ffAD->type.in(ID($dffe), ID($sdffe))) {
|
||||
|
|
@ -303,7 +309,7 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm)
|
|||
|
||||
cell->setParam(ID(USE_DPORT), Const("TRUE"));
|
||||
|
||||
pm.autoremove(st.preAdd);
|
||||
pm.autoremove(preAdder);
|
||||
}
|
||||
if (st.postAdd) {
|
||||
log(" postadder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type));
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
// If ADREG matched, treat 'A' input as input of ADREG
|
||||
// ( 3) Match the driver of the 'A' and 'D' inputs for a possible $add cell
|
||||
// (pre-adder)
|
||||
// (3.1) Match the driver of the 'A' and 'D' inputs for a possible $sub cell
|
||||
// (pre-adder)
|
||||
// ( 4) If pre-adder was present, find match 'A' input for A2REG
|
||||
// If pre-adder was not present, move ADREG to A2REG
|
||||
// If A2REG, then match 'A' input for A1REG
|
||||
|
|
@ -152,13 +154,41 @@ code sigA sigD
|
|||
}
|
||||
endcode
|
||||
|
||||
// (3.1) Match the driver of the 'A' and 'D' inputs for a possible $sub cell
|
||||
// (pre-adder)
|
||||
match preSub
|
||||
if sigD.empty() || sigD.is_fully_zero()
|
||||
// Ensure that preAdder not already used
|
||||
if param(dsp, \USE_DPORT).decode_string() == "FALSE"
|
||||
if port(dsp, \INMODE, Const(0, 5)).is_fully_zero()
|
||||
|
||||
select preSub->type.in($sub)
|
||||
// Output has to be 25 bits or less
|
||||
select GetSize(port(preSub, \Y)) <= 25
|
||||
select nusers(port(preSub, \Y)) == 2
|
||||
// D port has to be 25 bits or less
|
||||
select GetSize(port(preSub, \A)) <= 25
|
||||
// A port has to be 30 bits or less
|
||||
select GetSize(port(preSub, \B)) <= 30
|
||||
index <SigSpec> port(preSub, \Y) === sigA
|
||||
|
||||
optional
|
||||
endmatch
|
||||
|
||||
code sigA sigD
|
||||
if (preSub) {
|
||||
sigD = port(preSub, \A);
|
||||
sigA = port(preSub, \B);
|
||||
}
|
||||
endcode
|
||||
|
||||
// (4) If pre-adder was present, find match 'A' input for A2REG
|
||||
// If pre-adder was not present, move ADREG to A2REG
|
||||
// Then match 'A' input for A1REG
|
||||
code argQ ffAD sigA clock ffA2 ffA1
|
||||
// Only search for ffA2 if there was a pre-adder
|
||||
// (otherwise ffA2 would have been matched as ffAD)
|
||||
if (preAdd) {
|
||||
if (preAdd || preSub) {
|
||||
if (param(dsp, \AREG).as_int() == 0) {
|
||||
argQ = sigA;
|
||||
subpattern(in_dffe);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue