mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +00:00
Initial carry chain handling pass
This commit is contained in:
parent
474ed28aee
commit
da6a62f3a0
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
OBJS += techlibs/nanoxplore/synth_nanoxplore.o
|
OBJS += techlibs/nanoxplore/synth_nanoxplore.o
|
||||||
|
OBJS += techlibs/nanoxplore/nx_carry.o
|
||||||
|
|
||||||
# Techmap
|
# Techmap
|
||||||
$(eval $(call add_share_file,share/nanoxplore,techlibs/nanoxplore/arith_map.v))
|
$(eval $(call add_share_file,share/nanoxplore,techlibs/nanoxplore/arith_map.v))
|
||||||
|
|
|
@ -1,4 +1,21 @@
|
||||||
`default_nettype none
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 Miodrag Milanovic <micko@yosyshq.com>
|
||||||
|
*
|
||||||
|
* 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" *)
|
(* techmap_celltype = "$alu" *)
|
||||||
module _80_nx_cy_alu (A, B, CI, BI, X, Y, CO);
|
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(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));
|
\$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 *)
|
(* force_downto *)
|
||||||
wire [Y_WIDTH4-1:0] AA = A_buf;
|
wire [Y_WIDTH-1:0] AA = A_buf;
|
||||||
(* force_downto *)
|
(* force_downto *)
|
||||||
wire [Y_WIDTH4-1:0] BB = BI ? ~B_buf : B_buf;
|
wire [Y_WIDTH-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;
|
|
||||||
|
|
||||||
genvar i;
|
genvar i;
|
||||||
generate for (i = 0; i < Y_WIDTH4; i = i + 4) begin:slice
|
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
|
||||||
NX_CY cy_i (
|
NX_CY_1BIT #(.first(i==0))
|
||||||
.CI(C[i]),
|
alu_i (
|
||||||
.A1(AA[i]), .A2(AA[i+1]), .A3(AA[i+2]), .A4(AA[i+3]),
|
.CI(i==0 ? CI : CO[i-1]),
|
||||||
.B1(BB[i]), .B2(BB[i+1]), .B3(BB[i+2]), .B4(BB[i+3]),
|
.A(AA[i]),
|
||||||
.S1(Y1[i]), .S2(Y1[i+1]), .S3(Y1[i+2]), .S4(Y1[i+3]),
|
.B(BB[i]),
|
||||||
.CO(FCO[i])
|
.S(Y[i]),
|
||||||
);
|
.CO(CO[i])
|
||||||
|
);
|
||||||
|
|
||||||
assign CO[i] = (AA[i] && BB[i]) || (C[i] && (AA[i] || BB[i]));
|
end: slice
|
||||||
if (i+1 < Y_WIDTH)
|
endgenerate
|
||||||
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 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;
|
/* End implementation */
|
||||||
assign Y = Y1[Y_WIDTH-1:0];
|
assign X = AA ^ BB;
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -184,4 +184,16 @@ module NX_IOB_O(I, C, T, IO);
|
||||||
assign IO = C ? I : 1'bz;
|
assign IO = C ? I : 1'bz;
|
||||||
endmodule
|
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
|
||||||
|
|
158
techlibs/nanoxplore/nx_carry.cc
Normal file
158
techlibs/nanoxplore/nx_carry.cc
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* yosys -- Yosys Open SYnthesis Suite
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 Miodrag Milanovic <micko@yosyshq.com>
|
||||||
|
*
|
||||||
|
* 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<Cell*,SigBit> 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<SigBit,Cell*> 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<Cell*,vector<Cell*>> 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<Cell*> 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 ; i<c.second.size(); i++) {
|
||||||
|
if (j==0) {
|
||||||
|
cell = module->addCell(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<std::string> 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
|
|
@ -279,8 +279,10 @@ struct SynthNanoXplorePass : public ScriptPass
|
||||||
{
|
{
|
||||||
if (nocy)
|
if (nocy)
|
||||||
run("techmap");
|
run("techmap");
|
||||||
else
|
else {
|
||||||
run("techmap -map +/techmap.v -map +/nanoxplore/arith_map.v");
|
run("techmap -map +/techmap.v -map +/nanoxplore/arith_map.v");
|
||||||
|
run("nx_carry");
|
||||||
|
}
|
||||||
if (help_mode || iopad) {
|
if (help_mode || iopad) {
|
||||||
run("iopadmap -bits -outpad $__BEYOND_OBUF I:PAD -inpad $__BEYOND_IBUF O:PAD A:top", "(only if '-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");
|
run("techmap -map +/nanoxplore/io_map.v");
|
||||||
|
|
Loading…
Reference in a new issue