diff options
author | Zachary Snow <zach@zachjs.com> | 2020-12-18 12:59:08 -0700 |
---|---|---|
committer | Zachary Snow <zach@zachjs.com> | 2020-12-18 20:33:14 -0700 |
commit | 0d8e5d965f2585e6ed151a9e92d83ee63df6172a (patch) | |
tree | f2da85bd5aaf90406d3536b64749837d44003eab /frontends | |
parent | 40e35993af6ecb6207f15cc176455ff8d66bcc69 (diff) | |
download | yosys-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')
-rw-r--r-- | frontends/ast/genrtlil.cc | 26 |
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); |