mirror of
https://github.com/YosysHQ/yosys
synced 2025-05-09 16:55:49 +00:00
rtlil: enable single-bit vector wires
This commit is contained in:
parent
f60bbe64ac
commit
ab112b9b6b
12 changed files with 121 additions and 9 deletions
|
@ -178,8 +178,10 @@ struct JsonWriter
|
||||||
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
|
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
|
||||||
if (w->start_offset)
|
if (w->start_offset)
|
||||||
f << stringf(" \"offset\": %d,\n", w->start_offset);
|
f << stringf(" \"offset\": %d,\n", w->start_offset);
|
||||||
if (w->upto)
|
if (w->width != 1 && w->upto)
|
||||||
f << stringf(" \"upto\": 1,\n");
|
f << stringf(" \"upto\": 1,\n");
|
||||||
|
if (w->width == 1 && w->sbvector)
|
||||||
|
f << stringf(" \"sbvector\": 1,\n");
|
||||||
if (w->is_signed)
|
if (w->is_signed)
|
||||||
f << stringf(" \"signed\": %d,\n", w->is_signed);
|
f << stringf(" \"signed\": %d,\n", w->is_signed);
|
||||||
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
|
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
|
||||||
|
@ -270,8 +272,10 @@ struct JsonWriter
|
||||||
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
|
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
|
||||||
if (w->start_offset)
|
if (w->start_offset)
|
||||||
f << stringf(" \"offset\": %d,\n", w->start_offset);
|
f << stringf(" \"offset\": %d,\n", w->start_offset);
|
||||||
if (w->upto)
|
if (w->width != 1 && w->upto)
|
||||||
f << stringf(" \"upto\": 1,\n");
|
f << stringf(" \"upto\": 1,\n");
|
||||||
|
if (w->width == 1 && w->sbvector)
|
||||||
|
f << stringf(" \"sbvector\": 1,\n");
|
||||||
if (w->is_signed)
|
if (w->is_signed)
|
||||||
f << stringf(" \"signed\": %d,\n", w->is_signed);
|
f << stringf(" \"signed\": %d,\n", w->is_signed);
|
||||||
f << stringf(" \"attributes\": {");
|
f << stringf(" \"attributes\": {");
|
||||||
|
@ -403,10 +407,12 @@ struct JsonBackend : public Backend {
|
||||||
log(" \"bits\": <bit_vector>\n");
|
log(" \"bits\": <bit_vector>\n");
|
||||||
log(" \"offset\": <the lowest bit index in use, if non-0>\n");
|
log(" \"offset\": <the lowest bit index in use, if non-0>\n");
|
||||||
log(" \"upto\": <1 if the port bit indexing is MSB-first>\n");
|
log(" \"upto\": <1 if the port bit indexing is MSB-first>\n");
|
||||||
|
log(" \"sbvector\": <1 if a single-bit port is a vector, not a scalar>\n");
|
||||||
log(" \"signed\": <1 if the port is signed>\n");
|
log(" \"signed\": <1 if the port is signed>\n");
|
||||||
log(" }\n");
|
log(" }\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("The \"offset\" and \"upto\" fields are skipped if their value would be 0.\n");
|
log("The \"offset\", \"upto\", and \"sbvector\" fields are skipped\n");
|
||||||
|
log("if their value would be 0.\n");
|
||||||
log("They don't affect connection semantics, and are only used to preserve original\n");
|
log("They don't affect connection semantics, and are only used to preserve original\n");
|
||||||
log("HDL bit indexing.\n");
|
log("HDL bit indexing.\n");
|
||||||
log("And <cell_details> is:\n");
|
log("And <cell_details> is:\n");
|
||||||
|
@ -453,6 +459,7 @@ struct JsonBackend : public Backend {
|
||||||
log(" \"bits\": <bit_vector>\n");
|
log(" \"bits\": <bit_vector>\n");
|
||||||
log(" \"offset\": <the lowest bit index in use, if non-0>\n");
|
log(" \"offset\": <the lowest bit index in use, if non-0>\n");
|
||||||
log(" \"upto\": <1 if the port bit indexing is MSB-first>\n");
|
log(" \"upto\": <1 if the port bit indexing is MSB-first>\n");
|
||||||
|
log(" \"sbvector\": <1 if a single-bit port is a vector, not a scalar>\n");
|
||||||
log(" \"signed\": <1 if the port is signed>\n");
|
log(" \"signed\": <1 if the port is signed>\n");
|
||||||
log(" }\n");
|
log(" }\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
|
|
@ -130,10 +130,14 @@ void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
|
||||||
wire->driverCell()->name.c_str(), wire->driverPort().c_str());
|
wire->driverCell()->name.c_str(), wire->driverPort().c_str());
|
||||||
}
|
}
|
||||||
f << stringf("%s" "wire ", indent.c_str());
|
f << stringf("%s" "wire ", indent.c_str());
|
||||||
if (wire->width != 1)
|
if (wire->width == 1) {
|
||||||
|
if (wire->sbvector)
|
||||||
|
f << stringf("width %d ", wire->width);
|
||||||
|
} else {
|
||||||
f << stringf("width %d ", wire->width);
|
f << stringf("width %d ", wire->width);
|
||||||
if (wire->upto)
|
if (wire->upto)
|
||||||
f << stringf("upto ");
|
f << stringf("upto ");
|
||||||
|
}
|
||||||
if (wire->start_offset != 0)
|
if (wire->start_offset != 0)
|
||||||
f << stringf("offset %d ", wire->start_offset);
|
f << stringf("offset %d ", wire->start_offset);
|
||||||
if (wire->port_input && !wire->port_output)
|
if (wire->port_input && !wire->port_output)
|
||||||
|
|
|
@ -419,6 +419,9 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
|
||||||
range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
|
range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
|
||||||
else
|
else
|
||||||
range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
|
range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
|
||||||
|
} else {
|
||||||
|
if (wire->sbvector)
|
||||||
|
range = stringf(" [%d:%d]", wire->start_offset, wire->start_offset);
|
||||||
}
|
}
|
||||||
if (wire->port_input && !wire->port_output)
|
if (wire->port_input && !wire->port_output)
|
||||||
f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
|
||||||
|
|
|
@ -350,6 +350,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
|
||||||
fprintf(f, " port=%d", port_id);
|
fprintf(f, " port=%d", port_id);
|
||||||
if (range_valid || range_left != -1 || range_right != 0)
|
if (range_valid || range_left != -1 || range_right != 0)
|
||||||
fprintf(f, " %srange=[%d:%d]%s", range_swapped ? "swapped_" : "", range_left, range_right, range_valid ? "" : "!");
|
fprintf(f, " %srange=[%d:%d]%s", range_swapped ? "swapped_" : "", range_left, range_right, range_valid ? "" : "!");
|
||||||
|
if (is_sbvector)
|
||||||
|
fprintf(f, " vector");
|
||||||
if (integer != 0)
|
if (integer != 0)
|
||||||
fprintf(f, " int=%u", (int)integer);
|
fprintf(f, " int=%u", (int)integer);
|
||||||
if (realvalue != 0)
|
if (realvalue != 0)
|
||||||
|
|
|
@ -192,7 +192,7 @@ namespace AST
|
||||||
// node content - most of it is unused in most node types
|
// node content - most of it is unused in most node types
|
||||||
std::string str;
|
std::string str;
|
||||||
std::vector<RTLIL::State> bits;
|
std::vector<RTLIL::State> bits;
|
||||||
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized, is_custom_type;
|
bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, is_sbvector, was_checked, is_unsized, is_custom_type;
|
||||||
int port_id, range_left, range_right;
|
int port_id, range_left, range_right;
|
||||||
uint32_t integer;
|
uint32_t integer;
|
||||||
double realvalue;
|
double realvalue;
|
||||||
|
|
|
@ -1445,7 +1445,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
wire->port_id = port_id;
|
wire->port_id = port_id;
|
||||||
wire->port_input = is_input;
|
wire->port_input = is_input;
|
||||||
wire->port_output = is_output;
|
wire->port_output = is_output;
|
||||||
wire->upto = range_swapped;
|
if (wire->width != 1)
|
||||||
|
wire->upto = range_swapped;
|
||||||
|
else
|
||||||
|
wire->sbvector = is_sbvector;
|
||||||
|
|
||||||
wire->is_signed = is_signed;
|
wire->is_signed = is_signed;
|
||||||
|
|
||||||
for (auto &attr : attributes) {
|
for (auto &attr : attributes) {
|
||||||
|
|
|
@ -2084,6 +2084,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
std::swap(range_left, range_right);
|
std::swap(range_left, range_right);
|
||||||
range_swapped = force_upto;
|
range_swapped = force_upto;
|
||||||
}
|
}
|
||||||
|
if (range_left == range_right)
|
||||||
|
is_sbvector = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!range_valid)
|
if (!range_valid)
|
||||||
|
@ -2092,6 +2094,7 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
range_swapped = false;
|
range_swapped = false;
|
||||||
range_left = 0;
|
range_left = 0;
|
||||||
range_right = 0;
|
range_right = 0;
|
||||||
|
is_sbvector = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -345,6 +345,12 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
||||||
port_wire->upto = val->data_number != 0;
|
port_wire->upto = val->data_number != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (port_node->data_dict.count("sbvector") != 0) {
|
||||||
|
JsonNode *val = port_node->data_dict.at("sbvector");
|
||||||
|
if (val->type == 'N')
|
||||||
|
port_wire->sbvector = val->data_number != 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (port_node->data_dict.count("signed") != 0) {
|
if (port_node->data_dict.count("signed") != 0) {
|
||||||
JsonNode *val = port_node->data_dict.at("signed");
|
JsonNode *val = port_node->data_dict.at("signed");
|
||||||
if (val->type == 'N')
|
if (val->type == 'N')
|
||||||
|
@ -442,6 +448,11 @@ void json_import(Design *design, string &modname, JsonNode *node)
|
||||||
if (val->type == 'N')
|
if (val->type == 'N')
|
||||||
wire->upto = val->data_number != 0;
|
wire->upto = val->data_number != 0;
|
||||||
}
|
}
|
||||||
|
if (net_node->data_dict.count("sbvector") != 0) {
|
||||||
|
JsonNode *val = net_node->data_dict.at("sbvector");
|
||||||
|
if (val->type == 'N')
|
||||||
|
wire->sbvector = val->data_number != 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (net_node->data_dict.count("offset") != 0) {
|
if (net_node->data_dict.count("offset") != 0) {
|
||||||
JsonNode *val = net_node->data_dict.at("offset");
|
JsonNode *val = net_node->data_dict.at("offset");
|
||||||
|
|
|
@ -188,6 +188,9 @@ wire_stmt:
|
||||||
wire_options:
|
wire_options:
|
||||||
wire_options TOK_WIDTH TOK_INT {
|
wire_options TOK_WIDTH TOK_INT {
|
||||||
current_wire->width = $3;
|
current_wire->width = $3;
|
||||||
|
// Width 1 specified -> single-bit vector rather than scalar
|
||||||
|
if (current_wire->width == 1)
|
||||||
|
current_wire->sbvector = true;
|
||||||
} |
|
} |
|
||||||
wire_options TOK_WIDTH TOK_INVALID {
|
wire_options TOK_WIDTH TOK_INVALID {
|
||||||
rtlil_frontend_yyerror("RTLIL error: invalid wire width");
|
rtlil_frontend_yyerror("RTLIL error: invalid wire width");
|
||||||
|
|
|
@ -1803,6 +1803,16 @@ namespace RTLIL_BACKEND {
|
||||||
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
|
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BoolStruct {
|
||||||
|
private:
|
||||||
|
bool val;
|
||||||
|
public:
|
||||||
|
BoolStruct(bool v) : val(v) {}
|
||||||
|
operator bool() const {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct RTLIL::Wire : public RTLIL::NamedObject
|
struct RTLIL::Wire : public RTLIL::NamedObject
|
||||||
{
|
{
|
||||||
Hasher::hash_t hashidx_;
|
Hasher::hash_t hashidx_;
|
||||||
|
@ -1827,7 +1837,16 @@ public:
|
||||||
|
|
||||||
RTLIL::Module *module;
|
RTLIL::Module *module;
|
||||||
int width, start_offset, port_id;
|
int width, start_offset, port_id;
|
||||||
bool port_input, port_output, upto, is_signed;
|
bool port_input, port_output, is_signed;
|
||||||
|
// These are actually just total aliases, relying on
|
||||||
|
// common initial sequences of records to avoid UB.
|
||||||
|
// This is a retrofit and we don't know if we ensure
|
||||||
|
// only the active member is accessed
|
||||||
|
union {
|
||||||
|
BoolStruct upto; // if width >= 1
|
||||||
|
// "single bit vector" vs scalar
|
||||||
|
BoolStruct sbvector; // if width == 1
|
||||||
|
};
|
||||||
|
|
||||||
RTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; };
|
RTLIL::Cell *driverCell() const { log_assert(driverCell_); return driverCell_; };
|
||||||
RTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; };
|
RTLIL::IdString driverPort() const { log_assert(driverCell_); return driverPort_; };
|
||||||
|
|
36
tests/various/json_sbvector.ys
Normal file
36
tests/various/json_sbvector.ys
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module buffer(
|
||||||
|
output o,
|
||||||
|
input i
|
||||||
|
);
|
||||||
|
assign o = i;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
write_json json_sbvector_no.out
|
||||||
|
! ! grep -qF 'sbvector' json_sbvector_no.out
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_verilog <<EOT
|
||||||
|
module buffer(
|
||||||
|
output o,
|
||||||
|
input [0:0] i
|
||||||
|
);
|
||||||
|
assign o = i;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
write_json json_sbvector_yes.out
|
||||||
|
! grep -qF 'sbvector' json_sbvector_yes.out
|
||||||
|
|
||||||
|
design -reset
|
||||||
|
read_json json_sbvector_yes.out
|
||||||
|
logger -expect log "wire width 1 input 2 \\i" 1
|
||||||
|
dump
|
||||||
|
logger -check-expected
|
||||||
|
design -reset
|
||||||
|
|
||||||
|
read_json json_sbvector_no.out
|
||||||
|
logger -expect log "wire input 2 \\i" 1
|
||||||
|
dump
|
||||||
|
logger -check-expected
|
20
tests/verilog/sbvector.ys
Normal file
20
tests/verilog/sbvector.ys
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
module foo(
|
||||||
|
output o,
|
||||||
|
input [0:0] i1,
|
||||||
|
input i2
|
||||||
|
);
|
||||||
|
assign o = i1 ^ i2;
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
logger -expect log "wire width 1 input 2 \\i1" 1
|
||||||
|
logger -expect log "wire input 3 \\i2" 1
|
||||||
|
dump
|
||||||
|
logger -check-expected
|
||||||
|
|
||||||
|
write_verilog verilog_sbvector.out
|
||||||
|
!grep -qF 'wire [0:0] i1;' verilog_sbvector.out
|
||||||
|
!grep -qF 'input [0:0] i1;' verilog_sbvector.out
|
||||||
|
!grep -qF 'wire i2;' verilog_sbvector.out
|
||||||
|
!grep -qF 'input i2;' verilog_sbvector.out
|
Loading…
Add table
Add a link
Reference in a new issue