mirror of
https://github.com/YosysHQ/yosys.git
synced 2026-10-06 01:53:53 +02:00
Infer MULTADDSUB36X36.
This commit is contained in:
@@ -105,14 +105,9 @@ module \$__NX_MUL9X9 (input [8:0] A, input [8:0] B, output [17:0] Y);
|
||||
);
|
||||
endmodule
|
||||
|
||||
module \$__NX_MAC18X18 (input [17:0] A, input [17:0] B, input [47:0] C, output [53:0] Y);
|
||||
module \$__NX_MAC18X18 (input [17:0] A, input [17:0] B, input [53:0] C, output [53:0] Y);
|
||||
|
||||
parameter A_WIDTH = 18;
|
||||
parameter B_WIDTH = 18;
|
||||
parameter C_WIDTH = 48;
|
||||
parameter Y_WIDTH = 48;
|
||||
parameter A_SIGNED = 0;
|
||||
parameter B_SIGNED = 0;
|
||||
parameter SUBTRACT = 0;
|
||||
|
||||
MULTADDSUB18X18 #(
|
||||
@@ -128,7 +123,34 @@ module \$__NX_MAC18X18 (input [17:0] A, input [17:0] B, input [47:0] C, output [
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.A(A),
|
||||
.B(B),
|
||||
.C({6'b0, C}),
|
||||
.C(C),
|
||||
.SIGNED(A_SIGNED ? 1'b1 : 1'b0),
|
||||
.ADDSUB(SUBTRACT ? 1'b1 : 1'b0),
|
||||
.LOADC(1'b1),
|
||||
.CIN(1'b0),
|
||||
.Z(Y)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module \$__NX_MAC36X36 (input [35:0] A, input [35:0] B, input [107:0] C, output [107:0] Y);
|
||||
|
||||
parameter A_SIGNED = 0;
|
||||
parameter SUBTRACT = 0;
|
||||
|
||||
MULTADDSUB36X36 #(
|
||||
.REGINPUTA("BYPASS"),
|
||||
.REGINPUTB("BYPASS"),
|
||||
.REGINPUTC("BYPASS"),
|
||||
.REGADDSUB("BYPASS"),
|
||||
.REGLOADC("BYPASS"),
|
||||
.REGLOADC2("BYPASS"),
|
||||
.REGCIN("BYPASS"),
|
||||
.REGPIPELINE("BYPASS"),
|
||||
.REGOUTPUT("BYPASS")
|
||||
) _TECHMAP_REPLACE_ (
|
||||
.A(A),
|
||||
.B(B),
|
||||
.C(C),
|
||||
.SIGNED(A_SIGNED ? 1'b1 : 1'b0),
|
||||
.ADDSUB(SUBTRACT ? 1'b1 : 1'b0),
|
||||
.LOADC(1'b1),
|
||||
@@ -161,7 +183,7 @@ module \$__NX_PREADD18X18 (input [17:0] A, input [17:0] B, input [17:0] C, input
|
||||
);
|
||||
endmodule
|
||||
|
||||
module \$__NX_MAC9X9WIDE_4LANE (input [8:0] A0, B0, A1, B1, A2, B2, A3, B3, output [53:0] Y);
|
||||
module \$__NX_MAC9X9WIDE_4LANE (input [8:0] A0, B0, A1, B1, A2, B2, A3, B3, input [53:0] C, output [53:0] Y);
|
||||
|
||||
parameter SIGNED = 0;
|
||||
|
||||
@@ -181,7 +203,7 @@ module \$__NX_MAC9X9WIDE_4LANE (input [8:0] A0, B0, A1, B1, A2, B2, A3, B3, outp
|
||||
.A1(A1), .B1(B1),
|
||||
.A2(A2), .B2(B2),
|
||||
.A3(A3), .B3(B3),
|
||||
.C(54'b0),
|
||||
.C(C),
|
||||
.SIGNED(SIGNED ? 1'b1 : 1'b0),
|
||||
.ADDSUB(4'b0000),
|
||||
.LOADC(1'b1),
|
||||
|
||||
@@ -4,6 +4,38 @@
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
// $add and $sub are signed only if both operands are
|
||||
bool nexus_add_signed(Cell *add) { return add->getParam(ID::A_SIGNED).as_bool() && add->getParam(ID::B_SIGNED).as_bool(); }
|
||||
|
||||
// Bits [0, width) of the exact product of mul, or empty if its Y cuts them off
|
||||
SigSpec nexus_product_bits(Cell *mul, const SigSpec &mul_y, int width)
|
||||
{
|
||||
int full_width = GetSize(mul->getPort(ID::A)) + GetSize(mul->getPort(ID::B));
|
||||
if (GetSize(mul_y) < width && GetSize(mul_y) < full_width)
|
||||
return SigSpec();
|
||||
|
||||
SigSpec bits = mul_y;
|
||||
bits.extend_u0(width, mul->getParam(ID::A_SIGNED).as_bool());
|
||||
return bits;
|
||||
}
|
||||
|
||||
// Bits [0, width) of a partial sum, or empty if it is narrower
|
||||
SigSpec nexus_sum_bits(const SigSpec &sum_y, int width)
|
||||
{
|
||||
if (GetSize(sum_y) < width)
|
||||
return SigSpec();
|
||||
return sum_y.extract(0, width);
|
||||
}
|
||||
|
||||
// True if an adder operand, extended as the adder does, is value
|
||||
bool nexus_operand_is(SigSpec operand, bool add_signed, const SigSpec &value)
|
||||
{
|
||||
if (value.empty())
|
||||
return false;
|
||||
operand.extend_u0(GetSize(value), add_signed);
|
||||
return operand == value;
|
||||
}
|
||||
|
||||
#include "techlibs/lattice/lattice_dsp_nexus_pm.h"
|
||||
|
||||
struct LatticeDspNexusPass : public Pass {
|
||||
@@ -14,10 +46,10 @@ struct LatticeDspNexusPass : public Pass {
|
||||
log("\n");
|
||||
log(" lattice_dsp_nexus [options] [selection]\n");
|
||||
log("\n");
|
||||
log("Infer Lattice Nexus sysDSP macrocells (MULTADDSUB18X18, MULTPREADD18X18,\n");
|
||||
log("MULTADDSUB9X9WIDE) from MAC and dot-product patterns, and absorb the\n");
|
||||
log("pipeline flip-flops around bare MULT18X18 / MULT36X36 multipliers into\n");
|
||||
log("the hardened DSP input and output registers.\n");
|
||||
log("Infer Lattice Nexus sysDSP macrocells (MULTADDSUB18X18, MULTADDSUB36X36,\n");
|
||||
log("MULTPREADD18X18, MULTADDSUB9X9WIDE) from MAC and dot-product patterns, and\n");
|
||||
log("absorb the pipeline flip-flops around bare MULT18X18 / MULT36X36 multipliers\n");
|
||||
log("into the hardened DSP input and output registers.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
@@ -29,7 +61,7 @@ struct LatticeDspNexusPass : public Pass {
|
||||
lattice_dsp_nexus_pm pm(module, module->cells());
|
||||
|
||||
pm.run_nexus_mac9_4lane();
|
||||
pm.run_nexus_mac18();
|
||||
pm.run_nexus_mac();
|
||||
pm.run_nexus_preadd18();
|
||||
pm.run_nexus_mul_reg();
|
||||
}
|
||||
|
||||
@@ -1,59 +1,218 @@
|
||||
pattern nexus_mac18
|
||||
pattern nexus_mac9_4lane
|
||||
|
||||
// maccmap -unmap adds the addends first, then one product per $add:
|
||||
// (((C + P0) + P1) + P2) + P3, or ((P0 + P1) + P2) + P3 without C
|
||||
|
||||
match add3
|
||||
select add3->type == $add
|
||||
select GetSize(port(add3, \Y)) <= 54
|
||||
endmatch
|
||||
|
||||
match mul3
|
||||
select mul3->type == $mul
|
||||
select GetSize(port(mul3, \A)) <= 9 && GetSize(port(mul3, \B)) <= 9
|
||||
select nusers(port(mul3, \Y)) == 2
|
||||
index <SigBit> port(mul3, \Y)[0] === port(add3, \B)[0]
|
||||
endmatch
|
||||
|
||||
match add2
|
||||
select add2->type == $add
|
||||
select nusers(port(add2, \Y)) == 2
|
||||
index <SigBit> port(add2, \Y)[0] === port(add3, \A)[0]
|
||||
endmatch
|
||||
|
||||
match mul2
|
||||
select mul2->type == $mul
|
||||
select GetSize(port(mul2, \A)) <= 9 && GetSize(port(mul2, \B)) <= 9
|
||||
select nusers(port(mul2, \Y)) == 2
|
||||
index <SigBit> port(mul2, \Y)[0] === port(add2, \B)[0]
|
||||
endmatch
|
||||
|
||||
match add1
|
||||
select add1->type == $add
|
||||
select nusers(port(add1, \Y)) == 2
|
||||
index <SigBit> port(add1, \Y)[0] === port(add2, \A)[0]
|
||||
endmatch
|
||||
|
||||
match mul1
|
||||
select mul1->type == $mul
|
||||
select GetSize(port(mul1, \A)) <= 9 && GetSize(port(mul1, \B)) <= 9
|
||||
select nusers(port(mul1, \Y)) == 2
|
||||
index <SigBit> port(mul1, \Y)[0] === port(add1, \B)[0]
|
||||
endmatch
|
||||
|
||||
// C + P0
|
||||
match add0
|
||||
select add0->type == $add
|
||||
select nusers(port(add0, \Y)) == 2
|
||||
index <SigBit> port(add0, \Y)[0] === port(add1, \A)[0]
|
||||
optional
|
||||
endmatch
|
||||
|
||||
match mul0
|
||||
select mul0->type == $mul
|
||||
select GetSize(port(mul0, \A)) <= 9 && GetSize(port(mul0, \B)) <= 9
|
||||
select nusers(port(mul0, \Y)) == 2
|
||||
index <SigBit> port(mul0, \Y)[0] === (add0 ? port(add0, \B)[0] : port(add1, \A)[0])
|
||||
endmatch
|
||||
|
||||
code
|
||||
{
|
||||
int width = GetSize(port(add3, \Y));
|
||||
bool is_signed = param(mul0, \A_SIGNED).as_bool();
|
||||
for (auto mul : {mul0, mul1, mul2, mul3})
|
||||
if (param(mul, \A_SIGNED).as_bool() != is_signed || param(mul, \B_SIGNED).as_bool() != is_signed)
|
||||
reject;
|
||||
|
||||
// Each adder must see the exact products and partial sums in the width of the top one
|
||||
SigSpec p0 = nexus_product_bits(mul0, port(mul0, \Y), width);
|
||||
SigSpec p1 = nexus_product_bits(mul1, port(mul1, \Y), width);
|
||||
SigSpec p2 = nexus_product_bits(mul2, port(mul2, \Y), width);
|
||||
SigSpec p3 = nexus_product_bits(mul3, port(mul3, \Y), width);
|
||||
SigSpec s1 = add0 ? nexus_sum_bits(port(add0, \Y), width) : p0;
|
||||
SigSpec s2 = nexus_sum_bits(port(add1, \Y), width);
|
||||
SigSpec s3 = nexus_sum_bits(port(add2, \Y), width);
|
||||
if (!nexus_operand_is(port(add3, \A), nexus_add_signed(add3), s3) || !nexus_operand_is(port(add3, \B), nexus_add_signed(add3), p3))
|
||||
reject;
|
||||
if (!nexus_operand_is(port(add2, \A), nexus_add_signed(add2), s2) || !nexus_operand_is(port(add2, \B), nexus_add_signed(add2), p2))
|
||||
reject;
|
||||
if (!nexus_operand_is(port(add1, \A), nexus_add_signed(add1), s1) || !nexus_operand_is(port(add1, \B), nexus_add_signed(add1), p1))
|
||||
reject;
|
||||
if (add0 && !nexus_operand_is(port(add0, \B), nexus_add_signed(add0), p0))
|
||||
reject;
|
||||
|
||||
SigSpec sigC;
|
||||
if (add0) {
|
||||
sigC = port(add0, \A);
|
||||
sigC.extend_u0(width, nexus_add_signed(add0));
|
||||
// C must not read cells that are removed
|
||||
for (auto cell : {mul0, mul1, mul2, mul3, add0, add1, add2, add3})
|
||||
if (!sigC.extract(port(cell, \Y)).empty())
|
||||
reject;
|
||||
}
|
||||
sigC.extend_u0(54, false);
|
||||
|
||||
SigSpec sigY = port(add3, \Y);
|
||||
if (width < 54)
|
||||
sigY.append(module->addWire(NEW_ID, 54 - width));
|
||||
|
||||
Cell *mac = module->addCell(NEW_ID, "$__NX_MAC9X9WIDE_4LANE");
|
||||
int i = 0;
|
||||
for (auto mul : {mul0, mul1, mul2, mul3}) {
|
||||
SigSpec sigA = port(mul, \A);
|
||||
SigSpec sigB = port(mul, \B);
|
||||
sigA.extend_u0(9, is_signed);
|
||||
sigB.extend_u0(9, is_signed);
|
||||
mac->setPort(stringf("\\A%d", i), sigA);
|
||||
mac->setPort(stringf("\\B%d", i), sigB);
|
||||
i++;
|
||||
}
|
||||
mac->setPort(\C, sigC);
|
||||
mac->setPort(\Y, sigY);
|
||||
mac->setParam(\SIGNED, is_signed ? State::S1 : State::S0);
|
||||
|
||||
for (auto cell : {mul0, mul1, mul2, mul3, add0, add1, add2, add3})
|
||||
autoremove(cell);
|
||||
}
|
||||
|
||||
accept;
|
||||
endcode
|
||||
|
||||
pattern nexus_mac
|
||||
|
||||
state <IdString> add_AB add_C mux_add mux_mul
|
||||
|
||||
match mul
|
||||
select mul->type.in($mul)
|
||||
select GetSize(port(mul, \A)) <= 18
|
||||
select GetSize(port(mul, \B)) <= 18
|
||||
select GetSize(port(mul, \Y)) <= 48
|
||||
select param(mul, \A_SIGNED).as_bool() == param(mul, \B_SIGNED).as_bool()
|
||||
select GetSize(port(mul, \A)) <= 36
|
||||
select GetSize(port(mul, \B)) <= 36
|
||||
endmatch
|
||||
|
||||
match add
|
||||
select add->type.in($add, $sub)
|
||||
select GetSize(port(add, \Y)) <= 48
|
||||
select GetSize(port(add, \Y)) <= 108
|
||||
choice <IdString> AB {\A, \B}
|
||||
define <IdString> BA (AB == \A ? \B : \A)
|
||||
filter add->type == $add || AB == \B
|
||||
index <SigBit> port(add, AB)[0] === port(mul, \Y)[0]
|
||||
set add_AB AB
|
||||
set add_C BA
|
||||
endmatch
|
||||
|
||||
// Clear: S ? A * B : C + A * B becomes (S ? 0 : C) + A * B
|
||||
match mux
|
||||
select mux->type == $mux
|
||||
choice <IdString> AB {\A, \B}
|
||||
define <IdString> BA (AB == \A ? \B : \A)
|
||||
index <SigSpec> port(mux, AB) === port(add, \Y)
|
||||
set mux_add AB
|
||||
set mux_mul BA
|
||||
optional
|
||||
endmatch
|
||||
|
||||
code
|
||||
if (mul->getParam(\A_SIGNED).as_bool() != mul->getParam(\B_SIGNED).as_bool()) {
|
||||
reject;
|
||||
}
|
||||
|
||||
{
|
||||
SigSpec mul_out = port(mul, \Y);
|
||||
IdString add_AB;
|
||||
int width = GetSize(port(add, \Y));
|
||||
bool add_signed = nexus_add_signed(add);
|
||||
SigSpec product = nexus_product_bits(mul, port(mul, \Y), width);
|
||||
if (!nexus_operand_is(port(add, add_AB), add_signed, product))
|
||||
reject;
|
||||
|
||||
if (GetSize(port(add, \A)) >= GetSize(mul_out) && port(add, \A).extract(0, GetSize(mul_out)) == mul_out) {
|
||||
add_AB = \A;
|
||||
} else if (GetSize(port(add, \B)) >= GetSize(mul_out) && port(add, \B).extract(0, GetSize(mul_out)) == mul_out) {
|
||||
add_AB = \B;
|
||||
} else {
|
||||
SigSpec sigC = port(add, add_C);
|
||||
if (!sigC.extract(port(mul, \Y)).empty())
|
||||
reject;
|
||||
|
||||
if (mux) {
|
||||
if (add->type != $add || port(mux, mux_mul) != product)
|
||||
reject;
|
||||
// Don't read removed cells
|
||||
SigSpec sel = port(mux, \S);
|
||||
if (!sel.extract(port(mul, \Y)).empty() || !sel.extract(port(add, \Y)).empty())
|
||||
reject;
|
||||
if (nusers(port(mul, \Y)) != 3 || nusers(port(add, \Y)) != 2)
|
||||
reject;
|
||||
} else if (nusers(port(mul, \Y)) != 2) {
|
||||
reject;
|
||||
}
|
||||
|
||||
if (add->type == $sub && add_AB == \A)
|
||||
bool small = GetSize(port(mul, \A)) <= 18 && GetSize(port(mul, \B)) <= 18;
|
||||
// Narrow muls don't take a whole 36x36 block for a wide sum
|
||||
if (small && width > 54)
|
||||
reject;
|
||||
int ab_width = small ? 18 : 36;
|
||||
int z_width = small ? 54 : 108;
|
||||
|
||||
Cell *mac = module->addCell(NEW_ID, "$__NX_MAC18X18");
|
||||
IdString add_C = (add_AB == \A) ? \B : \A;
|
||||
|
||||
bool ab_signed = mul->getParam(\A_SIGNED).as_bool();
|
||||
bool ab_signed = param(mul, \A_SIGNED).as_bool();
|
||||
SigSpec sigA = port(mul, \A);
|
||||
SigSpec sigB = port(mul, \B);
|
||||
SigSpec sigC = port(add, add_C);
|
||||
sigA.extend_u0(18, ab_signed);
|
||||
sigB.extend_u0(18, ab_signed);
|
||||
sigC.extend_u0(48, ab_signed);
|
||||
SigSpec sigY = mux ? port(mux, \Y) : port(add, \Y);
|
||||
sigA.extend_u0(ab_width, ab_signed);
|
||||
sigB.extend_u0(ab_width, ab_signed);
|
||||
sigC.extend_u0(width, add_signed);
|
||||
if (mux) {
|
||||
SigSpec zero(State::S0, width);
|
||||
SigSpec sel = port(mux, \S);
|
||||
if (mux_add == \A)
|
||||
sigC = module->Mux(NEW_ID, sigC, zero, sel);
|
||||
else
|
||||
sigC = module->Mux(NEW_ID, zero, sigC, sel);
|
||||
}
|
||||
sigC.extend_u0(z_width, false);
|
||||
if (width < z_width)
|
||||
sigY.append(module->addWire(NEW_ID, z_width - width));
|
||||
|
||||
Cell *mac = module->addCell(NEW_ID, small ? "$__NX_MAC18X18" : "$__NX_MAC36X36");
|
||||
mac->setPort(\A, sigA);
|
||||
mac->setPort(\B, sigB);
|
||||
mac->setPort(\C, sigC);
|
||||
mac->setPort(\Y, port(add, \Y));
|
||||
mac->setParam(\A_SIGNED, mul->getParam(\A_SIGNED));
|
||||
mac->setPort(\Y, sigY);
|
||||
mac->setParam(\A_SIGNED, param(mul, \A_SIGNED));
|
||||
mac->setParam(\SUBTRACT, add->type == $sub ? State::S1 : State::S0);
|
||||
|
||||
autoremove(mul);
|
||||
autoremove(add);
|
||||
autoremove(mux);
|
||||
}
|
||||
|
||||
accept;
|
||||
@@ -134,92 +293,6 @@ code
|
||||
accept;
|
||||
endcode
|
||||
|
||||
pattern nexus_mac9_4lane
|
||||
|
||||
match add_top
|
||||
select add_top->type == $add
|
||||
endmatch
|
||||
|
||||
match add_mid
|
||||
select add_mid->type == $add
|
||||
index <SigBit> port(add_mid, \Y)[0] === port(add_top, \A)[0]
|
||||
endmatch
|
||||
|
||||
match add_bot
|
||||
select add_bot->type == $add
|
||||
index <SigBit> port(add_bot, \Y)[0] === port(add_mid, \A)[0]
|
||||
endmatch
|
||||
|
||||
match mul3
|
||||
select mul3->type == $mul
|
||||
select GetSize(port(mul3, \A)) <= 9 && GetSize(port(mul3, \B)) <= 9
|
||||
index <SigBit> port(mul3, \Y)[0] === port(add_top, \B)[0]
|
||||
endmatch
|
||||
|
||||
match mul2
|
||||
select mul2->type == $mul
|
||||
select GetSize(port(mul2, \A)) <= 9 && GetSize(port(mul2, \B)) <= 9
|
||||
index <SigBit> port(mul2, \Y)[0] === port(add_mid, \B)[0]
|
||||
endmatch
|
||||
|
||||
match mul1
|
||||
select mul1->type == $mul
|
||||
select GetSize(port(mul1, \A)) <= 9 && GetSize(port(mul1, \B)) <= 9
|
||||
index <SigBit> port(mul1, \Y)[0] === port(add_bot, \B)[0]
|
||||
endmatch
|
||||
|
||||
match mul0
|
||||
select mul0->type == $mul
|
||||
select GetSize(port(mul0, \A)) <= 9 && GetSize(port(mul0, \B)) <= 9
|
||||
index <SigBit> port(mul0, \Y)[0] === port(add_bot, \A)[0]
|
||||
endmatch
|
||||
|
||||
code
|
||||
bool is_signed = mul0->getParam(\A_SIGNED).as_bool();
|
||||
|
||||
if (
|
||||
mul0->getParam(\B_SIGNED).as_bool() != is_signed ||
|
||||
mul1->getParam(\A_SIGNED).as_bool() != is_signed ||
|
||||
mul1->getParam(\B_SIGNED).as_bool() != is_signed ||
|
||||
mul2->getParam(\A_SIGNED).as_bool() != is_signed ||
|
||||
mul2->getParam(\B_SIGNED).as_bool() != is_signed ||
|
||||
mul3->getParam(\A_SIGNED).as_bool() != is_signed ||
|
||||
mul3->getParam(\B_SIGNED).as_bool() != is_signed
|
||||
) {
|
||||
reject;
|
||||
}
|
||||
|
||||
{
|
||||
Cell *mac = module->addCell(NEW_ID, "$__NX_MAC9X9WIDE_4LANE");
|
||||
|
||||
auto ext9 = [&](SigSpec s) {
|
||||
s.extend_u0(9, is_signed);
|
||||
return s;
|
||||
};
|
||||
|
||||
mac->setPort(\A0, ext9(port(mul0, \A)));
|
||||
mac->setPort(\B0, ext9(port(mul0, \B)));
|
||||
mac->setPort(\A1, ext9(port(mul1, \A)));
|
||||
mac->setPort(\B1, ext9(port(mul1, \B)));
|
||||
mac->setPort(\A2, ext9(port(mul2, \A)));
|
||||
mac->setPort(\B2, ext9(port(mul2, \B)));
|
||||
mac->setPort(\A3, ext9(port(mul3, \A)));
|
||||
mac->setPort(\B3, ext9(port(mul3, \B)));
|
||||
mac->setPort(\Y, port(add_top, \Y));
|
||||
mac->setParam(\SIGNED, is_signed ? State::S1 : State::S0);
|
||||
|
||||
autoremove(add_top);
|
||||
autoremove(add_mid);
|
||||
autoremove(add_bot);
|
||||
autoremove(mul0);
|
||||
autoremove(mul1);
|
||||
autoremove(mul2);
|
||||
autoremove(mul3);
|
||||
}
|
||||
|
||||
accept;
|
||||
endcode
|
||||
|
||||
pattern nexus_mul_reg
|
||||
|
||||
state <SigBit> clk
|
||||
|
||||
@@ -55,8 +55,8 @@ module dot4 (
|
||||
assign p = p_r;
|
||||
endmodule
|
||||
|
||||
// Oversized 24x24 MAC
|
||||
module neg_mac24 (input clk, clear, input [23:0] a, b, output [47:0] p);
|
||||
// 24x24 MAC
|
||||
module mac24 (input clk, clear, input [23:0] a, b, output [47:0] p);
|
||||
reg [23:0] a_r, b_r; reg [47:0] p_r; reg clear_r;
|
||||
always_ff @(posedge clk) begin
|
||||
a_r <= a; b_r <= b; clear_r <= clear;
|
||||
@@ -75,6 +75,35 @@ module neg_dot_mixed (input clk, input [8:0] a0,b0,a1,b1, input [17:0] a2, b2, o
|
||||
assign p = p_r;
|
||||
endmodule
|
||||
|
||||
// https://github.com/YosysHQ/yosys/issues/6233
|
||||
|
||||
module mac36 (input [35:0] a, b, input [107:0] c, output [107:0] y);
|
||||
assign y = c + a * b;
|
||||
endmodule
|
||||
|
||||
module msub36 (input [35:0] a, b, input [107:0] c, output [107:0] y);
|
||||
assign y = c - a * b;
|
||||
endmodule
|
||||
|
||||
module neg_mulsub36 (input [35:0] a, b, input [107:0] c, output [107:0] y);
|
||||
assign y = a * b - c;
|
||||
endmodule
|
||||
|
||||
module mac16 (input [15:0] a, b, input [51:0] c, output [51:0] y);
|
||||
assign y = c + a * b;
|
||||
endmodule
|
||||
|
||||
module dot4_acc (input [8:0] a0, b0, a1, b1, a2, b2, a3, b3, input [53:0] c, output [53:0] y);
|
||||
assign y = a0*b0 + a1*b1 + a2*b2 + a3*b3 + c;
|
||||
endmodule
|
||||
|
||||
// The mux select reads the product
|
||||
module mac_sel (input [3:0] a, b, input [5:0] c, output [5:0] y);
|
||||
wire [7:0] p = a * b;
|
||||
wire [5:0] s = c + p[5:0];
|
||||
assign y = p[7] ? p[5:0] : s;
|
||||
endmodule
|
||||
|
||||
// The pre-adder result is also an output
|
||||
module preadd_fanout (input [5:0] a, b, d, output [15:0] p, output [6:0] q);
|
||||
assign q = a + d;
|
||||
|
||||
@@ -9,6 +9,11 @@ synth_nexus -family lifcl -top mac
|
||||
select -assert-count 1 t:MULTADDSUB18X18
|
||||
select -assert-count 0 t:CCU2
|
||||
|
||||
design -load pristine
|
||||
hierarchy -top mac;
|
||||
synth_nexus -family lifcl -top mac -run begin:map_ram
|
||||
check -assert
|
||||
|
||||
# 18x18 pre-add MAC
|
||||
design -load pristine
|
||||
hierarchy -top madd_pre;
|
||||
@@ -23,9 +28,10 @@ select -assert-count 1 t:MULTADDSUB9X9WIDE
|
||||
|
||||
# 24x24 MAC
|
||||
design -load pristine
|
||||
hierarchy -top neg_mac24;
|
||||
synth_nexus -family lifcl -top neg_mac24
|
||||
hierarchy -top mac24;
|
||||
synth_nexus -family lifcl -top mac24
|
||||
select -assert-count 0 t:MULTADDSUB18X18
|
||||
select -assert-count 1 t:MULTADDSUB36X36
|
||||
|
||||
# mixed
|
||||
design -load pristine
|
||||
@@ -34,7 +40,46 @@ synth_nexus -family lifcl -top neg_dot_mixed
|
||||
select -assert-count 0 t:MULTADDSUB9X9WIDE
|
||||
select -assert-count 2 t:MULTADDSUB18X18
|
||||
|
||||
# 36x36 MAC
|
||||
design -load pristine
|
||||
hierarchy -top mac36;
|
||||
synth_nexus -family lifcl -top mac36
|
||||
select -assert-count 1 t:MULTADDSUB36X36
|
||||
select -assert-count 0 t:CCU2
|
||||
|
||||
# 36x36 C - A*B
|
||||
design -load pristine
|
||||
hierarchy -top msub36;
|
||||
synth_nexus -family lifcl -top msub36
|
||||
select -assert-count 1 t:MULTADDSUB36X36
|
||||
select -assert-count 0 t:CCU2
|
||||
|
||||
# A*B - C is not a DSP operation
|
||||
design -load pristine
|
||||
hierarchy -top neg_mulsub36;
|
||||
synth_nexus -family lifcl -top neg_mulsub36
|
||||
select -assert-count 0 t:MULTADDSUB36X36
|
||||
|
||||
# 16x16 MAC with a 52-bit sum stays on the 18x18 cell
|
||||
design -load pristine
|
||||
hierarchy -top mac16;
|
||||
synth_nexus -family lifcl -top mac16
|
||||
select -assert-count 1 t:MULTADDSUB18X18
|
||||
select -assert-count 0 t:MULTADDSUB36X36
|
||||
|
||||
# 4-lane 9x9 dot product with addend
|
||||
design -load pristine
|
||||
hierarchy -top dot4_acc;
|
||||
synth_nexus -family lifcl -top dot4_acc
|
||||
select -assert-count 1 t:MULTADDSUB9X9WIDE
|
||||
select -assert-count 0 t:CCU2
|
||||
|
||||
# Cells read elsewhere must not be removed
|
||||
design -load pristine
|
||||
hierarchy -top mac_sel;
|
||||
proc
|
||||
equiv_opt -assert -map +/lattice/cells_sim_nexus.v synth_nexus -family lifcl -top mac_sel -run begin:map_ram
|
||||
|
||||
design -load pristine
|
||||
hierarchy -top preadd_fanout;
|
||||
proc
|
||||
|
||||
Reference in New Issue
Block a user