aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/ast/genrtlil.cc
diff options
context:
space:
mode:
authorZachary Snow <zach@zachjs.com>2020-12-18 12:59:08 -0700
committerZachary Snow <zach@zachjs.com>2020-12-18 20:33:14 -0700
commit0d8e5d965f2585e6ed151a9e92d83ee63df6172a (patch)
treef2da85bd5aaf90406d3536b64749837d44003eab /frontends/ast/genrtlil.cc
parent40e35993af6ecb6207f15cc176455ff8d66bcc69 (diff)
downloadyosys-0d8e5d965f2585e6ed151a9e92d83ee63df6172a.tar.gz
yosys-0d8e5d965f2585e6ed151a9e92d83ee63df6172a.tar.bz2
yosys-0d8e5d965f2585e6ed151a9e92d83ee63df6172a.zip
Sign extend port connections where necessary
- Signed cell outputs are sign extended when bound to larger wires - Signed connections are sign extended when bound to larger cell inputs - Sign extension is performed in hierarchy and flatten phases - genrtlil indirects signed constants through signed wires - Other phases producing RTLIL may need to be updated to preserve signedness information - Resolves #1418 - Resolves #2265
Diffstat (limited to 'frontends/ast/genrtlil.cc')
-rw-r--r--frontends/ast/genrtlil.cc26
1 files changed, 24 insertions, 2 deletions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index e878d0dd2..500ccf8c0 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -106,6 +106,7 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width);
wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column);
+ wire->is_signed = that->is_signed;
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
@@ -1721,8 +1722,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
if (child->type == AST_ARGUMENT) {
RTLIL::SigSpec sig;
- if (child->children.size() > 0)
- sig = child->children[0]->genRTLIL();
+ if (child->children.size() > 0) {
+ AstNode *arg = child->children[0];
+ int local_width_hint = -1;
+ bool local_sign_hint = false;
+ // don't inadvertently attempt to detect the width of interfaces
+ if (arg->type != AST_IDENTIFIER || !arg->id2ast || arg->id2ast->type != AST_CELL)
+ arg->detectSignWidth(local_width_hint, local_sign_hint);
+ sig = arg->genRTLIL(local_width_hint, local_sign_hint);
+ log_assert(local_sign_hint == arg->is_signed);
+ if (sig.is_wire()) {
+ // if the resulting SigSpec is a wire, its
+ // signedness should match that of the AstNode
+ log_assert(arg->is_signed == sig.as_wire()->is_signed);
+ } else if (arg->is_signed) {
+ // non-trivial signed nodes are indirected through
+ // signed wires to enable sign extension
+ RTLIL::IdString wire_name = NEW_ID;
+ RTLIL::Wire *wire = current_module->addWire(wire_name, arg->bits.size());
+ wire->is_signed = true;
+ current_module->connect(wire, sig);
+ sig = wire;
+ }
+ }
if (child->str.size() == 0) {
char buf[100];
snprintf(buf, 100, "$%d", ++port_counter);