diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | backends/cxxrtl/cxxrtl.h | 16 | ||||
-rw-r--r-- | backends/cxxrtl/cxxrtl_backend.cc | 22 | ||||
-rw-r--r-- | backends/cxxrtl/cxxrtl_vcd.h | 4 | ||||
-rw-r--r-- | frontends/verilog/preproc.cc | 6 | ||||
-rw-r--r-- | passes/cmds/scc.cc | 77 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 2 | ||||
-rw-r--r-- | techlibs/xilinx/cells_sim.v | 80 | ||||
-rw-r--r-- | techlibs/xilinx/xilinx_dffopt.cc | 6 | ||||
-rw-r--r-- | tests/arch/xilinx/mux.ys | 3 | ||||
-rw-r--r-- | tests/arch/xilinx/xilinx_dffopt.ys | 46 | ||||
-rw-r--r-- | tests/simple/macro_arg_surrounding_spaces.v | 20 |
12 files changed, 243 insertions, 41 deletions
@@ -126,7 +126,7 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.9+3863 +YOSYS_VER := 0.9+3876 GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN) OBJS = kernel/version_$(GIT_REV).o diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 0a6bcb849..0e55c46c2 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -1217,49 +1217,49 @@ value<BitsY> xnor_ss(const value<BitsA> &a, const value<BitsB> &b) { template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> shl_uu(const value<BitsA> &a, const value<BitsB> &b) { - return a.template zcast<BitsY>().template shl(b); + return a.template zcast<BitsY>().shl(b); } template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> shl_su(const value<BitsA> &a, const value<BitsB> &b) { - return a.template scast<BitsY>().template shl(b); + return a.template scast<BitsY>().shl(b); } template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> sshl_uu(const value<BitsA> &a, const value<BitsB> &b) { - return a.template zcast<BitsY>().template shl(b); + return a.template zcast<BitsY>().shl(b); } template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> sshl_su(const value<BitsA> &a, const value<BitsB> &b) { - return a.template scast<BitsY>().template shl(b); + return a.template scast<BitsY>().shl(b); } template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> shr_uu(const value<BitsA> &a, const value<BitsB> &b) { - return a.template shr(b).template zcast<BitsY>(); + return a.shr(b).template zcast<BitsY>(); } template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> shr_su(const value<BitsA> &a, const value<BitsB> &b) { - return a.template shr(b).template scast<BitsY>(); + return a.shr(b).template scast<BitsY>(); } template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> sshr_uu(const value<BitsA> &a, const value<BitsB> &b) { - return a.template shr(b).template zcast<BitsY>(); + return a.shr(b).template zcast<BitsY>(); } template<size_t BitsY, size_t BitsA, size_t BitsB> CXXRTL_ALWAYS_INLINE value<BitsY> sshr_su(const value<BitsA> &a, const value<BitsB> &b) { - return a.template sshr(b).template scast<BitsY>(); + return a.sshr(b).template scast<BitsY>(); } template<size_t BitsY, size_t BitsA, size_t BitsB> diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 861b484f4..39046bd78 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -601,6 +601,12 @@ struct WireType { bool is_exact() const { return type == ALIAS || type == CONST; } }; +// Tests for a SigSpec that is a valid clock input, clocks have to have a backing wire and be a single bit +// using this instead of sig.is_wire() solves issues when the clock is a slice instead of a full wire +bool is_valid_clock(const RTLIL::SigSpec& sig) { + return sig.is_chunk() && sig.is_bit() && sig[0].wire; +} + struct CxxrtlWorker { bool split_intf = false; std::string intf_filename; @@ -1110,7 +1116,8 @@ struct CxxrtlWorker { // Flip-flops } else if (is_ff_cell(cell->type)) { log_assert(!for_debug); - if (cell->hasPort(ID::CLK) && cell->getPort(ID::CLK).is_wire()) { + // Clocks might be slices of larger signals but should only ever be single bit + if (cell->hasPort(ID::CLK) && is_valid_clock(cell->getPort(ID::CLK))) { // Edge-sensitive logic RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0]; clk_bit = sigmaps[clk_bit.wire->module](clk_bit); @@ -2266,7 +2273,7 @@ struct CxxrtlWorker { void register_edge_signal(SigMap &sigmap, RTLIL::SigSpec signal, RTLIL::SyncType type) { signal = sigmap(signal); - log_assert(signal.is_wire() && signal.is_bit()); + log_assert(is_valid_clock(signal)); log_assert(type == RTLIL::STp || type == RTLIL::STn || type == RTLIL::STe); RTLIL::SigBit sigbit = signal[0]; @@ -2274,7 +2281,8 @@ struct CxxrtlWorker { edge_types[sigbit] = type; else if (edge_types[sigbit] != type) edge_types[sigbit] = RTLIL::STe; - edge_wires.insert(signal.as_wire()); + // Cannot use as_wire because signal might not be a full wire, instead extract the wire from the sigbit + edge_wires.insert(sigbit.wire); } void analyze_design(RTLIL::Design *design) @@ -2355,14 +2363,14 @@ struct CxxrtlWorker { // Various DFF cells are treated like posedge/negedge processes, see above for details. if (cell->type.in(ID($dff), ID($dffe), ID($adff), ID($adffe), ID($dffsr), ID($dffsre), ID($sdff), ID($sdffe), ID($sdffce))) { - if (sigmap(cell->getPort(ID::CLK)).is_wire()) + if (is_valid_clock(cell->getPort(ID::CLK))) register_edge_signal(sigmap, cell->getPort(ID::CLK), cell->parameters[ID::CLK_POLARITY].as_bool() ? RTLIL::STp : RTLIL::STn); } // Similar for memory port cells. if (cell->type.in(ID($memrd), ID($memwr))) { if (cell->getParam(ID::CLK_ENABLE).as_bool()) { - if (sigmap(cell->getPort(ID::CLK)).is_wire()) + if (is_valid_clock(cell->getPort(ID::CLK))) register_edge_signal(sigmap, cell->getPort(ID::CLK), cell->parameters[ID::CLK_POLARITY].as_bool() ? RTLIL::STp : RTLIL::STn); } @@ -2372,7 +2380,7 @@ struct CxxrtlWorker { if (cell->type == ID($memwr)) writable_memories.insert(module->memories[cell->getParam(ID::MEMID).decode_string()]); // Collect groups of memory write ports in the same domain. - if (cell->type == ID($memwr) && cell->getParam(ID::CLK_ENABLE).as_bool() && cell->getPort(ID::CLK).is_wire()) { + if (cell->type == ID($memwr) && cell->getParam(ID::CLK_ENABLE).as_bool() && is_valid_clock(cell->getPort(ID::CLK))) { RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID::CLK))[0]; const RTLIL::Memory *memory = module->memories[cell->getParam(ID::MEMID).decode_string()]; memwr_per_domain[{clk_bit, memory}].insert(cell); @@ -2384,7 +2392,7 @@ struct CxxrtlWorker { } for (auto cell : module->cells()) { // Collect groups of memory write ports read by every transparent read port. - if (cell->type == ID($memrd) && cell->getParam(ID::CLK_ENABLE).as_bool() && cell->getPort(ID::CLK).is_wire() && + if (cell->type == ID($memrd) && cell->getParam(ID::CLK_ENABLE).as_bool() && is_valid_clock(cell->getPort(ID::CLK)) && cell->getParam(ID::TRANSPARENT).as_bool()) { RTLIL::SigBit clk_bit = sigmap(cell->getPort(ID::CLK))[0]; const RTLIL::Memory *memory = module->memories[cell->getParam(ID::MEMID).decode_string()]; diff --git a/backends/cxxrtl/cxxrtl_vcd.h b/backends/cxxrtl/cxxrtl_vcd.h index 6ee98b428..3f40a8d12 100644 --- a/backends/cxxrtl/cxxrtl_vcd.h +++ b/backends/cxxrtl/cxxrtl_vcd.h @@ -228,13 +228,13 @@ public: } void add(const debug_items &items) { - this->template add(items, [](const std::string &, const debug_item &) { + this->add(items, [](const std::string &, const debug_item &) { return true; }); } void add_without_memories(const debug_items &items) { - this->template add(items, [](const std::string &, const debug_item &item) { + this->add(items, [](const std::string &, const debug_item &item) { return item.type != debug_item::MEMORY; }); } diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 5a2804a41..c451c4c20 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -390,12 +390,16 @@ static void input_file(std::istream &f, std::string filename) // the argument list); false if we finished with ','. static bool read_argument(std::string &dest) { + skip_spaces(); std::vector<char> openers; for (;;) { std::string tok = next_token(true); if (tok == ")") { - if (openers.empty()) + if (openers.empty()) { + while (dest.size() && (dest.back() == ' ' || dest.back() == '\t')) + dest = dest.substr(0, dest.size() - 1); return true; + } if (openers.back() != '(') log_error("Mismatched brackets in macro argument: %c and %c.\n", openers.back(), tok[0]); diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 8e7f3f990..7aa9a484f 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -37,7 +37,7 @@ struct SccWorker RTLIL::Design *design; RTLIL::Module *module; SigMap sigmap; - CellTypes ct; + CellTypes ct, specifyCells; std::set<RTLIL::Cell*> workQueue; std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell; @@ -100,7 +100,7 @@ struct SccWorker } } - SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) : + SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, bool specifyMode, int maxDepth) : design(design), module(module), sigmap(module) { if (module->processes.size() > 0) { @@ -115,6 +115,18 @@ struct SccWorker ct.setup_stdcells(); } + // Discover boxes with specify rules in them, for special handling. + if (specifyMode) { + for (auto mod : design->modules()) + if (mod->get_blackbox_attribute(false)) + for (auto cell : mod->cells()) + if (cell->type == ID($specify2)) + { + specifyCells.setup_module(mod); + break; + } + } + SigPool selectedSignals; SigSet<RTLIL::Cell*> sigToNextCells; @@ -129,29 +141,52 @@ struct SccWorker if (!design->selected(module, cell)) continue; - if (!allCellTypes && !ct.cell_known(cell->type)) + if (!allCellTypes && !ct.cell_known(cell->type) && !specifyCells.cell_known(cell->type)) continue; workQueue.insert(cell); RTLIL::SigSpec inputSignals, outputSignals; - for (auto &conn : cell->connections()) - { - bool isInput = true, isOutput = true; + if (specifyCells.cell_known(cell->type)) { + // Use specify rules of the type `(X => Y) = NN` to look for asynchronous paths in boxes. + for (auto subcell : design->module(cell->type)->cells()) + { + if (subcell->type != ID($specify2)) + continue; - if (ct.cell_known(cell->type)) { - isInput = ct.cell_input(cell->type, conn.first); - isOutput = ct.cell_output(cell->type, conn.first); + for (auto bit : subcell->getPort(ID::SRC)) + { + if (!bit.wire || !cell->hasPort(bit.wire->name)) + continue; + inputSignals.append(sigmap(cell->getPort(bit.wire->name))); + } + + for (auto bit : subcell->getPort(ID::DST)) + { + if (!bit.wire || !cell->hasPort(bit.wire->name)) + continue; + outputSignals.append(sigmap(cell->getPort(bit.wire->name))); + } } + } else { + for (auto &conn : cell->connections()) + { + bool isInput = true, isOutput = true; + + if (ct.cell_known(cell->type)) { + isInput = ct.cell_input(cell->type, conn.first); + isOutput = ct.cell_output(cell->type, conn.first); + } - RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second)); - sig.sort_and_unify(); + RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second)); + sig.sort_and_unify(); - if (isInput) - inputSignals.append(sig); - if (isOutput) - outputSignals.append(sig); + if (isInput) + inputSignals.append(sig); + if (isOutput) + outputSignals.append(sig); + } } inputSignals.sort_and_unify(); @@ -228,7 +263,7 @@ struct SccPass : public Pass { log("design.\n"); log("\n"); log(" -expect <num>\n"); - log(" expect to find exactly <num> SSCs. A different number of SSCs will\n"); + log(" expect to find exactly <num> SCCs. A different number of SCCs will\n"); log(" produce an error.\n"); log("\n"); log(" -max_depth <num>\n"); @@ -254,6 +289,9 @@ struct SccPass : public Pass { log(" replace the current selection with a selection of all cells and wires\n"); log(" that are part of a found logic loop\n"); log("\n"); + log(" -specify\n"); + log(" examine specify rules to detect logic loops in whitebox/blackbox cells\n"); + log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) override { @@ -261,6 +299,7 @@ struct SccPass : public Pass { bool allCellTypes = false; bool selectMode = false; bool nofeedbackMode = false; + bool specifyMode = false; int maxDepth = -1; int expect = -1; @@ -293,6 +332,10 @@ struct SccPass : public Pass { selectMode = true; continue; } + if (args[argidx] == "-specify") { + specifyMode = true; + continue; + } break; } int origSelectPos = design->selection_stack.size() - 1; @@ -303,7 +346,7 @@ struct SccPass : public Pass { for (auto mod : design->selected_modules()) { - SccWorker worker(design, mod, nofeedbackMode, allCellTypes, maxDepth); + SccWorker worker(design, mod, nofeedbackMode, allCellTypes, specifyMode, maxDepth); if (!setAttr.empty()) { diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7d017ac40..56bb15495 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -339,7 +339,7 @@ struct Abc9Pass : public ScriptPass if (check_label("pre")) { run("read_verilog -icells -lib -specify +/abc9_model.v"); - run("scc -set_attr abc9_scc_id {}"); + run("scc -specify -set_attr abc9_scc_id {}"); if (help_mode) run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); else diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index adaf7aee1..a079f1c95 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -633,6 +633,41 @@ module FDRSE ( Q <= d; endmodule +module FDRSE_1 ( + output reg Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + (* invertible_pin = "IS_CE_INVERTED" *) + input CE, + (* invertible_pin = "IS_D_INVERTED" *) + input D, + (* invertible_pin = "IS_R_INVERTED" *) + input R, + (* invertible_pin = "IS_S_INVERTED" *) + input S +); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_R_INVERTED = 1'b0; + parameter [0:0] IS_S_INVERTED = 1'b0; + initial Q <= INIT; + wire c = C ^ IS_C_INVERTED; + wire ce = CE ^ IS_CE_INVERTED; + wire d = D ^ IS_D_INVERTED; + wire r = R ^ IS_R_INVERTED; + wire s = S ^ IS_S_INVERTED; + always @(negedge c) + if (r) + Q <= 0; + else if (s) + Q <= 1; + else if (ce) + Q <= d; +endmodule + (* abc9_box, lib_whitebox *) module FDCE ( output reg Q, @@ -837,6 +872,51 @@ module FDCPE ( assign Q = qs ? qp : qc; endmodule +module FDCPE_1 ( + output wire Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + input CE, + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR, + input D, + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE +); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + wire c = C ^ IS_C_INVERTED; + wire clr = CLR ^ IS_CLR_INVERTED; + wire pre = PRE ^ IS_PRE_INVERTED; + // Hacky model to avoid simulation-synthesis mismatches. + reg qc, qp, qs; + initial qc = INIT; + initial qp = INIT; + initial qs = 0; + always @(negedge c, posedge clr) begin + if (clr) + qc <= 0; + else if (CE) + qc <= D; + end + always @(negedge c, posedge pre) begin + if (pre) + qp <= 1; + else if (CE) + qp <= D; + end + always @* begin + if (clr) + qs <= 0; + else if (pre) + qs <= 1; + end + assign Q = qs ? qp : qc; +endmodule + module LDCE ( output reg Q, (* invertible_pin = "IS_CLR_INVERTED" *) diff --git a/techlibs/xilinx/xilinx_dffopt.cc b/techlibs/xilinx/xilinx_dffopt.cc index 365f505fb..598f1b216 100644 --- a/techlibs/xilinx/xilinx_dffopt.cc +++ b/techlibs/xilinx/xilinx_dffopt.cc @@ -209,7 +209,7 @@ lut_sigin_done: continue; LutData lut_d = it_D->second.first; Cell *cell_d = it_D->second.second; - if (cell->getParam(ID(IS_D_INVERTED)).as_bool()) { + if (cell->hasParam(ID(IS_D_INVERTED)) && cell->getParam(ID(IS_D_INVERTED)).as_bool()) { // Flip all bits in the LUT. for (int i = 0; i < GetSize(lut_d.first); i++) lut_d.first.bits[i] = (lut_d.first.bits[i] == State::S1) ? State::S0 : State::S1; @@ -249,7 +249,7 @@ lut_sigin_done: if (has_s) { SigBit sig_S = sigmap(cell->getPort(ID::S)); LutData lut_s = LutData(Const(2, 2), {sig_S}); - bool inv_s = cell->getParam(ID(IS_S_INVERTED)).as_bool(); + bool inv_s = cell->hasParam(ID(IS_S_INVERTED)) && cell->getParam(ID(IS_S_INVERTED)).as_bool(); auto it_S = bit_to_lut.find(sig_S); if (it_S != bit_to_lut.end()) lut_s = it_S->second.first; @@ -271,7 +271,7 @@ lut_sigin_done: if (has_r) { SigBit sig_R = sigmap(cell->getPort(ID::R)); LutData lut_r = LutData(Const(2, 2), {sig_R}); - bool inv_r = cell->getParam(ID(IS_R_INVERTED)).as_bool(); + bool inv_r = cell->hasParam(ID(IS_R_INVERTED)) && cell->getParam(ID(IS_R_INVERTED)).as_bool(); auto it_R = bit_to_lut.find(sig_R); if (it_R != bit_to_lut.end()) lut_r = it_R->second.first; diff --git a/tests/arch/xilinx/mux.ys b/tests/arch/xilinx/mux.ys index 1b2788448..c2a23de6d 100644 --- a/tests/arch/xilinx/mux.ys +++ b/tests/arch/xilinx/mux.ys @@ -40,10 +40,11 @@ proc equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module +select -assert-max 2 t:LUT3 select -assert-max 2 t:LUT4 select -assert-min 4 t:LUT6 select -assert-max 7 t:LUT6 select -assert-max 2 t:MUXF7 dump -select -assert-none t:LUT6 t:LUT4 t:MUXF7 %% t:* %D +select -assert-none t:LUT6 t:LUT4 t:LUT3 t:MUXF7 %% t:* %D diff --git a/tests/arch/xilinx/xilinx_dffopt.ys b/tests/arch/xilinx/xilinx_dffopt.ys index 2c729832e..c09699411 100644 --- a/tests/arch/xilinx/xilinx_dffopt.ys +++ b/tests/arch/xilinx/xilinx_dffopt.ys @@ -223,3 +223,49 @@ select -assert-count 1 t:LUT2 select -assert-none t:FDRSE t:LUT4 t:LUT2 %% t:* %D design -reset + + +read_verilog << EOT + +// FDSE_1, mergeable CE and S, but CE only not worth it. + +module t0 (...); +input wire clk; +input wire [7:0] i; +output wire [7:0] o; + +wire [7:0] tmp ; + +LUT2 #(.INIT(4'h6)) lut0 (.I0(i[0]), .I1(i[1]), .O(tmp[0])); +LUT2 #(.INIT(4'h6)) lut1 (.I0(i[1]), .I1(i[2]), .O(tmp[1])); + +FDSE_1 ff (.D(tmp[0]), .CE(i[7]), .S(tmp[1]), .Q(o[0])); + +endmodule + +EOT + +read_verilog -lib +/xilinx/cells_sim.v +design -save t0 + +equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt +design -load postopt +clean + +cd t0 +select -assert-count 1 t:FDSE_1 +select -assert-count 1 t:LUT5 +select -assert-none t:FDSE_1 t:LUT5 %% t:* %D + +design -load t0 + +equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt -lut4 +design -load postopt +clean + +cd t0 +select -assert-count 1 t:FDSE_1 +select -assert-count 2 t:LUT2 +select -assert-none t:FDSE_1 t:LUT2 %% t:* %D + +design -reset diff --git a/tests/simple/macro_arg_surrounding_spaces.v b/tests/simple/macro_arg_surrounding_spaces.v new file mode 100644 index 000000000..3dbb5ea01 --- /dev/null +++ b/tests/simple/macro_arg_surrounding_spaces.v @@ -0,0 +1,20 @@ +module top( + IDENT_V_, + IDENT_W_, + IDENT_X_, + IDENT_Y_, + IDENT_Z_, + IDENT_A_, + IDENT_B_, + IDENT_C_ +); + `define MACRO(dummy, x) IDENT_``x``_ + output wire IDENT_V_; + output wire `MACRO(_,W); + output wire `MACRO(_, X); + output wire `MACRO(_,Y ); + output wire `MACRO(_, Z ); + output wire `MACRO(_, A); + output wire `MACRO(_,B ); + output wire `MACRO(_, C ); +endmodule |