mirror of https://github.com/YosysHQ/yosys.git
Merge c1450b54e4 into 4821ed17b4
This commit is contained in:
commit
017e4b83dd
|
|
@ -41,18 +41,22 @@ struct AlumaccWorker
|
|||
std::vector<RTLIL::Cell*> cells;
|
||||
RTLIL::SigSpec a, b, c, y;
|
||||
std::vector<tuple<bool, bool, bool, bool, bool, RTLIL::SigSpec>> cmp;
|
||||
bool is_signed, invert_b;
|
||||
bool is_signed, invert_b, oversized;
|
||||
|
||||
RTLIL::Cell *alu_cell;
|
||||
RTLIL::SigSpec cached_lt, cached_slt, cached_gt, cached_sgt, cached_eq, cached_ne;
|
||||
RTLIL::SigSpec cached_cf, cached_of, cached_sf;
|
||||
|
||||
RTLIL::SigSpec get_lt(bool is_signed) {
|
||||
if (is_signed) {
|
||||
RTLIL::SigSpec get_lt(bool this_signed) {
|
||||
if (this_signed) {
|
||||
if (GetSize(cached_slt) == 0) {
|
||||
get_of();
|
||||
get_sf();
|
||||
cached_slt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf);
|
||||
if (is_signed && oversized) {
|
||||
cached_slt = cached_sf;
|
||||
} else {
|
||||
get_of();
|
||||
cached_slt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf);
|
||||
}
|
||||
}
|
||||
|
||||
return cached_slt;
|
||||
|
|
@ -65,10 +69,10 @@ struct AlumaccWorker
|
|||
}
|
||||
}
|
||||
|
||||
RTLIL::SigSpec get_gt(bool is_signed) {
|
||||
if (is_signed) {
|
||||
RTLIL::SigSpec get_gt(bool this_signed) {
|
||||
if (this_signed) {
|
||||
if (GetSize(cached_sgt) == 0) {
|
||||
get_lt(is_signed);
|
||||
get_lt(this_signed);
|
||||
get_eq();
|
||||
SigSpec Or = alu_cell->module->Or(NEW_ID, cached_slt, cached_eq);
|
||||
cached_sgt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute());
|
||||
|
|
@ -77,7 +81,7 @@ struct AlumaccWorker
|
|||
return cached_sgt;
|
||||
} else {
|
||||
if (GetSize(cached_gt) == 0) {
|
||||
get_lt(is_signed);
|
||||
get_lt(this_signed);
|
||||
get_eq();
|
||||
SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq);
|
||||
cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute());
|
||||
|
|
@ -112,7 +116,14 @@ struct AlumaccWorker
|
|||
if (GetSize(cached_of) == 0) {
|
||||
cached_of = {alu_cell->getPort(ID::CO), alu_cell->getPort(ID::CI)};
|
||||
log_assert(GetSize(cached_of) >= 2);
|
||||
cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]);
|
||||
if (oversized) {
|
||||
auto max_input = max(GetSize(a), GetSize(b));
|
||||
log_assert(max_input >= 1);
|
||||
cached_of = alu_cell->module->Xor(NEW_ID, cached_of[max_input], cached_of[max_input-1]);
|
||||
} else {
|
||||
log_assert(GetSize(y) >= 1);
|
||||
cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(y)], cached_of[GetSize(y)-1]);
|
||||
}
|
||||
}
|
||||
return cached_of;
|
||||
}
|
||||
|
|
@ -120,7 +131,12 @@ struct AlumaccWorker
|
|||
RTLIL::SigSpec get_sf() {
|
||||
if (GetSize(cached_sf) == 0) {
|
||||
cached_sf = alu_cell->getPort(ID::Y);
|
||||
cached_sf = cached_sf[GetSize(cached_sf)-1];
|
||||
log_assert(GetSize(cached_sf) >= 1);
|
||||
if (oversized && !is_signed) {
|
||||
cached_sf = cached_sf[max(GetSize(a), GetSize(b))-1];
|
||||
} else {
|
||||
cached_sf = cached_sf[GetSize(y)-1];
|
||||
}
|
||||
}
|
||||
return cached_sf;
|
||||
}
|
||||
|
|
@ -357,13 +373,17 @@ struct AlumaccWorker
|
|||
alunode->cells.push_back(n->cell);
|
||||
alunode->is_signed = a_signed;
|
||||
alunode->invert_b = subtract_b;
|
||||
alunode->oversized = max(GetSize(A), GetSize(B)) < GetSize(n->y);
|
||||
|
||||
alunode->a = A;
|
||||
alunode->b = B;
|
||||
alunode->c = C;
|
||||
alunode->y = n->y;
|
||||
|
||||
sig_alu[RTLIL::SigSig(A, B)].insert(alunode);
|
||||
// only consider merging if the output is at least as wide as the inputs
|
||||
if (max(GetSize(A), GetSize(B)) <= GetSize(n->y)) {
|
||||
sig_alu[RTLIL::SigSig(A, B)].insert(alunode);
|
||||
}
|
||||
delete_nodes.insert(n);
|
||||
next_macc:;
|
||||
}
|
||||
|
|
@ -410,6 +430,20 @@ struct AlumaccWorker
|
|||
eq_cells.push_back(cell);
|
||||
}
|
||||
|
||||
auto cmp_mergeable = [](const alunode_t *node, const SigSpec cmp_A, const SigSpec cmp_B, bool is_signed) {
|
||||
if (!node->invert_b || node->c != State::S1) {
|
||||
// comparators need subtraction
|
||||
return false;
|
||||
}
|
||||
if (is_signed != node->is_signed) {
|
||||
if (GetSize(cmp_A) != GetSize(cmp_B)) {
|
||||
// mismatched input widths are problematic when mixing signedness
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
for (auto cell : lge_cells)
|
||||
{
|
||||
log(" creating $alu model for %s (%s):", cell, cell->type.unescape());
|
||||
|
|
@ -425,14 +459,14 @@ struct AlumaccWorker
|
|||
alunode_t *n = nullptr;
|
||||
|
||||
for (auto node : sig_alu[RTLIL::SigSig(A, B)])
|
||||
if (node->invert_b && node->c == State::S1) {
|
||||
if (cmp_mergeable(node, A, B, is_signed)) {
|
||||
n = node;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == nullptr) {
|
||||
for (auto node : sig_alu[RTLIL::SigSig(B, A)])
|
||||
if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) {
|
||||
if (cmp_mergeable(node, B, A, is_signed)) {
|
||||
n = node;
|
||||
cmp_less = !cmp_less;
|
||||
std::swap(A, B);
|
||||
|
|
@ -448,6 +482,7 @@ struct AlumaccWorker
|
|||
n->y = module->addWire(NEW_ID, max(GetSize(A), GetSize(B)));
|
||||
n->is_signed = is_signed;
|
||||
n->invert_b = true;
|
||||
n->oversized = false;
|
||||
sig_alu[RTLIL::SigSig(A, B)].insert(n);
|
||||
log(" new $alu\n");
|
||||
} else {
|
||||
|
|
@ -470,14 +505,14 @@ struct AlumaccWorker
|
|||
alunode_t *n = nullptr;
|
||||
|
||||
for (auto node : sig_alu[RTLIL::SigSig(A, B)])
|
||||
if (node->invert_b && node->c == State::S1) {
|
||||
if (cmp_mergeable(node, A, B, is_signed)) {
|
||||
n = node;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == nullptr) {
|
||||
for (auto node : sig_alu[RTLIL::SigSig(B, A)])
|
||||
if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) {
|
||||
if (cmp_mergeable(node, B, A, is_signed)) {
|
||||
n = node;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
uut_*.*
|
||||
|
|
@ -26,8 +26,18 @@ assign ne = ra != rb;
|
|||
endmodule
|
||||
EOT
|
||||
|
||||
proc
|
||||
|
||||
equiv_opt -assert alumacc
|
||||
alumacc
|
||||
design -load postopt
|
||||
select -assert-count 1 t:$alu
|
||||
|
||||
design -reset
|
||||
read_verilog << EOT
|
||||
module top(input signed a, b, output x, output [1:0] y);
|
||||
assign y = $unsigned(a) - $unsigned(b);
|
||||
assign x = a > b;
|
||||
endmodule
|
||||
EOT
|
||||
hierarchy
|
||||
wreduce
|
||||
equiv_opt -assert alumacc
|
||||
|
||||
|
|
@ -5,4 +5,99 @@ sys.path.append("..")
|
|||
|
||||
import gen_tests_makefile
|
||||
|
||||
import argparse
|
||||
import random
|
||||
from itertools import product
|
||||
|
||||
TEMPLATE=r"""read_rtlil << EOT
|
||||
module \top
|
||||
wire width {a_width} input 1 signed \a
|
||||
wire width {b_width} input 2 signed \b
|
||||
wire output 3 \x
|
||||
wire width {y_width} output 4 \y
|
||||
cell ${c1} \c1
|
||||
parameter \A_SIGNED {c1_signed}
|
||||
parameter \B_SIGNED {c1_signed}
|
||||
parameter \A_WIDTH {a_width}
|
||||
parameter \B_WIDTH {b_width}
|
||||
parameter \Y_WIDTH 1
|
||||
connect \A \a
|
||||
connect \B \b
|
||||
connect \Y \x
|
||||
end
|
||||
cell ${c2} \c2
|
||||
parameter \A_SIGNED {c2_signed}
|
||||
parameter \B_SIGNED {c2_signed}
|
||||
parameter \A_WIDTH {a_width}
|
||||
parameter \B_WIDTH {b_width}
|
||||
parameter \Y_WIDTH {y_width}
|
||||
connect \A \a
|
||||
connect \B \b
|
||||
connect \Y \y
|
||||
end
|
||||
end
|
||||
EOT
|
||||
equiv_opt -assert alumacc
|
||||
design -load postopt
|
||||
{postopt_assert}
|
||||
"""
|
||||
|
||||
EQ = ["eq", "eqx", "ne", "nex"]
|
||||
LGE = ["lt", "gt"]
|
||||
CMP = EQ + LGE
|
||||
ARITH = ["add", "sub"]
|
||||
SIGNED = [0, 1]
|
||||
WIDTH = list(range(1, 4))
|
||||
|
||||
parser = argparse.ArgumentParser(formatter_class = argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('-S', '--seed', type = int, help = 'seed for PRNG')
|
||||
args = parser.parse_args()
|
||||
|
||||
seed = args.seed
|
||||
if seed is None:
|
||||
seed = random.randrange(sys.maxsize)
|
||||
print("alumacc PRNG seed: %d" % seed)
|
||||
random.seed(seed)
|
||||
|
||||
count = 0
|
||||
for c1_signed, c2, c2_signed, a_width in product(
|
||||
SIGNED, [EQ, LGE, ARITH], SIGNED, WIDTH
|
||||
):
|
||||
c1 = random.choice(LGE)
|
||||
if isinstance(c2, list):
|
||||
c2 = random.choice(c2)
|
||||
|
||||
b_widths: list[int]
|
||||
if a_width == 2:
|
||||
b_widths = [1, 2, 3]
|
||||
else:
|
||||
b_widths = [a_width]
|
||||
y_widths: list[int]
|
||||
if c2 in CMP:
|
||||
y_widths = [1]
|
||||
else:
|
||||
y_widths = b_widths
|
||||
|
||||
for b_width, y_width in product(b_widths, y_widths):
|
||||
out_cells = "t:$alu"
|
||||
for c in c1, c2:
|
||||
if c in EQ:
|
||||
# LGE cells will always remap to $alu, but EQ cells only will if merged
|
||||
out_cells += f" t:${c}"
|
||||
|
||||
undersized = c2 in ARITH and y_width < max(a_width, b_width)
|
||||
mixed_sign = c1_signed != c2_signed and a_width != b_width
|
||||
if c2 != "add" and not undersized and not mixed_sign:
|
||||
# cells correctly merged
|
||||
postopt_assert = f"select -assert-count 1 {out_cells}"
|
||||
else:
|
||||
# currently these all produce 2, but assert-max allows for future improvement
|
||||
postopt_assert = f"select -assert-max 2 {out_cells}"
|
||||
|
||||
with open(f"uut_{'s' if c1_signed else 'u'}{c1}_{'s' if c2_signed else 'u'}{c2}_{a_width}_{b_width}_{y_width}.ys", "w") as f:
|
||||
print(str.format_map(TEMPLATE, locals()), file=f)
|
||||
count = count + 1
|
||||
|
||||
# print(count)
|
||||
|
||||
gen_tests_makefile.generate(["--yosys-scripts"])
|
||||
|
|
|
|||
Loading…
Reference in New Issue