diff --git a/techlibs/nanoxplore/Makefile.inc b/techlibs/nanoxplore/Makefile.inc index cae2817b3..f6606639e 100644 --- a/techlibs/nanoxplore/Makefile.inc +++ b/techlibs/nanoxplore/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/nanoxplore/synth_nanoxplore.o +OBJS += techlibs/nanoxplore/nx_carry.o # Techmap $(eval $(call add_share_file,share/nanoxplore,techlibs/nanoxplore/arith_map.v)) diff --git a/techlibs/nanoxplore/arith_map.v b/techlibs/nanoxplore/arith_map.v index 69e83b68c..7b4534b83 100644 --- a/techlibs/nanoxplore/arith_map.v +++ b/techlibs/nanoxplore/arith_map.v @@ -1,4 +1,21 @@ -`default_nettype none +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Miodrag Milanovic + * + * 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. + * + */ (* techmap_celltype = "$alu" *) module _80_nx_cy_alu (A, B, CI, BI, X, Y, CO); @@ -26,46 +43,32 @@ module _80_nx_cy_alu (A, B, CI, BI, X, Y, CO); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - function integer round_up4; - input integer N; - begin - round_up4 = ((N + 3) / 4) * 4; - end - endfunction - - localparam Y_WIDTH4 = round_up4(Y_WIDTH); - (* force_downto *) - wire [Y_WIDTH4-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] AA = A_buf; (* force_downto *) - wire [Y_WIDTH4-1:0] BB = BI ? ~B_buf : B_buf; - (* force_downto *) - wire [Y_WIDTH4-1:0] BX = B_buf; - (* force_downto *) - wire [Y_WIDTH4:0] C = {CO, CI}; - (* force_downto *) - wire [Y_WIDTH4-1:0] FCO, Y1; + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; genvar i; - generate for (i = 0; i < Y_WIDTH4; i = i + 4) begin:slice - NX_CY cy_i ( - .CI(C[i]), - .A1(AA[i]), .A2(AA[i+1]), .A3(AA[i+2]), .A4(AA[i+3]), - .B1(BB[i]), .B2(BB[i+1]), .B3(BB[i+2]), .B4(BB[i+3]), - .S1(Y1[i]), .S2(Y1[i+1]), .S3(Y1[i+2]), .S4(Y1[i+3]), - .CO(FCO[i]) - ); + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice + NX_CY_1BIT #(.first(i==0)) + alu_i ( + .CI(i==0 ? CI : CO[i-1]), + .A(AA[i]), + .B(BB[i]), + .S(Y[i]), + .CO(CO[i]) + ); - assign CO[i] = (AA[i] && BB[i]) || (C[i] && (AA[i] || BB[i])); - if (i+1 < Y_WIDTH) - assign CO[i+1] = (AA[i+1] && BB[i+1]) || (C[i+1] && (AA[i+1] || BB[i+1])); - if (i+2 < Y_WIDTH) - assign CO[i+2] = (AA[i+2] && BB[i+2]) || (C[i+2] && (AA[i+2] || BB[i+2])); - if (i+3 < Y_WIDTH) - assign CO[i+3] = FCO[i]; + end: slice + endgenerate - end endgenerate + NX_CY_1BIT alu_cout( + .CI(CO[Y_WIDTH-1]), + .A(1'b0), + .B(1'b0), + .S(CO[Y_WIDTH-1]) + ); - assign X = AA ^ BB; - assign Y = Y1[Y_WIDTH-1:0]; + /* End implementation */ + assign X = AA ^ BB; endmodule diff --git a/techlibs/nanoxplore/cells_sim.v b/techlibs/nanoxplore/cells_sim.v index 88ec78b5c..9c3cace47 100644 --- a/techlibs/nanoxplore/cells_sim.v +++ b/techlibs/nanoxplore/cells_sim.v @@ -184,4 +184,16 @@ module NX_IOB_O(I, C, T, IO); assign IO = C ? I : 1'bz; endmodule +(* abc9_box, lib_whitebox *) +module NX_CY_1BIT(CI, A, B, S, CO); + (* abc9_carry *) + input CI; + input A; + input B; + output S; + (* abc9_carry *) + output CO; + parameter first = 1'b0; + assign {CO, S} = A + B + CI; +endmodule diff --git a/techlibs/nanoxplore/nx_carry.cc b/techlibs/nanoxplore/nx_carry.cc new file mode 100644 index 000000000..f67cc7d5c --- /dev/null +++ b/techlibs/nanoxplore/nx_carry.cc @@ -0,0 +1,158 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2024 Miodrag Milanovic + * + * 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 + +static SigBit get_bit_or_zero(const SigSpec &sig) +{ + if (GetSize(sig) == 0) + return State::S0; + return sig[0]; +} + +static void nx_carry_chain(Module *module) +{ + SigMap sigmap(module); + + dict carry_ci_propagate; + for (auto cell : module->cells()) + { + if (cell->type == ID(NX_CY_1BIT)) { + // Only first can have CI generated that is not constant + if (cell->getParam(ID(first)).as_int() == 0) continue; + if (!cell->getPort(ID(CI)).is_wire()) continue; + carry_ci_propagate[cell] = cell->getPort(ID(CI)).as_bit(); + } + } + + for (auto cy : carry_ci_propagate) + { + Cell *cell = cy.first; + cell->setParam(ID(first), Const(0, 1)); + + SigBit new_co = module->addWire(NEW_ID); + Cell *c = module->addCell(NEW_ID, ID(NX_CY_1BIT)); + c->setParam(ID(first), Const(1)); + c->setPort(ID(CI), State::S0); + c->setPort(ID(A), cy.second); + c->setPort(ID(B), State::S0); + c->setPort(ID(CO), new_co); + cell->setPort(ID(CI), new_co); + + log("Adding cell %s to propaget CI signal.\n", log_id(cell)); + } + carry_ci_propagate.clear(); + + dict carry; + for (auto cell : module->cells()) + { + if (cell->type == ID(NX_CY_1BIT)) { + if (cell->getParam(ID(first)).as_int() == 1) continue; + if (!cell->hasPort(ID(CI))) + log_error("Not able to find connected carry.\n"); + SigBit ci = sigmap(cell->getPort(ID(CI)).as_bit()); + carry[ci] = cell; + } + } + + dict> carry_chains; + log("Detecting carry chains\n"); + for (auto cell : module->cells()) + { + if (cell->type == ID(NX_CY_1BIT)) { + if (cell->getParam(ID(first)).as_int() == 0) continue; + + vector chain; + SigBit co = sigmap(cell->getPort(ID(CO)).as_bit()); + Cell *current = cell; + chain.push_back(current); + while (co.is_wire()) + { + if (carry.count(co)==0) + break; + //log_error("Not able to find connected carry.\n"); + current = carry[co]; + chain.push_back(current); + if (!current->hasPort(ID(CO))) break; + co = sigmap(current->getPort(ID(CO)).as_bit()); + } + carry_chains[cell] = chain; + } + } + + log("Creating NX_CY cells.\n"); + for(auto& c : carry_chains) { + Cell *cell = nullptr; + int j = 0; + IdString names_A[] = { ID(A1), ID(A2), ID(A3), ID(A4) }; + IdString names_B[] = { ID(B1), ID(B2), ID(B3), ID(B4) }; + IdString names_S[] = { ID(S1), ID(S2), ID(S3), ID(S4) }; + for (size_t i=0 ; iaddCell(NEW_ID, ID(NX_CY)); + cell->setPort(ID(CI), c.second.at(i)->getPort(ID(CI))); + } + if (j==3) + cell->setPort(ID(CO), c.second.at(i)->getPort(ID(CO))); + + + cell->setPort(names_A[j], get_bit_or_zero(c.second.at(i)->getPort(ID(A)))); + cell->setPort(names_B[j], get_bit_or_zero(c.second.at(i)->getPort(ID(B)))); + + if (c.second.at(i)->hasPort(ID(S))) + cell->setPort(names_S[j], c.second.at(i)->getPort(ID(S))); + + j = (j + 1) % 4; + module->remove(c.second.at(i)); + } + } +} + +struct NXCarryPass : public Pass { + NXCarryPass() : Pass("nx_carry", "NanoXplore: create carry cells") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" nx_carry [options] [selection]\n"); + log("\n"); + log("Fixes carry chain if needed, break it on 24 elements and group by 4 into NX_CY.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + log_header(design, "Executing NX_CARRY pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + nx_carry_chain(module); + } +} NXCarryPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/nanoxplore/synth_nanoxplore.cc b/techlibs/nanoxplore/synth_nanoxplore.cc index 23a2af278..975f78cae 100644 --- a/techlibs/nanoxplore/synth_nanoxplore.cc +++ b/techlibs/nanoxplore/synth_nanoxplore.cc @@ -279,8 +279,10 @@ struct SynthNanoXplorePass : public ScriptPass { if (nocy) run("techmap"); - else + else { run("techmap -map +/techmap.v -map +/nanoxplore/arith_map.v"); + run("nx_carry"); + } if (help_mode || iopad) { run("iopadmap -bits -outpad $__BEYOND_OBUF I:PAD -inpad $__BEYOND_IBUF O:PAD A:top", "(only if '-iopad')"); run("techmap -map +/nanoxplore/io_map.v");