From 6c562c76bc36ea51af25c26abffe7f92ceae77bd Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Mon, 2 Oct 2023 18:32:53 +0200 Subject: [PATCH] fix handling right shifts --- kernel/celledges.cc | 61 +++++++++++++++++++++++++++++++++++++-------- passes/sat/eval.cc | 4 +-- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/kernel/celledges.cc b/kernel/celledges.cc index fc381f35cdd..1e5a68db3a8 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -174,26 +174,67 @@ void demux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) void shift_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { + bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); int a_width = GetSize(cell->getPort(ID::A)); int b_width = GetSize(cell->getPort(ID::B)); int y_width = GetSize(cell->getPort(ID::Y)); - for (int i = 0; i < y_width; i++){ - for (int k = 0; k < b_width; k++) - db->add_edge(cell, ID::B, k, ID::Y, i, -1); + // how far the maximum value of B is able to shift + int b_range = (1<type.in(ID($shl), ID($sshl))) { - for (int k = min(i, a_width); k >= 0; k--) - db->add_edge(cell, ID::A, k, ID::Y, i, -1); + // << and <<< + b_range_upper = a_width + b_range; + if (is_signed) b_range_upper -= 1; + a_range_lower = max(0, i - b_range); + a_range_upper = min(i+1, a_width); + } else if (cell->type.in(ID($shr), ID($sshr))){ + // >> and >>> + b_range_upper = a_width; + a_range_lower = min(i, a_width - 1); // technically the min is unneccessary as b_range_upper check already skips any i >= a_width, but let's leave the logic in since this is hard enough + a_range_upper = min(i+1 + b_range, a_width); + } else if (cell->type.in(ID($shift), ID($shiftx))) { + // can go both ways depending on sign of B + // 2's complement range is different depending on direction + int b_range_left = (1<<(b_width - 1)); + int b_range_right = (1<<(b_width - 1)) - 1; + b_range_upper = a_width + b_range_left; + a_range_lower = max(0, i - b_range_left); + a_range_upper = min(i+1 + b_range_right, a_width); } - if (cell->type.in(ID($shr), ID($sshr))) - for (int k = i; k < a_width; k++) + if (i < b_range_upper) { + for (int k = a_range_lower; k < a_range_upper; k++) db->add_edge(cell, ID::A, k, ID::Y, i, -1); + } else { + // the only possible influence value is sign extension + if (is_signed) + db->add_edge(cell, ID::A, a_width - 1, ID::Y, i, -1); + } + + for (int k = 0; k < b_width; k++) { + if (cell->type.in(ID($shl), ID($sshl)) && a_width == 1 && is_signed) { + int skip = (1<<(k+1)); + int base = skip -1; + if (i % skip != base) + db->add_edge(cell, ID::B, k, ID::Y, i, -1); + } else if (cell->type.in(ID($shr), ID($sshr)) && is_signed) { + int skip = (1<<(k+1)); + int base = 0; + if (i % skip != base || i < a_width - 1) + db->add_edge(cell, ID::B, k, ID::Y, i, -1); + } else { + db->add_edge(cell, ID::B, k, ID::Y, i, -1); + } + } - if (cell->type.in(ID($shift), ID($shiftx))) - for (int k = 0; k < a_width; k++) - db->add_edge(cell, ID::A, k, ID::Y, i, -1); } } diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc index 05879426e63..acebea6c568 100644 --- a/passes/sat/eval.cc +++ b/passes/sat/eval.cc @@ -543,13 +543,13 @@ struct EvalPass : public Pass { int pos = 0; for (auto &c : tabsigs.chunks()) { - tab_line.push_back(log_signal(RTLIL::SigSpec(tabvals).extract(pos, c.width))); + tab_line.push_back(log_signal(RTLIL::SigSpec(tabvals).extract(pos, c.width), false)); pos += c.width; } pos = 0; for (auto &c : signal.chunks()) { - tab_line.push_back(log_signal(value.extract(pos, c.width))); + tab_line.push_back(log_signal(value.extract(pos, c.width), false)); pos += c.width; }