From 27a872d1e7041be4894bc643a420587ff5894125 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 28 Jul 2014 14:25:03 +0200 Subject: [PATCH] Added support for "upto" wires to Verilog front- and back-end --- backends/verilog/verilog_backend.cc | 31 +++++++++++----- frontends/ast/ast.cc | 5 ++- frontends/ast/ast.h | 2 +- frontends/ast/genrtlil.cc | 19 ++++------ frontends/ast/simplify.cc | 4 ++ tests/simple/partsel.v | 57 +++++++++++++++++++++++++++++ 6 files changed, 96 insertions(+), 22 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index fe2c2b247..5826aea87 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -211,14 +211,23 @@ void dump_sigchunk(FILE *f, const RTLIL::SigChunk &chunk, bool no_decimal = fals if (chunk.wire == NULL) { dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal); } else { - if (chunk.width == chunk.wire->width && chunk.offset == 0) + if (chunk.width == chunk.wire->width && chunk.offset == 0) { fprintf(f, "%s", id(chunk.wire->name).c_str()); - else if (chunk.width == 1) - fprintf(f, "%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset); - else - fprintf(f, "%s[%d:%d]", id(chunk.wire->name).c_str(), - chunk.offset + chunk.wire->start_offset + chunk.width - 1, - chunk.offset + chunk.wire->start_offset); + } else if (chunk.width == 1) { + if (chunk.wire->upto) + fprintf(f, "%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); + else + fprintf(f, "%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset); + } else { + if (chunk.wire->upto) + fprintf(f, "%s[%d:%d]", id(chunk.wire->name).c_str(), + (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset, + (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset); + else + fprintf(f, "%s[%d:%d]", id(chunk.wire->name).c_str(), + (chunk.offset + chunk.width - 1) + chunk.wire->start_offset, + chunk.offset + chunk.wire->start_offset); + } } } @@ -267,8 +276,12 @@ void dump_wire(FILE *f, std::string indent, RTLIL::Wire *wire) #else // do not use Verilog-2k "outut reg" syntax in verilog export std::string range = ""; - if (wire->width != 1) - range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset); + if (wire->width != 1) { + if (wire->upto) + range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset); + else + range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset); + } if (wire->port_input && !wire->port_output) fprintf(f, "%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str()); if (!wire->port_input && wire->port_output) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index cec199b63..5b3214f5c 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -181,6 +181,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2) is_signed = false; is_string = false; range_valid = false; + range_swapped = false; port_id = 0; range_left = -1; range_right = 0; @@ -276,7 +277,7 @@ void AstNode::dumpAst(FILE *f, std::string indent) if (port_id > 0) fprintf(f, " port=%d", port_id); if (range_valid || range_left != -1 || range_right != 0) - fprintf(f, " range=[%d:%d]%s", range_left, range_right, range_valid ? "" : "!"); + fprintf(f, " %srange=[%d:%d]%s", range_swapped ? "swapped_" : "", range_left, range_right, range_valid ? "" : "!"); if (integer != 0) fprintf(f, " int=%u", (int)integer); if (realvalue != 0) @@ -620,6 +621,8 @@ bool AstNode::operator==(const AstNode &other) const return false; if (range_valid != other.range_valid) return false; + if (range_swapped != other.range_swapped) + return false; if (port_id != other.port_id) return false; if (range_left != other.range_left) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 8253a2052..6c15c03ab 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -151,7 +151,7 @@ namespace AST // node content - most of it is unused in most node types std::string str; std::vector bits; - bool is_input, is_output, is_reg, is_signed, is_string, range_valid; + bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped; int port_id, range_left, range_right; uint32_t integer; double realvalue; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 8ee46eb85..5545fc169 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -786,13 +786,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) log_error("Signal `%s' with non-constant width at %s:%d!\n", str.c_str(), filename.c_str(), linenum); - bool wire_upto = false; - if (range_left < range_right && (range_left != -1 || range_right != 0)) { - int tmp = range_left; - range_left = range_right; - range_right = tmp; - wire_upto = true; - } + log_assert(range_left >= range_right || (range_left == -1 && range_right == 0)); RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -800,7 +794,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) wire->port_id = port_id; wire->port_input = is_input; wire->port_output = is_output; - wire->upto = wire_upto; + wire->upto = range_swapped; for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) @@ -918,17 +912,20 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shr", width, - fake_ast->children[0]->genRTLIL(), fake_ast->children[1]->genRTLIL()); + fake_ast->children[0]->genRTLIL(), !wire->upto ? fake_ast->children[1]->genRTLIL() : + current_module->Sub(NEW_ID, RTLIL::SigSpec(wire->width - width), fake_ast->children[1]->genRTLIL())); delete left_at_zero_ast; delete right_at_zero_ast; delete fake_ast; return sig; } else { - chunk.offset = children[0]->range_right - id2ast->range_right; - chunk.width = children[0]->range_left - children[0]->range_right + 1; if (children[0]->range_left > id2ast->range_left || id2ast->range_right > children[0]->range_right) log_error("Range select out of bounds on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + chunk.width = children[0]->range_left - children[0]->range_right + 1; + chunk.offset = children[0]->range_right - id2ast->range_right; + if (wire->upto) + chunk.offset = wire->width - (chunk.offset + chunk.width); } } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2a55adeff..7aa6d24c3 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -504,6 +504,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_RANGE) { bool old_range_valid = range_valid; range_valid = false; + range_swapped = false; range_left = -1; range_right = 0; log_assert(children.size() >= 1); @@ -525,6 +526,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int tmp = range_right; range_right = range_left; range_left = tmp; + range_swapped = true; } } @@ -535,6 +537,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (!range_valid) did_something = true; range_valid = true; + range_swapped = children[0]->range_swapped; range_left = children[0]->range_left; range_right = children[0]->range_right; } @@ -542,6 +545,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (!range_valid) did_something = true; range_valid = true; + range_swapped = false; range_left = 0; range_right = 0; } diff --git a/tests/simple/partsel.v b/tests/simple/partsel.v index 9b1a99859..7461358ad 100644 --- a/tests/simple/partsel.v +++ b/tests/simple/partsel.v @@ -3,3 +3,60 @@ wire [5:0] offset = idx << 2; assign slice_up = data[offset +: 4]; assign slice_down = data[offset + 3 -: 4]; endmodule + +module partsel_test002 ( + input clk, rst, + input [7:0] a, + input [0:7] b, + input [1:0] s, + output [7:0] x1, x2, x3, + output [0:7] x4, x5, x6, + output [7:0] y1, y2, y3, + output [0:7] y4, y5, y6, + output [7:0] z1, z2, z3, + output [0:7] z4, z5, z6, + output [7:0] w1, w2, w3, + output [0:7] w4, w5, w6, + output [7:0] p1, p2, p3, p4, p5, p6, + output [0:7] q1, q2, q3, q4, q5, q6, + output reg [7:0] r1, + output reg [0:7] r2 +); + +assign x1 = a, x2 = a + b, x3 = b; +assign x4 = a, x5 = a + b, x6 = b; +assign y1 = a[4 +: 3], y2 = a[4 +: 3] + b[4 +: 3], y3 = b[4 +: 3]; +assign y4 = a[4 +: 3], y5 = a[4 +: 3] + b[4 +: 3], y6 = b[4 +: 3]; +assign z1 = a[4 -: 3], z2 = a[4 -: 3] + b[4 -: 3], z3 = b[4 -: 3]; +assign z4 = a[4 -: 3], z5 = a[4 -: 3] + b[4 -: 3], z6 = b[4 -: 3]; +assign w1 = a[6:3], w2 = a[6:3] + b[3:6], w3 = b[3:6]; +assign w4 = a[6:3], w5 = a[6:3] + b[3:6], w6 = b[3:6]; +assign p1 = a[s], p2 = b[s], p3 = a[s+2 +: 2], p4 = b[s+2 +: 2], p5 = a[s+2 -: 2], p6 = b[s+2 -: 2]; +assign q1 = a[s], q2 = b[s], q3 = a[s+2 +: 2], q4 = b[s+2 +: 2], q5 = a[s+2 -: 2], q6 = b[s+2 -: 2]; + +always @(posedge clk) begin + if (rst) begin + { r1, r2 } = 16'h1337 ^ {a, b}; + end else begin + case (s) + 0: begin + r1[3:0] <= r2[0:3] ^ x1; + r2[4:7] <= r1[7:4] ^ x4; + end + 1: begin + r1[2 +: 3] <= r2[5 -: 3] + x1; + r2[3 +: 3] <= r1[6 -: 3] + x4; + end + 2: begin + r1[6 -: 3] <= r2[3 +: 3] - x1; + r2[7 -: 3] <= r1[4 +: 3] - x4; + end + 3: begin + r1 <= r2; + r2 <= r1; + end + endcase + end +end + +endmodule -- 2.30.2