mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-02 21:46:07 +00:00
verilog backend: preserve signed on wire and port declarations
`dump_wire` had no code path that emits the `signed` keyword for
wires/ports whose RTLIL `is_signed` flag is set. Reading
module top(input signed [9:0] in, output signed [31:0] o);
assign o = in;
endmodule
and writing it back via `write_verilog` produced
input [9:0] in;
output [31:0] o;
losing the declared signedness even though `wire->is_signed` was
tracked correctly in RTLIL throughout the round trip. The IEEE
1364-2001 grammar (Annex A.2.1.2 / A.2.1.3) allows `signed` after the
direction / net-type keyword, which is the dialect `write_verilog`
targets by default — so the fix is to emit ` signed` between the
direction/net-type and the range when `wire->is_signed`.
Closes the half of chipsalliance/synlig#2425 that lives in Yosys: the
SystemVerilog frontend correctly produces a signed wire for `output int`,
but the Verilog backend dropped it on write.
Adds `tests/various/write_verilog_signed_port.ys`, which round-trips a
module with `signed` inputs, outputs, and an internal wire and greps
for the keyword on each declaration — fails without the fix, passes
with it.
This commit is contained in:
parent
2046a23a2f
commit
13ab5d4a67
2 changed files with 43 additions and 5 deletions
|
|
@ -456,21 +456,26 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
|
|||
if (wire->attributes.count(ID::single_bit_vector))
|
||||
range = stringf(" [%d:%d]", wire->start_offset, wire->start_offset);
|
||||
}
|
||||
// Emit `signed` for wires/ports whose RTLIL is_signed flag is set.
|
||||
// Without this, an `output signed [N:0] o` was silently demoted to plain
|
||||
// `output [N:0] o` on write, losing the declared signedness in a
|
||||
// read_verilog -> write_verilog round-trip.
|
||||
const char *signed_kw = wire->is_signed ? " signed" : "";
|
||||
if (wire->port_input && !wire->port_output)
|
||||
f << stringf("%s" "input%s %s;\n", indent, range, id(wire->name));
|
||||
f << stringf("%s" "input%s%s %s;\n", indent, signed_kw, range, id(wire->name));
|
||||
if (!wire->port_input && wire->port_output)
|
||||
f << stringf("%s" "output%s %s;\n", indent, range, id(wire->name));
|
||||
f << stringf("%s" "output%s%s %s;\n", indent, signed_kw, range, id(wire->name));
|
||||
if (wire->port_input && wire->port_output)
|
||||
f << stringf("%s" "inout%s %s;\n", indent, range, id(wire->name));
|
||||
f << stringf("%s" "inout%s%s %s;\n", indent, signed_kw, range, id(wire->name));
|
||||
if (reg_wires.count(wire->name)) {
|
||||
f << stringf("%s" "reg%s %s", indent, range, id(wire->name));
|
||||
f << stringf("%s" "reg%s%s %s", indent, signed_kw, range, id(wire->name));
|
||||
if (wire->attributes.count(ID::init)) {
|
||||
f << stringf(" = ");
|
||||
dump_const(f, wire->attributes.at(ID::init));
|
||||
}
|
||||
f << stringf(";\n");
|
||||
} else
|
||||
f << stringf("%s" "wire%s %s;\n", indent, range, id(wire->name));
|
||||
f << stringf("%s" "wire%s%s %s;\n", indent, signed_kw, range, id(wire->name));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue