diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc index bd8b9ceac..388f125d8 100644 --- a/passes/cmds/splitnets.cc +++ b/passes/cmds/splitnets.cc @@ -112,6 +112,12 @@ struct SplitnetsPass : public Pass { log(" -ports\n"); log(" also split module ports. per default only internal signals are split.\n"); log("\n"); + log(" -ports_only\n"); + log(" split module ports, but not the internal signals.\n"); + log("\n"); + log(" -top_only\n"); + log(" split module ports/nets, only at the top level of hierarchy.\n"); + log("\n"); log(" -driver\n"); log(" don't blindly split nets in individual bits. instead look at the driver\n"); log(" and split nets so that no driver drives only part of a net.\n"); @@ -121,6 +127,8 @@ struct SplitnetsPass : public Pass { { bool flag_ports = false; bool flag_driver = false; + bool flag_ports_only = false; + bool flag_top_only = false; std::string format = "[]:"; log_header(design, "Executing SPLITNETS pass (splitting up multi-bit signals).\n"); @@ -136,6 +144,14 @@ struct SplitnetsPass : public Pass { flag_ports = true; continue; } + if (args[argidx] == "-ports_only") { + flag_ports_only = true; + continue; + } + if (args[argidx] == "-top_only") { + flag_top_only = true; + continue; + } if (args[argidx] == "-driver") { flag_driver = true; continue; @@ -151,10 +167,12 @@ struct SplitnetsPass : public Pass { { if (module->has_processes_warn()) continue; + if (flag_top_only && (design->top_module() != module)) + continue; SplitnetsWorker worker; - if (flag_ports) + if (flag_ports || flag_ports_only) { int normalized_port_factor = 0; @@ -186,7 +204,8 @@ struct SplitnetsPass : public Pass { for (auto &chunk : sig.chunks()) { if (chunk.wire == NULL) continue; - if (chunk.wire->port_id == 0 || flag_ports) { + if ((flag_ports_only && (chunk.wire->port_id != 0) || + (!flag_ports_only && (chunk.wire->port_id == 0 || flag_ports))) { if (chunk.offset != 0) split_wires_at[chunk.wire].insert(chunk.offset); if (chunk.offset + chunk.width < chunk.wire->width) @@ -207,7 +226,10 @@ struct SplitnetsPass : public Pass { else { for (auto wire : module->wires()) { - if (wire->width > 1 && (wire->port_id == 0 || flag_ports) && design->selected(module, wire)) + if (flag_ports_only) + if (wire->width > 1 && (wire->port_id != 0) && design->selected(module, wire)) + worker.splitmap[wire] = std::vector(); + else if (wire->width > 1 && (wire->port_id == 0 || flag_ports) && design->selected(module, wire)) worker.splitmap[wire] = std::vector(); } @@ -218,7 +240,7 @@ struct SplitnetsPass : public Pass { module->rewrite_sigspecs(worker); - if (flag_ports) + if (flag_ports || flag_ports_only) { for (auto wire : module->wires()) { @@ -243,7 +265,7 @@ struct SplitnetsPass : public Pass { delete_wires.insert(it.first); module->remove(delete_wires); - if (flag_ports) + if (flag_ports || flag_ports_only) module->fixup_ports(); } diff --git a/tests/various/test_splitnets.tcl b/tests/various/test_splitnets.tcl new file mode 100644 index 000000000..9cb2b4305 --- /dev/null +++ b/tests/various/test_splitnets.tcl @@ -0,0 +1,63 @@ +yosys -import + +proc read_stats { file } { + set fid [open $file] + set result [read $fid] + close $fid + set ports 0 + set nets 0 + foreach line [split $result "\n"] { + if [regexp {Number of wires:[ \t]+([0-9]+)} $line tmp n] { + set nets [expr $nets + $n] + } + if [regexp {Number of ports:[ \t]+([0-9]+)} $line tmp n] { + set ports [expr $ports + $n] + } + } + return [list $nets $ports] +} + +proc assert_count { type actual expected } { + if {$actual != $expected} { + puts "Error, $type count: $actual vs $expected expected" + exit 1 + } +} + +read_verilog test_splitnets.v +hierarchy -auto-top +procs +design -save "pre" + +splitnets -ports_only -top_only +write_verilog -noexpr "ports_only_in_top.v" +tee -o "ports_only_in_top.txt" stat +foreach {nets ports} [read_stats "ports_only_in_top.txt"] {} +assert_count "nets" $nets 26 +assert_count "ports" $ports 16 + +design -load "pre" +splitnets -ports_only +write_verilog -noexpr "ports_only_in_all.v" +tee -o "ports_only_in_all.txt" stat +foreach {nets ports} [read_stats "ports_only_in_all.txt"] {} +assert_count "nets" $nets 30 +assert_count "ports" $ports 20 + +design -load "pre" +splitnets -ports -top_only +write_verilog -noexpr "ports_nets_in_top.v" +tee -o "ports_nets_in_top.txt" stat +foreach {nets ports} [read_stats "ports_nets_in_top.txt"] {} +assert_count "nets" $nets 30 +assert_count "ports" $ports 16 + +design -load "pre" +splitnets -ports +write_verilog -noexpr "ports_nets_in_all.v" +tee -o "ports_nets_in_all.txt" stat +foreach {nets ports} [read_stats "ports_nets_in_all.txt"] {} +assert_count "nets" $nets 40 +assert_count "ports" $ports 20 + +exit 0 diff --git a/tests/various/test_splitnets.v b/tests/various/test_splitnets.v new file mode 100644 index 000000000..2833ce147 --- /dev/null +++ b/tests/various/test_splitnets.v @@ -0,0 +1,13 @@ +module bottom(input clk, input wire [1:0] i, output reg [1:0] q); + reg [1:0] q1; + always @(posedge clk) begin + q1 <= i; + q <= q1; + end +endmodule + +module top(input clk, input wire [1:0] i, output reg [1:0] q); + reg [1:0] q1; + bottom u1 (.clk(clk), .i(i), .q(q1)); + not u2 (q, q1); +endmodule diff --git a/tests/various/test_splitnets.ys b/tests/various/test_splitnets.ys new file mode 100644 index 000000000..2af787d4f --- /dev/null +++ b/tests/various/test_splitnets.ys @@ -0,0 +1 @@ +tcl test_splitnets.tcl