From a6cadf6318f4eff6197d6c6f0e052c2417689f38 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Fri, 31 May 2019 12:24:12 +0200 Subject: [PATCH 01/22] Added support for parsing attributes on port connections. Signed-off-by: Maciej Kurc --- frontends/verilog/verilog_parser.y | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 8244a8f44..82a1d9d39 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1532,27 +1532,27 @@ cell_port_list_rules: cell_port | cell_port_list_rules ',' cell_port; cell_port: - /* empty */ { + attr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); } | - expr { + attr expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); - node->children.push_back($1); + node->children.push_back($2); } | - '.' TOK_ID '(' expr ')' { + attr '.' TOK_ID '(' expr ')' { AstNode *node = new AstNode(AST_ARGUMENT); - node->str = *$2; + node->str = *$3; astbuf2->children.push_back(node); - node->children.push_back($4); - delete $2; + node->children.push_back($5); + delete $3; } | - '.' TOK_ID '(' ')' { + attr '.' TOK_ID '(' ')' { AstNode *node = new AstNode(AST_ARGUMENT); - node->str = *$2; + node->str = *$3; astbuf2->children.push_back(node); - delete $2; + delete $3; }; always_stmt: From 5739cf52650ccb3627868d9c9d7e02888efad12b Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Mon, 3 Jun 2019 09:12:51 +0200 Subject: [PATCH 02/22] Added tests for attributes Signed-off-by: Maciej Kurc --- tests/simple/attrib01_module.v | 21 ++++++++++++++ tests/simple/attrib02_port_decl.v | 25 +++++++++++++++++ tests/simple/attrib03_parameter.v | 28 +++++++++++++++++++ tests/simple/attrib04_net_var.v | 32 ++++++++++++++++++++++ tests/simple/attrib05_port_conn.v.DISABLED | 21 ++++++++++++++ tests/simple/attrib06_operator_suffix.v | 23 ++++++++++++++++ tests/simple/attrib07_func_call.v.DISABLED | 21 ++++++++++++++ tests/simple/attrib08_mod_inst.v | 22 +++++++++++++++ tests/simple/attrib09_case.v | 26 ++++++++++++++++++ 9 files changed, 219 insertions(+) create mode 100644 tests/simple/attrib01_module.v create mode 100644 tests/simple/attrib02_port_decl.v create mode 100644 tests/simple/attrib03_parameter.v create mode 100644 tests/simple/attrib04_net_var.v create mode 100644 tests/simple/attrib05_port_conn.v.DISABLED create mode 100644 tests/simple/attrib06_operator_suffix.v create mode 100644 tests/simple/attrib07_func_call.v.DISABLED create mode 100644 tests/simple/attrib08_mod_inst.v create mode 100644 tests/simple/attrib09_case.v diff --git a/tests/simple/attrib01_module.v b/tests/simple/attrib01_module.v new file mode 100644 index 000000000..adef34f5b --- /dev/null +++ b/tests/simple/attrib01_module.v @@ -0,0 +1,21 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output reg out; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= ~inp; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib02_port_decl.v b/tests/simple/attrib02_port_decl.v new file mode 100644 index 000000000..3505e7265 --- /dev/null +++ b/tests/simple/attrib02_port_decl.v @@ -0,0 +1,25 @@ +module bar(clk, rst, inp, out); + (* this_is_clock = 1 *) + input wire clk; + (* this_is_reset = 1 *) + input wire rst; + input wire inp; + (* an_output_register = 1*) + output reg out; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= ~inp; + +endmodule + +module foo(clk, rst, inp, out); + (* this_is_the_master_clock *) + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib03_parameter.v b/tests/simple/attrib03_parameter.v new file mode 100644 index 000000000..562d225cd --- /dev/null +++ b/tests/simple/attrib03_parameter.v @@ -0,0 +1,28 @@ +module bar(clk, rst, inp, out); + + (* bus_width *) + parameter WIDTH = 2; + + (* an_attribute_on_localparam = 55 *) + localparam INCREMENT = 5; + + input wire clk; + input wire rst; + input wire [WIDTH-1:0] inp; + output reg [WIDTH-1:0] out; + + always @(posedge clk) + if (rst) out <= 0; + else out <= inp + INCREMENT; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire [7:0] inp; + output wire [7:0] out; + + bar # (.WIDTH(8)) bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib04_net_var.v b/tests/simple/attrib04_net_var.v new file mode 100644 index 000000000..8b5523406 --- /dev/null +++ b/tests/simple/attrib04_net_var.v @@ -0,0 +1,32 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output reg out; + + (* this_is_a_prescaler *) + reg [7:0] counter; + + (* temp_wire *) + wire out_val; + + always @(posedge clk) + counter <= counter + 1; + + assign out_val = inp ^ counter[4]; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= out_val; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib05_port_conn.v.DISABLED b/tests/simple/attrib05_port_conn.v.DISABLED new file mode 100644 index 000000000..e20e66319 --- /dev/null +++ b/tests/simple/attrib05_port_conn.v.DISABLED @@ -0,0 +1,21 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output reg out; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= ~inp; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance ( (* clock_connected *) clk, rst, (* this_is_the_input *) inp, out); +endmodule + diff --git a/tests/simple/attrib06_operator_suffix.v b/tests/simple/attrib06_operator_suffix.v new file mode 100644 index 000000000..e21173c58 --- /dev/null +++ b/tests/simple/attrib06_operator_suffix.v @@ -0,0 +1,23 @@ +module bar(clk, rst, inp_a, inp_b, out); + input wire clk; + input wire rst; + input wire [7:0] inp_a; + input wire [7:0] inp_b; + output reg [7:0] out; + + always @(posedge clk) + if (rst) out <= 0; + else out <= inp_a + (* ripple_adder *) inp_b; + +endmodule + +module foo(clk, rst, inp_a, inp_b, out); + input wire clk; + input wire rst; + input wire [7:0] inp_a; + input wire [7:0] inp_b; + output wire [7:0] out; + + bar bar_instance (clk, rst, inp_a, inp_b, out); +endmodule + diff --git a/tests/simple/attrib07_func_call.v.DISABLED b/tests/simple/attrib07_func_call.v.DISABLED new file mode 100644 index 000000000..f55ef2316 --- /dev/null +++ b/tests/simple/attrib07_func_call.v.DISABLED @@ -0,0 +1,21 @@ +function [7:0] do_add; + input [7:0] inp_a; + input [7:0] inp_b; + + do_add = inp_a + inp_b; + +endfunction + +module foo(clk, rst, inp_a, inp_b, out); + input wire clk; + input wire rst; + input wire [7:0] inp_a; + input wire [7:0] inp_b; + output wire [7:0] out; + + always @(posedge clk) + if (rst) out <= 0; + else out <= do_add (* combinational_adder *) (inp_a, inp_b); + +endmodule + diff --git a/tests/simple/attrib08_mod_inst.v b/tests/simple/attrib08_mod_inst.v new file mode 100644 index 000000000..c5a32234e --- /dev/null +++ b/tests/simple/attrib08_mod_inst.v @@ -0,0 +1,22 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output reg out; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= ~inp; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output wire out; + + (* my_module_instance = 99 *) + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib09_case.v b/tests/simple/attrib09_case.v new file mode 100644 index 000000000..8551bf9d0 --- /dev/null +++ b/tests/simple/attrib09_case.v @@ -0,0 +1,26 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire [1:0] inp; + output reg [1:0] out; + + always @(inp) + (* full_case, parallel_case *) + case(inp) + 2'd0: out <= 2'd3; + 2'd1: out <= 2'd2; + 2'd2: out <= 2'd1; + 2'd3: out <= 2'd0; + endcase + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire [1:0] inp; + output wire [1:0] out; + + bar bar_instance (clk, rst, inp, out); +endmodule + From b79bd5b3ca086718e308c75cbece0b07bbe48733 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 4 Jun 2019 10:42:42 +0200 Subject: [PATCH 03/22] Moved tests that fail with Icarus Verilog to /tests/various. Those tests are just for parsing Verilog. Signed-off-by: Maciej Kurc --- tests/various/attrib05_port_conn.v | 21 +++++++++++++++++++++ tests/various/attrib05_port_conn.ys | 2 ++ tests/various/attrib07_func_call.v | 21 +++++++++++++++++++++ tests/various/attrib07_func_call.ys | 2 ++ 4 files changed, 46 insertions(+) create mode 100644 tests/various/attrib05_port_conn.v create mode 100644 tests/various/attrib05_port_conn.ys create mode 100644 tests/various/attrib07_func_call.v create mode 100644 tests/various/attrib07_func_call.ys diff --git a/tests/various/attrib05_port_conn.v b/tests/various/attrib05_port_conn.v new file mode 100644 index 000000000..e20e66319 --- /dev/null +++ b/tests/various/attrib05_port_conn.v @@ -0,0 +1,21 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output reg out; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= ~inp; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance ( (* clock_connected *) clk, rst, (* this_is_the_input *) inp, out); +endmodule + diff --git a/tests/various/attrib05_port_conn.ys b/tests/various/attrib05_port_conn.ys new file mode 100644 index 000000000..27a016733 --- /dev/null +++ b/tests/various/attrib05_port_conn.ys @@ -0,0 +1,2 @@ +# Read and parse Verilog file +read_verilog attrib05_port_conn.v diff --git a/tests/various/attrib07_func_call.v b/tests/various/attrib07_func_call.v new file mode 100644 index 000000000..f55ef2316 --- /dev/null +++ b/tests/various/attrib07_func_call.v @@ -0,0 +1,21 @@ +function [7:0] do_add; + input [7:0] inp_a; + input [7:0] inp_b; + + do_add = inp_a + inp_b; + +endfunction + +module foo(clk, rst, inp_a, inp_b, out); + input wire clk; + input wire rst; + input wire [7:0] inp_a; + input wire [7:0] inp_b; + output wire [7:0] out; + + always @(posedge clk) + if (rst) out <= 0; + else out <= do_add (* combinational_adder *) (inp_a, inp_b); + +endmodule + diff --git a/tests/various/attrib07_func_call.ys b/tests/various/attrib07_func_call.ys new file mode 100644 index 000000000..774827651 --- /dev/null +++ b/tests/various/attrib07_func_call.ys @@ -0,0 +1,2 @@ +# Read and parse Verilog file +read_verilog attrib07_func_call.v From 03e0d3a17cf27858d16e0169614b6575c7dac538 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Wed, 5 Jun 2019 10:42:43 +0200 Subject: [PATCH 04/22] Fixed memory leak. Signed-off-by: Maciej Kurc --- frontends/verilog/verilog_parser.y | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 82a1d9d39..ccdab987f 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1535,11 +1535,13 @@ cell_port: attr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); + free_attr($1); } | attr expr { AstNode *node = new AstNode(AST_ARGUMENT); astbuf2->children.push_back(node); node->children.push_back($2); + free_attr($1); } | attr '.' TOK_ID '(' expr ')' { AstNode *node = new AstNode(AST_ARGUMENT); @@ -1547,12 +1549,14 @@ cell_port: astbuf2->children.push_back(node); node->children.push_back($5); delete $3; + free_attr($1); } | attr '.' TOK_ID '(' ')' { AstNode *node = new AstNode(AST_ARGUMENT); node->str = *$3; astbuf2->children.push_back(node); delete $3; + free_attr($1); }; always_stmt: From feb2ddb52bd7ca590596e22f73a5d3c153907391 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 5 Jun 2019 14:08:14 -0700 Subject: [PATCH 05/22] Fix typo in opt_rmdff --- passes/opt/opt_rmdff.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index 2abffa2a9..eeb992a3e 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -292,8 +292,8 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) sig_q = dff->getPort("\\Q"); sig_c = dff->getPort("\\C"); sig_e = dff->getPort("\\E"); - val_cp = RTLIL::Const(dff->type[6] == 'P', 1); - val_ep = RTLIL::Const(dff->type[7] == 'P', 1); + val_cp = RTLIL::Const(dff->type[7] == 'P', 1); + val_ep = RTLIL::Const(dff->type[8] == 'P', 1); } else if (dff->type == "$ff") { sig_d = dff->getPort("\\D"); From dd134914cc93f7506504ad95aad438a468bb0fe8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 5 Jun 2019 14:16:24 -0700 Subject: [PATCH 06/22] Error out if no top module given before 'sim' --- passes/sat/sim.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 53e248adf..4c3022c70 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -88,6 +88,8 @@ struct SimInstance SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) : shared(shared), module(module), instance(instance), parent(parent), sigmap(module) { + log_assert(module); + if (parent) { log_assert(parent->children.count(instance) == 0); parent->children[instance] = this; @@ -848,6 +850,9 @@ struct SimPass : public Pass { if (design->full_selection()) { top_mod = design->top_module(); + + if (!top_mod) + log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n"); } else { auto mods = design->selected_whole_modules(); if (GetSize(mods) != 1) From fd8ef128bfdc01b6bcf90ca5a3426aac22811161 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 5 Jun 2019 14:21:44 -0700 Subject: [PATCH 07/22] Missing doc for -tech xilinx in shregmap --- passes/techmap/shregmap.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 75eedfbcc..21dfe9619 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -606,6 +606,9 @@ struct ShregmapPass : public Pass { log(" -tech greenpak4\n"); log(" map to greenpak4 shift registers.\n"); log("\n"); + log(" -tech xilinx\n"); + log(" map to xilinx dynamic-length shift registers.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { From f3a26730b610e1d80ca408e6913311bdfc82914c Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 6 Jun 2019 10:03:03 +0000 Subject: [PATCH 08/22] ECP5: implement all Diamond I/O buffer primitives. --- techlibs/ecp5/cells_map.v | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index 6ab4b69f2..f6c71a03d 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -47,6 +47,21 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED" module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +// Diamond I/O buffers +module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule +module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule +module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule +module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule + // For Diamond compatibility, FIXME: add all Diamond flipflop mappings module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule From 7bd1c664a6f0d9a20a2f3f0c0f136403918afacf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 10:51:02 -0700 Subject: [PATCH 09/22] Initial adaptation of muxpack from shregmap --- passes/techmap/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index cf9e198ad..561636080 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -37,6 +37,7 @@ OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o +OBJS += passes/techmap/muxpack.o endif GENFILES += passes/techmap/techmap.inc From 543dd11c7e46f9c88bd1f0d21474bac95d1ab6d1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 11:03:45 -0700 Subject: [PATCH 10/22] Missing file --- passes/techmap/muxpack.cc | 232 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 passes/techmap/muxpack.cc diff --git a/passes/techmap/muxpack.cc b/passes/techmap/muxpack.cc new file mode 100644 index 000000000..4945affb0 --- /dev/null +++ b/passes/techmap/muxpack.cc @@ -0,0 +1,232 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct MuxpackWorker +{ + Module *module; + SigMap sigmap; + + int mux_count, pmux_count; + + pool remove_cells; + + dict sig_chain_next; + dict sig_chain_prev; + pool sigbit_with_non_chain_users; + pool chain_start_cells; + + void make_sig_chain_next_prev() + { + for (auto wire : module->wires()) + { + if (wire->port_output || wire->get_bool_attribute("\\keep")) { + for (auto bit : sigmap(wire)) { + sigbit_with_non_chain_users.insert(bit); + } + } + } + + for (auto cell : module->cells()) + { + if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) + { + SigSpec a_sig = sigmap(cell->getPort("\\A")); + SigSpec y_sig = sigmap(cell->getPort("\\Y")); + + if (sig_chain_next.count(a_sig)) + for (auto a_bit : a_sig.bits()) + sigbit_with_non_chain_users.insert(a_bit); + else + sig_chain_next[a_sig] = cell; + + sig_chain_prev[y_sig] = cell; + continue; + } + + for (auto conn : cell->connections()) + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + sigbit_with_non_chain_users.insert(bit); + } + } + + void find_chain_start_cells() + { + for (auto it : sig_chain_next) + { + for (auto bit : it.first.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + + if (sig_chain_prev.count(it.first) != 0) + { + Cell *c1 = sig_chain_prev.at(it.first); + Cell *c2 = it.second; + + if (c1->type != c2->type) + goto start_cell; + + if (c1->parameters != c2->parameters) + goto start_cell; + + continue; + } + + start_cell: + chain_start_cells.insert(it.second); + } + } + + vector create_chain(Cell *start_cell) + { + vector chain; + + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); + + SigSpec y_sig = sigmap(c->getPort("\\Y")); + + if (sig_chain_next.count(y_sig) == 0) + break; + + c = sig_chain_next.at(y_sig); + if (chain_start_cells.count(c) != 0) + break; + } + + return chain; + } + + void process_chain(vector &chain) + { + if (GetSize(chain) < 2) + return; + + int cursor = 0; + while (cursor < GetSize(chain)) + { + int cases = GetSize(chain) - cursor; + + Cell *first_cell = chain[cursor]; + dict taps_dict; + + if (cases < 2) { + cursor++; + continue; + } + + Cell *last_cell = chain[cursor+cases-1]; + + log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n", + log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases); + + mux_count += cases; + pmux_count += 1; + + first_cell->type = "$pmux"; + SigSpec b_sig = first_cell->getPort("\\B"); + SigSpec s_sig = first_cell->getPort("\\S"); + + for (int i = 1; i < cases; i++) { + Cell* cursor_cell = chain[cursor+i]; + b_sig.append(cursor_cell->getPort("\\B")); + s_sig.append(cursor_cell->getPort("\\S")); + remove_cells.insert(cursor_cell); + } + + first_cell->setPort("\\B", b_sig); + first_cell->setPort("\\S", s_sig); + first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); + first_cell->setPort("\\Y", last_cell->getPort("\\Y")); + + cursor += cases; + } + } + + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + remove_cells.clear(); + sig_chain_next.clear(); + sig_chain_prev.clear(); + chain_start_cells.clear(); + } + + MuxpackWorker(Module *module) : + module(module), sigmap(module), mux_count(0), pmux_count(0) + { + make_sig_chain_next_prev(); + find_chain_start_cells(); + + for (auto c : chain_start_cells) { + vector chain = create_chain(c); + process_chain(chain); + } + + cleanup(); + } +}; + +struct MuxpackPass : public Pass { + MuxpackPass() : Pass("muxpack", "TODO") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" muxpack [options] [selection]\n"); + log("\n"); + log("TODO"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing MUXPACK pass (TODO).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + int mux_count = 0; + int pmux_count = 0; + + for (auto module : design->selected_modules()) { + MuxpackWorker worker(module); + mux_count += worker.mux_count; + pmux_count += worker.pmux_count; + } + + log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count); + } +} MuxpackPass; + +PRIVATE_NAMESPACE_END From 3e76e3a6fa4355e7223b10bba394f986d6821551 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 11:54:38 -0700 Subject: [PATCH 11/22] Add tests, fix for != --- passes/techmap/muxpack.cc | 41 +++++++++++++++++++++++++++++--------- tests/various/muxpack.v | 36 +++++++++++++++++++++++++++++++++ tests/various/muxpack.ys | 42 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 tests/various/muxpack.v create mode 100644 tests/various/muxpack.ys diff --git a/passes/techmap/muxpack.cc b/passes/techmap/muxpack.cc index 4945affb0..54c52150a 100644 --- a/passes/techmap/muxpack.cc +++ b/passes/techmap/muxpack.cc @@ -54,14 +54,21 @@ struct MuxpackWorker if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) { SigSpec a_sig = sigmap(cell->getPort("\\A")); + SigSpec b_sig = sigmap(cell->getPort("\\B")); SigSpec y_sig = sigmap(cell->getPort("\\Y")); if (sig_chain_next.count(a_sig)) for (auto a_bit : a_sig.bits()) sigbit_with_non_chain_users.insert(a_bit); - else + else sig_chain_next[a_sig] = cell; + if (sig_chain_next.count(b_sig)) + for (auto b_bit : b_sig.bits()) + sigbit_with_non_chain_users.insert(b_bit); + else + sig_chain_next[b_sig] = cell; + sig_chain_prev[y_sig] = cell; continue; } @@ -77,13 +84,22 @@ struct MuxpackWorker { for (auto it : sig_chain_next) { + SigSpec next_sig; + for (auto bit : it.first.bits()) if (sigbit_with_non_chain_users.count(bit)) goto start_cell; - if (sig_chain_prev.count(it.first) != 0) + next_sig = it.second->getPort("\\A"); + if (sig_chain_prev.count(next_sig) == 0) { + next_sig = it.second->getPort("\\B"); + if (sig_chain_prev.count(next_sig) == 0) + next_sig = SigSpec(); + } + + if (!next_sig.empty()) { - Cell *c1 = sig_chain_prev.at(it.first); + Cell *c1 = sig_chain_prev.at(next_sig); Cell *c2 = it.second; if (c1->type != c2->type) @@ -149,15 +165,22 @@ struct MuxpackWorker pmux_count += 1; first_cell->type = "$pmux"; - SigSpec b_sig = first_cell->getPort("\\B"); - SigSpec s_sig = first_cell->getPort("\\S"); + SigSpec b_sig = first_cell->getPort("\\B"); + SigSpec s_sig = first_cell->getPort("\\S"); for (int i = 1; i < cases; i++) { - Cell* cursor_cell = chain[cursor+i]; - b_sig.append(cursor_cell->getPort("\\B")); - s_sig.append(cursor_cell->getPort("\\S")); + Cell* prev_cell = chain[cursor+i-1]; + Cell* cursor_cell = chain[cursor+i]; + if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) { + b_sig.append(cursor_cell->getPort("\\B")); + s_sig.append(cursor_cell->getPort("\\S")); + } + else { + b_sig.append(cursor_cell->getPort("\\A")); + s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S"))); + } remove_cells.insert(cursor_cell); - } + } first_cell->setPort("\\B", b_sig); first_cell->setPort("\\S", s_sig); diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v new file mode 100644 index 000000000..abc87ba44 --- /dev/null +++ b/tests/various/muxpack.v @@ -0,0 +1,36 @@ +module mux_if_unbal_4_1 #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s == 0) o <= i[0*W+:W]; + else if (s == 1) o <= i[1*W+:W]; + else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else o <= {W{1'bx}}; + +endmodule + +module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; +end + +endmodule + +module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s != 0) + if (s != 1) + if (s != 2) + if (s != 3) + if (s != 4) o <= i[4*W+:W]; + else o <= i[0*W+:W]; + else o <= i[3*W+:W]; + else o <= i[2*W+:W]; + else o <= i[1*W+:W]; + else o <= {W{1'bx}}; + +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys new file mode 100644 index 000000000..58c01cf05 --- /dev/null +++ b/tests/various/muxpack.ys @@ -0,0 +1,42 @@ +read_verilog muxpack.v +design -save read +hierarchy -top mux_if_unbal_4_1 +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3 +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_invert +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter From 5d4eca5a298d2f98de220cfd0efe5452ab4052d8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 11:59:41 -0700 Subject: [PATCH 12/22] Add a few more special case tests --- tests/various/muxpack.v | 23 +++++++++++++++++++++++ tests/various/muxpack.ys | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index abc87ba44..333908fcb 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -34,3 +34,26 @@ always @* else o <= {W{1'bx}}; endmodule + +module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o[W-2:0] <= i[2*W+:W-1]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; +end + +endmodule + +module mux_if_unbal_5_3_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + if (s == 0) o <= i[0*W+:W]; +// else if (s == 1) o <= i[1*W+:W]; +// else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else o <= {W{1'bx}}; +end + +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 58c01cf05..174eea74b 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -40,3 +40,31 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_width_mismatch +prep +design -save gold +muxpack +opt +stat +select -assert-count 2 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_missing +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter From b8620f7b3dde4460e5a8ed3ea7fd7aef54aa7da1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:03:44 -0700 Subject: [PATCH 13/22] One more and tidy up --- tests/various/muxpack.v | 20 ++++++++++++++------ tests/various/muxpack.ys | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 333908fcb..c2c2537a0 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -5,7 +5,6 @@ always @* else if (s == 2) o <= i[2*W+:W]; else if (s == 3) o <= i[3*W+:W]; else o <= {W{1'bx}}; - endmodule module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); @@ -17,7 +16,6 @@ always @* begin if (s == 3) o <= i[3*W+:W]; if (s == 4) o <= i[4*W+:W]; end - endmodule module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); @@ -32,7 +30,6 @@ always @* else o <= i[2*W+:W]; else o <= i[1*W+:W]; else o <= {W{1'bx}}; - endmodule module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); @@ -44,10 +41,9 @@ always @* begin if (s == 3) o <= i[3*W+:W]; if (s == 4) o <= i[4*W+:W]; end - endmodule -module mux_if_unbal_5_3_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +module mux_if_unbal_4_1_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); always @* begin if (s == 0) o <= i[0*W+:W]; // else if (s == 1) o <= i[1*W+:W]; @@ -55,5 +51,17 @@ always @* begin else if (s == 3) o <= i[3*W+:W]; else o <= {W{1'bx}}; end - endmodule + +module mux_if_unbal_5_3_order #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 3) o <= i[3*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 4) o <= i[4*W+:W]; + if (s == 0) o <= i[0*W+:W]; +end +endmodule + + diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 174eea74b..a967ddfef 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -56,7 +56,21 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter design -load read -hierarchy -top mux_if_unbal_5_3_missing +hierarchy -top mux_if_unbal_4_1_missing +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_order prep design -save gold muxpack From 030f1d30e9cd04b4412114bdc93a15a39a4597c4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:04:42 -0700 Subject: [PATCH 14/22] Add to CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 36b64e111..e67d9c903 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev - Added "gate2lut.v" techmap rule - Added "rename -src" - Added "equiv_opt" pass + - Added "muxpack" pass - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" From 3dd0682f298cec18f60c2d9da6417e287a385dd4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:11:59 -0700 Subject: [PATCH 15/22] Update doc --- passes/techmap/muxpack.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/passes/techmap/muxpack.cc b/passes/techmap/muxpack.cc index 54c52150a..9668b0d43 100644 --- a/passes/techmap/muxpack.cc +++ b/passes/techmap/muxpack.cc @@ -218,19 +218,20 @@ struct MuxpackWorker }; struct MuxpackPass : public Pass { - MuxpackPass() : Pass("muxpack", "TODO") { } + MuxpackPass() : Pass("muxpack", "$mux cell cascades to $pmux") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" muxpack [options] [selection]\n"); + log(" muxpack [selection]\n"); log("\n"); - log("TODO"); + log("This pass converts cascaded chains of $mux cells (e.g. those created by if-else\n"); + log("constructs) into $pmux cells.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - log_header(design, "Executing MUXPACK pass (TODO).\n"); + log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) From 83450a94898321a239f67f92e05fb9a246f4dd6d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:15:13 -0700 Subject: [PATCH 16/22] Move muxpack from passes/techmap to passes/opt --- passes/opt/Makefile.inc | 1 + passes/{techmap => opt}/muxpack.cc | 0 passes/techmap/Makefile.inc | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename passes/{techmap => opt}/muxpack.cc (100%) diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index 337fee9e4..ea3646330 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -14,5 +14,6 @@ OBJS += passes/opt/opt_demorgan.o OBJS += passes/opt/rmports.o OBJS += passes/opt/opt_lut.o OBJS += passes/opt/pmux2shiftx.o +OBJS += passes/opt/muxpack.o endif diff --git a/passes/techmap/muxpack.cc b/passes/opt/muxpack.cc similarity index 100% rename from passes/techmap/muxpack.cc rename to passes/opt/muxpack.cc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 561636080..cf9e198ad 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -37,7 +37,6 @@ OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o -OBJS += passes/techmap/muxpack.o endif GENFILES += passes/techmap/techmap.inc From 705388eb24022d2a310ae72cd81e67a2f0ce7586 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:44:06 -0700 Subject: [PATCH 17/22] Add non exclusive test --- tests/various/muxpack.v | 20 ++++++++++++++++++++ tests/various/muxpack.ys | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index c2c2537a0..e847fef27 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -64,4 +64,24 @@ always @* begin end endmodule +module mux_if_unbal_4_1_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s == 0) o <= i[0*W+:W]; + else if (s == 1) o <= i[1*W+:W]; + else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else if (s == 0) o <= {W{1'b0}}; + else o <= {W{1'bx}}; +endmodule +module mux_if_unbal_5_3_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; + if (s == 0) o <= i[2*W+:W]; +end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index a967ddfef..178860b88 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -6,6 +6,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -20,6 +21,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -34,6 +36,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -48,6 +51,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 2 t:$pmux design -stash gate design -import gold -as gold @@ -62,6 +66,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -76,6 +81,37 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_4_1_nonexcl +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_nonexcl +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold From d2172c6846f710e9a362708e3308dd302110deb2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:44:50 -0700 Subject: [PATCH 18/22] Non chain user check using next_sig --- passes/opt/muxpack.cc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 9668b0d43..963083107 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -84,19 +84,17 @@ struct MuxpackWorker { for (auto it : sig_chain_next) { - SigSpec next_sig; - - for (auto bit : it.first.bits()) - if (sigbit_with_non_chain_users.count(bit)) - goto start_cell; - - next_sig = it.second->getPort("\\A"); + SigSpec next_sig = it.second->getPort("\\A"); if (sig_chain_prev.count(next_sig) == 0) { next_sig = it.second->getPort("\\B"); if (sig_chain_prev.count(next_sig) == 0) next_sig = SigSpec(); } + for (auto bit : next_sig.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + if (!next_sig.empty()) { Cell *c1 = sig_chain_prev.at(next_sig); From 978fda94f684185a7d583a3865b7a68459344e46 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:46:42 -0700 Subject: [PATCH 19/22] Fix spacing --- passes/opt/muxpack.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 963083107..cb13a45b0 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -43,9 +43,8 @@ struct MuxpackWorker for (auto wire : module->wires()) { if (wire->port_output || wire->get_bool_attribute("\\keep")) { - for (auto bit : sigmap(wire)) { + for (auto bit : sigmap(wire)) sigbit_with_non_chain_users.insert(bit); - } } } @@ -58,8 +57,8 @@ struct MuxpackWorker SigSpec y_sig = sigmap(cell->getPort("\\Y")); if (sig_chain_next.count(a_sig)) - for (auto a_bit : a_sig.bits()) - sigbit_with_non_chain_users.insert(a_bit); + for (auto a_bit : a_sig.bits()) + sigbit_with_non_chain_users.insert(a_bit); else sig_chain_next[a_sig] = cell; @@ -70,7 +69,7 @@ struct MuxpackWorker sig_chain_next[b_sig] = cell; sig_chain_prev[y_sig] = cell; - continue; + continue; } for (auto conn : cell->connections()) @@ -182,7 +181,7 @@ struct MuxpackWorker first_cell->setPort("\\B", b_sig); first_cell->setPort("\\S", s_sig); - first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); + first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); first_cell->setPort("\\Y", last_cell->getPort("\\Y")); cursor += cases; From dc7b8c4b942f9d9bc61a87a81291244d0b73843b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:56:34 -0700 Subject: [PATCH 20/22] More cleanup --- passes/opt/muxpack.cc | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index cb13a45b0..ae4b67db2 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -37,6 +37,7 @@ struct MuxpackWorker dict sig_chain_prev; pool sigbit_with_non_chain_users; pool chain_start_cells; + pool candidate_cells; void make_sig_chain_next_prev() { @@ -59,14 +60,18 @@ struct MuxpackWorker if (sig_chain_next.count(a_sig)) for (auto a_bit : a_sig.bits()) sigbit_with_non_chain_users.insert(a_bit); - else + else { sig_chain_next[a_sig] = cell; + candidate_cells.insert(cell); + } if (sig_chain_next.count(b_sig)) for (auto b_bit : b_sig.bits()) sigbit_with_non_chain_users.insert(b_bit); - else + else { sig_chain_next[b_sig] = cell; + candidate_cells.insert(cell); + } sig_chain_prev[y_sig] = cell; continue; @@ -81,35 +86,34 @@ struct MuxpackWorker void find_chain_start_cells() { - for (auto it : sig_chain_next) + for (auto cell : candidate_cells) { - SigSpec next_sig = it.second->getPort("\\A"); + SigSpec next_sig = cell->getPort("\\A"); if (sig_chain_prev.count(next_sig) == 0) { - next_sig = it.second->getPort("\\B"); + next_sig = cell->getPort("\\B"); if (sig_chain_prev.count(next_sig) == 0) - next_sig = SigSpec(); + goto start_cell; } - for (auto bit : next_sig.bits()) - if (sigbit_with_non_chain_users.count(bit)) - goto start_cell; - - if (!next_sig.empty()) { + for (auto bit : next_sig.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + Cell *c1 = sig_chain_prev.at(next_sig); - Cell *c2 = it.second; + Cell *c2 = cell; if (c1->type != c2->type) goto start_cell; if (c1->parameters != c2->parameters) goto start_cell; - - continue; } + continue; + start_cell: - chain_start_cells.insert(it.second); + chain_start_cells.insert(cell); } } @@ -197,6 +201,7 @@ struct MuxpackWorker sig_chain_next.clear(); sig_chain_prev.clear(); chain_start_cells.clear(); + candidate_cells.clear(); } MuxpackWorker(Module *module) : From ccdf989025e57da7dfd5ab609676ebe3cfb2c2d6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 13:51:22 -0700 Subject: [PATCH 21/22] Support cascading $pmux.A with $mux.A and $mux.B --- passes/opt/muxpack.cc | 42 ++++++++++++++++++++++++---------------- tests/various/muxpack.v | 25 ++++++++++++++++++++++++ tests/various/muxpack.ys | 15 ++++++++++++++ 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index ae4b67db2..f9e5c8f09 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -51,10 +51,12 @@ struct MuxpackWorker for (auto cell : module->cells()) { - if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) + if (cell->type.in("$mux", "$pmux") && !cell->get_bool_attribute("\\keep")) { SigSpec a_sig = sigmap(cell->getPort("\\A")); - SigSpec b_sig = sigmap(cell->getPort("\\B")); + SigSpec b_sig; + if (cell->type == "$mux") + b_sig = sigmap(cell->getPort("\\B")); SigSpec y_sig = sigmap(cell->getPort("\\Y")); if (sig_chain_next.count(a_sig)) @@ -65,12 +67,14 @@ struct MuxpackWorker candidate_cells.insert(cell); } - if (sig_chain_next.count(b_sig)) - for (auto b_bit : b_sig.bits()) - sigbit_with_non_chain_users.insert(b_bit); - else { - sig_chain_next[b_sig] = cell; - candidate_cells.insert(cell); + if (!b_sig.empty()) { + if (sig_chain_next.count(b_sig)) + for (auto b_bit : b_sig.bits()) + sigbit_with_non_chain_users.insert(b_bit); + else { + sig_chain_next[b_sig] = cell; + candidate_cells.insert(cell); + } } sig_chain_prev[y_sig] = cell; @@ -88,10 +92,16 @@ struct MuxpackWorker { for (auto cell : candidate_cells) { + log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type)); + SigSpec next_sig = cell->getPort("\\A"); if (sig_chain_prev.count(next_sig) == 0) { - next_sig = cell->getPort("\\B"); - if (sig_chain_prev.count(next_sig) == 0) + if (cell->type == "$mux") { + next_sig = cell->getPort("\\B"); + if (sig_chain_prev.count(next_sig) == 0) + goto start_cell; + } + else goto start_cell; } @@ -103,10 +113,7 @@ struct MuxpackWorker Cell *c1 = sig_chain_prev.at(next_sig); Cell *c2 = cell; - if (c1->type != c2->type) - goto start_cell; - - if (c1->parameters != c2->parameters) + if (c1->getParam("\\WIDTH") != c2->getParam("\\WIDTH")) goto start_cell; } @@ -220,15 +227,16 @@ struct MuxpackWorker }; struct MuxpackPass : public Pass { - MuxpackPass() : Pass("muxpack", "$mux cell cascades to $pmux") { } + MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" muxpack [selection]\n"); log("\n"); - log("This pass converts cascaded chains of $mux cells (e.g. those created by if-else\n"); - log("constructs) into $pmux cells.\n"); + log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n"); + log("constructs) and $mux cells (e.g. those created by if-else constructs) into \n"); + log("into $pmux cells.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index e847fef27..fe0150532 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -85,3 +85,28 @@ always @* begin if (s == 0) o <= i[2*W+:W]; end endmodule + +module mux_case_unbal_7_7#(parameter N=7, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + case (s) + 0: o <= i[0*W+:W]; + default: + case (s) + 1: o <= i[1*W+:W]; + 2: o <= i[2*W+:W]; + default: + case (s) + 3: o <= i[3*W+:W]; + 4: o <= i[4*W+:W]; + 5: o <= i[5*W+:W]; + default: + case (s) + 6: o <= i[6*W+:W]; + default: o <= i[7*W+:W]; + endcase + endcase + endcase + endcase +end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 178860b88..4dcb9ed89 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -118,3 +118,18 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_case_unbal_7_7 +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter From 0a66720f6f67b087fe6342d01d45944506240942 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 14:01:42 -0700 Subject: [PATCH 22/22] Fix warnings --- tests/various/muxpack.v | 4 ++-- tests/various/muxpack.ys | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index fe0150532..7c189fff8 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -74,7 +74,7 @@ always @* else o <= {W{1'bx}}; endmodule -module mux_if_unbal_5_3_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +module mux_if_unbal_5_3_nonexcl #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); always @* begin o <= {W{1'bx}}; if (s == 0) o <= i[0*W+:W]; @@ -86,7 +86,7 @@ always @* begin end endmodule -module mux_case_unbal_7_7#(parameter N=7, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +module mux_case_unbal_8_7#(parameter N=8, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); always @* begin o <= {W{1'bx}}; case (s) diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 4dcb9ed89..0c5b82818 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -120,7 +120,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter design -load read -hierarchy -top mux_case_unbal_7_7 +hierarchy -top mux_case_unbal_8_7 prep design -save gold muxpack