From 74d38db3b5e6a029d035f980a6b7cd7d2de51519 Mon Sep 17 00:00:00 2001 From: Adrian Parvin Ouano Date: Sun, 8 Oct 2023 01:23:00 +0800 Subject: [PATCH 01/49] alumacc: merge eq independent of sign --- passes/techmap/alumacc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index e4e70004c..bd183d815 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -451,7 +451,7 @@ struct AlumaccWorker alunode_t *n = nullptr; for (auto node : sig_alu[RTLIL::SigSig(A, B)]) - if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) { + if (node->invert_b && node->c == State::S1) { n = node; break; } From 535ecf84acff0207088ff1fcf3c0491adc5e3d4f Mon Sep 17 00:00:00 2001 From: Adrian Parvin Ouano Date: Sun, 8 Oct 2023 00:09:27 +0800 Subject: [PATCH 02/49] alumacc: merge independent of sign --- passes/techmap/alumacc.cc | 60 +++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index bd183d815..dbb117ff4 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -40,34 +40,51 @@ struct AlumaccWorker { std::vector cells; RTLIL::SigSpec a, b, c, y; - std::vector> cmp; + std::vector> cmp; bool is_signed, invert_b; RTLIL::Cell *alu_cell; - RTLIL::SigSpec cached_lt, cached_gt, cached_eq, cached_ne; + RTLIL::SigSpec cached_lt, cached_slt, cached_gt, cached_sgt, cached_eq, cached_ne; RTLIL::SigSpec cached_cf, cached_of, cached_sf; - RTLIL::SigSpec get_lt() { - if (GetSize(cached_lt) == 0) { - if (is_signed) { + RTLIL::SigSpec get_lt(bool is_signed) { + if (is_signed) { + if (GetSize(cached_slt) == 0) { get_of(); get_sf(); - cached_lt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf); + cached_slt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf); } - else + + return cached_slt; + } else { + if (GetSize(cached_lt) == 0) { cached_lt = get_cf(); + } + + return cached_lt; } - return cached_lt; } - RTLIL::SigSpec get_gt() { - if (GetSize(cached_gt) == 0) { - get_lt(); - get_eq(); - SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq); - cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); + RTLIL::SigSpec get_gt(bool is_signed) { + if (is_signed) { + if (GetSize(cached_sgt) == 0) { + get_lt(is_signed); + get_eq(); + SigSpec Or = alu_cell->module->Or(NEW_ID, cached_slt, cached_eq); + cached_sgt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); + } + + return cached_sgt; + } else { + if (GetSize(cached_gt) == 0) { + get_lt(is_signed); + get_eq(); + SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq); + cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); + } + + return cached_gt; } - return cached_gt; } RTLIL::SigSpec get_eq() { @@ -413,7 +430,7 @@ struct AlumaccWorker alunode_t *n = nullptr; for (auto node : sig_alu[RTLIL::SigSig(A, B)]) - if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) { + if (node->invert_b && node->c == State::S1) { n = node; break; } @@ -433,7 +450,7 @@ struct AlumaccWorker } n->cells.push_back(cell); - n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y)); + n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, is_signed, Y)); } for (auto cell : eq_cells) @@ -459,7 +476,7 @@ struct AlumaccWorker if (n != nullptr) { log(" creating $alu model for %s (%s): merged with %s.\n", log_id(cell), log_id(cell->type), log_id(n->cells.front())); n->cells.push_back(cell); - n->cmp.push_back(std::make_tuple(false, false, cmp_equal, !cmp_equal, Y)); + n->cmp.push_back(std::make_tuple(false, false, cmp_equal, !cmp_equal, false, Y)); } } } @@ -508,11 +525,12 @@ struct AlumaccWorker bool cmp_gt = std::get<1>(it); bool cmp_eq = std::get<2>(it); bool cmp_ne = std::get<3>(it); - RTLIL::SigSpec cmp_y = std::get<4>(it); + bool is_signed = std::get<4>(it); + RTLIL::SigSpec cmp_y = std::get<5>(it); RTLIL::SigSpec sig; - if (cmp_lt) sig.append(n->get_lt()); - if (cmp_gt) sig.append(n->get_gt()); + if (cmp_lt) sig.append(n->get_lt(is_signed)); + if (cmp_gt) sig.append(n->get_gt(is_signed)); if (cmp_eq) sig.append(n->get_eq()); if (cmp_ne) sig.append(n->get_ne()); From 062dbf2c9674ab046337279f5042445c4085ceb8 Mon Sep 17 00:00:00 2001 From: Adrian Parvin Ouano Date: Mon, 9 Oct 2023 00:36:22 +0800 Subject: [PATCH 03/49] alumacc: add signed-independent comparison tests --- tests/opt/alumacc.ys | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/opt/alumacc.ys diff --git a/tests/opt/alumacc.ys b/tests/opt/alumacc.ys new file mode 100644 index 000000000..043bdaaee --- /dev/null +++ b/tests/opt/alumacc.ys @@ -0,0 +1,33 @@ +read_verilog < rb; +assign sgt = $signed(ra) > $signed(rb); +assign lt = ra < rb; +assign slt = $signed(ra) < $signed(rb); + +assign ge = ra >= rb; +assign eq = ra == rb; +assign seq = $signed(ra) == $signed(rb); +assign ne = ra != rb; + +endmodule +EOT + +proc + +equiv_opt -assert alumacc +alumacc +select -assert-count 1 t:$alu From 4fe21dd652ec58255927ef8977553301e05ef604 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 16 Sep 2025 04:16:11 +0000 Subject: [PATCH 04/49] Reduce hashops verbiage in OptMergePass --- kernel/hashlib.h | 8 ++++++-- passes/opt/opt_merge.cc | 13 ++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 92188a220..70e9736f7 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -114,7 +114,7 @@ public: return; } [[nodiscard]] - hash_t yield() { + hash_t yield() const { return (hash_t)state; } @@ -373,7 +373,11 @@ public: commutative_hash() { buckets.fill(0); } - void eat(Hasher h) { + template + void eat(const T &obj) { + eat(hash_ops::hash(obj)); + } + void eat(const Hasher &h) { Hasher::hash_t v = h.yield(); size_t index = v & (buckets.size() - 1); buckets[index] += v; diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index fbfdb9b63..ded0e7360 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -33,6 +33,9 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +template +inline Hasher hash_pair(const T &t, const U &u) { return hash_ops>::hash(t, u); } + struct OptMergeWorker { RTLIL::Design *design; @@ -51,7 +54,7 @@ struct OptMergeWorker hashlib::commutative_hash comm; for (int i = 0; i < s_width; i++) - comm.eat(hash_ops>::hash({sig_s[i], sig_b.extract(i*width, width)})); + comm.eat(hash_pair(sig_s[i], sig_b.extract(i*width, width))); return comm.hash_into(h); } @@ -86,8 +89,8 @@ struct OptMergeWorker if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul), ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) { hashlib::commutative_hash comm; - comm.eat(hash_ops::hash(assign_map(cell->getPort(ID::A)))); - comm.eat(hash_ops::hash(assign_map(cell->getPort(ID::B)))); + comm.eat(assign_map(cell->getPort(ID::A))); + comm.eat(assign_map(cell->getPort(ID::B))); h = comm.hash_into(h); } else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { SigSpec a = assign_map(cell->getPort(ID::A)); @@ -107,7 +110,7 @@ struct OptMergeWorker for (const auto& [port, sig] : cell->connections()) { if (cell->output(port)) continue; - comm.eat(hash_ops>::hash(port, assign_map(sig))); + comm.eat(hash_pair(port, assign_map(sig))); } h = comm.hash_into(h); if (RTLIL::builtin_ff_cell_types().count(cell->type)) @@ -120,7 +123,7 @@ struct OptMergeWorker { hashlib::commutative_hash comm; for (const auto& param : cell->parameters) { - comm.eat(hash_ops>::hash(param)); + comm.eat(param); } return comm.hash_into(h); } From 0eb93c80e6048668cf2b63fad97ea572c2aa998e Mon Sep 17 00:00:00 2001 From: Ethan Sifferman Date: Wed, 24 Sep 2025 20:50:47 -0700 Subject: [PATCH 05/49] added ifndef SIMLIB_NOCONNECT --- techlibs/common/simlib.v | 3 +++ 1 file changed, 3 insertions(+) diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 096df07b9..977b8bbf9 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -3219,6 +3219,8 @@ endmodule // -------------------------------------------------------- //* group wire +`ifndef SIMLIB_NOCONNECT + module \$connect (A, B); parameter WIDTH = 0; @@ -3230,6 +3232,7 @@ tran connect[WIDTH-1:0] (A, B); endmodule +`endif // -------------------------------------------------------- //* group wire module \$input_port (Y); From b94b39cd40a7341528bfc1bc7b7f8492c45cc99d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 28 Aug 2023 16:47:59 +0200 Subject: [PATCH 06/49] Special DP16KD model is required --- techlibs/lattice/cells_bb_ecp5.v | 198 --------------------------- techlibs/lattice/cells_sim_ecp5.v | 217 ++++++++++++++++++++++++++++++ techlibs/lattice/cells_xtra.py | 7 +- 3 files changed, 218 insertions(+), 204 deletions(-) diff --git a/techlibs/lattice/cells_bb_ecp5.v b/techlibs/lattice/cells_bb_ecp5.v index 20a8134c3..1b1b9a1f4 100644 --- a/techlibs/lattice/cells_bb_ecp5.v +++ b/techlibs/lattice/cells_bb_ecp5.v @@ -17,204 +17,6 @@ module SGSR (...); input CLK; endmodule -(* blackbox *) -module DP16KD (...); - parameter CLKAMUX = "CLKA"; - parameter CLKBMUX = "CLKB"; - parameter DATA_WIDTH_A = 18; - parameter DATA_WIDTH_B = 18; - parameter REGMODE_A = "NOREG"; - parameter REGMODE_B = "NOREG"; - parameter RESETMODE = "SYNC"; - parameter ASYNC_RESET_RELEASE = "SYNC"; - parameter WRITEMODE_A = "NORMAL"; - parameter WRITEMODE_B = "NORMAL"; - parameter CSDECODE_A = "0b000"; - parameter CSDECODE_B = "0b000"; - parameter GSR = "ENABLED"; - parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INIT_DATA = "STATIC"; - input DIA17; - input DIA16; - input DIA15; - input DIA14; - input DIA13; - input DIA12; - input DIA11; - input DIA10; - input DIA9; - input DIA8; - input DIA7; - input DIA6; - input DIA5; - input DIA4; - input DIA3; - input DIA2; - input DIA1; - input DIA0; - input ADA13; - input ADA12; - input ADA11; - input ADA10; - input ADA9; - input ADA8; - input ADA7; - input ADA6; - input ADA5; - input ADA4; - input ADA3; - input ADA2; - input ADA1; - input ADA0; - input CEA; - input OCEA; - input CLKA; - input WEA; - input CSA2; - input CSA1; - input CSA0; - input RSTA; - input DIB17; - input DIB16; - input DIB15; - input DIB14; - input DIB13; - input DIB12; - input DIB11; - input DIB10; - input DIB9; - input DIB8; - input DIB7; - input DIB6; - input DIB5; - input DIB4; - input DIB3; - input DIB2; - input DIB1; - input DIB0; - input ADB13; - input ADB12; - input ADB11; - input ADB10; - input ADB9; - input ADB8; - input ADB7; - input ADB6; - input ADB5; - input ADB4; - input ADB3; - input ADB2; - input ADB1; - input ADB0; - input CEB; - input OCEB; - input CLKB; - input WEB; - input CSB2; - input CSB1; - input CSB0; - input RSTB; - output DOA17; - output DOA16; - output DOA15; - output DOA14; - output DOA13; - output DOA12; - output DOA11; - output DOA10; - output DOA9; - output DOA8; - output DOA7; - output DOA6; - output DOA5; - output DOA4; - output DOA3; - output DOA2; - output DOA1; - output DOA0; - output DOB17; - output DOB16; - output DOB15; - output DOB14; - output DOB13; - output DOB12; - output DOB11; - output DOB10; - output DOB9; - output DOB8; - output DOB7; - output DOB6; - output DOB5; - output DOB4; - output DOB3; - output DOB2; - output DOB1; - output DOB0; -endmodule - (* blackbox *) module PDPW16KD (...); parameter CLKRMUX = "CLKR"; diff --git a/techlibs/lattice/cells_sim_ecp5.v b/techlibs/lattice/cells_sim_ecp5.v index 9439e3a5b..41836e58f 100644 --- a/techlibs/lattice/cells_sim_ecp5.v +++ b/techlibs/lattice/cells_sim_ecp5.v @@ -1,6 +1,223 @@ `include "common_sim.vh" `include "ccu2c_sim.vh" +(* blackbox *) +module DP16KD( + input DIA17, DIA16, DIA15, DIA14, DIA13, DIA12, DIA11, DIA10, DIA9, DIA8, DIA7, DIA6, DIA5, DIA4, DIA3, DIA2, DIA1, DIA0, + input ADA13, ADA12, ADA11, ADA10, ADA9, ADA8, ADA7, ADA6, ADA5, ADA4, ADA3, ADA2, ADA1, ADA0, + input CEA, OCEA, CLKA, WEA, RSTA, + input CSA2, CSA1, CSA0, + output DOA17, DOA16, DOA15, DOA14, DOA13, DOA12, DOA11, DOA10, DOA9, DOA8, DOA7, DOA6, DOA5, DOA4, DOA3, DOA2, DOA1, DOA0, + + input DIB17, DIB16, DIB15, DIB14, DIB13, DIB12, DIB11, DIB10, DIB9, DIB8, DIB7, DIB6, DIB5, DIB4, DIB3, DIB2, DIB1, DIB0, + input ADB13, ADB12, ADB11, ADB10, ADB9, ADB8, ADB7, ADB6, ADB5, ADB4, ADB3, ADB2, ADB1, ADB0, + input CEB, OCEB, CLKB, WEB, RSTB, + input CSB2, CSB1, CSB0, + output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0 +); + parameter DATA_WIDTH_A = 18; + parameter DATA_WIDTH_B = 18; + + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + + parameter CSDECODE_A = "0b000"; + parameter CSDECODE_B = "0b000"; + + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + + parameter DIA17MUX = "DIA17"; + parameter DIA16MUX = "DIA16"; + parameter DIA15MUX = "DIA15"; + parameter DIA14MUX = "DIA14"; + parameter DIA13MUX = "DIA13"; + parameter DIA12MUX = "DIA12"; + parameter DIA11MUX = "DIA11"; + parameter DIA10MUX = "DIA10"; + parameter DIA9MUX = "DIA9"; + parameter DIA8MUX = "DIA8"; + parameter DIA7MUX = "DIA7"; + parameter DIA6MUX = "DIA6"; + parameter DIA5MUX = "DIA5"; + parameter DIA4MUX = "DIA4"; + parameter DIA3MUX = "DIA3"; + parameter DIA2MUX = "DIA2"; + parameter DIA1MUX = "DIA1"; + parameter DIA0MUX = "DIA0"; + parameter ADA13MUX = "ADA13"; + parameter ADA12MUX = "ADA12"; + parameter ADA11MUX = "ADA11"; + parameter ADA10MUX = "ADA10"; + parameter ADA9MUX = "ADA9"; + parameter ADA8MUX = "ADA8"; + parameter ADA7MUX = "ADA7"; + parameter ADA6MUX = "ADA6"; + parameter ADA5MUX = "ADA5"; + parameter ADA4MUX = "ADA4"; + parameter ADA3MUX = "ADA3"; + parameter ADA2MUX = "ADA2"; + parameter ADA1MUX = "ADA1"; + parameter ADA0MUX = "ADA0"; + parameter CEAMUX = "CEA"; + parameter OCEAMUX = "OCEA"; + parameter CLKAMUX = "CLKA"; + parameter WEAMUX = "WEA"; + parameter RSTAMUX = "RSTA"; + parameter CSA2MUX = "CSA2"; + parameter CSA1MUX = "CSA1"; + parameter CSA0MUX = "CSA0"; + parameter DOA17MUX = "DOA17"; + parameter DOA16MUX = "DOA16"; + parameter DOA15MUX = "DOA15"; + parameter DOA14MUX = "DOA14"; + parameter DOA13MUX = "DOA13"; + parameter DOA12MUX = "DOA12"; + parameter DOA11MUX = "DOA11"; + parameter DOA10MUX = "DOA10"; + parameter DOA9MUX = "DOA9"; + parameter DOA8MUX = "DOA8"; + parameter DOA7MUX = "DOA7"; + parameter DOA6MUX = "DOA6"; + parameter DOA5MUX = "DOA5"; + parameter DOA4MUX = "DOA4"; + parameter DOA3MUX = "DOA3"; + parameter DOA2MUX = "DOA2"; + parameter DOA1MUX = "DOA1"; + parameter DOA0MUX = "DOA0"; + parameter DIB17MUX = "DIB17"; + parameter DIB16MUX = "DIB16"; + parameter DIB15MUX = "DIB15"; + parameter DIB14MUX = "DIB14"; + parameter DIB13MUX = "DIB13"; + parameter DIB12MUX = "DIB12"; + parameter DIB11MUX = "DIB11"; + parameter DIB10MUX = "DIB10"; + parameter DIB9MUX = "DIB9"; + parameter DIB8MUX = "DIB8"; + parameter DIB7MUX = "DIB7"; + parameter DIB6MUX = "DIB6"; + parameter DIB5MUX = "DIB5"; + parameter DIB4MUX = "DIB4"; + parameter DIB3MUX = "DIB3"; + parameter DIB2MUX = "DIB2"; + parameter DIB1MUX = "DIB1"; + parameter DIB0MUX = "DIB0"; + parameter ADB13MUX = "ADB13"; + parameter ADB12MUX = "ADB12"; + parameter ADB11MUX = "ADB11"; + parameter ADB10MUX = "ADB10"; + parameter ADB9MUX = "ADB9"; + parameter ADB8MUX = "ADB8"; + parameter ADB7MUX = "ADB7"; + parameter ADB6MUX = "ADB6"; + parameter ADB5MUX = "ADB5"; + parameter ADB4MUX = "ADB4"; + parameter ADB3MUX = "ADB3"; + parameter ADB2MUX = "ADB2"; + parameter ADB1MUX = "ADB1"; + parameter ADB0MUX = "ADB0"; + parameter CEBMUX = "CEB"; + parameter OCEBMUX = "OCEB"; + parameter CLKBMUX = "CLKB"; + parameter WEBMUX = "WEB"; + parameter RSTBMUX = "RSTB"; + parameter CSB2MUX = "CSB2"; + parameter CSB1MUX = "CSB1"; + parameter CSB0MUX = "CSB0"; + parameter DOB17MUX = "DOB17"; + parameter DOB16MUX = "DOB16"; + parameter DOB15MUX = "DOB15"; + parameter DOB14MUX = "DOB14"; + parameter DOB13MUX = "DOB13"; + parameter DOB12MUX = "DOB12"; + parameter DOB11MUX = "DOB11"; + parameter DOB10MUX = "DOB10"; + parameter DOB9MUX = "DOB9"; + parameter DOB8MUX = "DOB8"; + parameter DOB7MUX = "DOB7"; + parameter DOB6MUX = "DOB6"; + parameter DOB5MUX = "DOB5"; + parameter DOB4MUX = "DOB4"; + parameter DOB3MUX = "DOB3"; + parameter DOB2MUX = "DOB2"; + parameter DOB1MUX = "DOB1"; + parameter DOB0MUX = "DOB0"; + + parameter WID = 0; + + parameter GSR = "ENABLED"; + + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_DATA = "STATIC"; +endmodule + `ifndef NO_INCLUDES `include "cells_ff.vh" diff --git a/techlibs/lattice/cells_xtra.py b/techlibs/lattice/cells_xtra.py index 5531fd2b2..3199e2263 100644 --- a/techlibs/lattice/cells_xtra.py +++ b/techlibs/lattice/cells_xtra.py @@ -121,12 +121,7 @@ devices = [ #Cell("XOR3"), #Cell("XOR4"), #Cell("XOR5"), - Cell("DP16KD", extra_params={ - # Optional clock inverters, present in prjtrellis data but - # not in Diamond bb models. - "CLKAMUX": "CLKA", - "CLKBMUX": "CLKB", - }), + #Cell("DP16KD"), Cell("PDPW16KD", extra_params={ # Optional clock inverters, present in prjtrellis data but # not in Diamond bb models. From cfe53b7395da3310301efebd43c37e1b631a7e41 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 28 Aug 2023 16:48:31 +0200 Subject: [PATCH 07/49] Move diamond tests --- techlibs/{ecp5 => lattice}/tests/.gitignore | 0 techlibs/{ecp5 => lattice}/tests/test_diamond_ffs.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename techlibs/{ecp5 => lattice}/tests/.gitignore (100%) rename techlibs/{ecp5 => lattice}/tests/test_diamond_ffs.py (100%) diff --git a/techlibs/ecp5/tests/.gitignore b/techlibs/lattice/tests/.gitignore similarity index 100% rename from techlibs/ecp5/tests/.gitignore rename to techlibs/lattice/tests/.gitignore diff --git a/techlibs/ecp5/tests/test_diamond_ffs.py b/techlibs/lattice/tests/test_diamond_ffs.py similarity index 100% rename from techlibs/ecp5/tests/test_diamond_ffs.py rename to techlibs/lattice/tests/test_diamond_ffs.py From e7ac2374996fb6f2bdb95d352f82ac6ba2d00cff Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 28 Aug 2023 16:48:48 +0200 Subject: [PATCH 08/49] Delete synth_ecp5 --- techlibs/ecp5/Makefile.inc | 15 - techlibs/ecp5/arith_map.v | 90 ---- techlibs/ecp5/brams.txt | 52 -- techlibs/ecp5/brams_map.v | 489 ------------------- techlibs/ecp5/cells_bb.v | 850 --------------------------------- techlibs/ecp5/cells_ff.vh | 40 -- techlibs/ecp5/cells_io.vh | 14 - techlibs/ecp5/cells_map.v | 191 -------- techlibs/ecp5/cells_sim.v | 681 -------------------------- techlibs/ecp5/dsp_map.v | 17 - techlibs/ecp5/latches_map.v | 11 - techlibs/ecp5/lutrams.txt | 12 - techlibs/ecp5/lutrams_map.v | 30 -- techlibs/ecp5/synth_ecp5.cc | 457 ------------------ techlibs/lattice/common_sim.vh | 2 +- 15 files changed, 1 insertion(+), 2950 deletions(-) delete mode 100644 techlibs/ecp5/Makefile.inc delete mode 100644 techlibs/ecp5/arith_map.v delete mode 100644 techlibs/ecp5/brams.txt delete mode 100644 techlibs/ecp5/brams_map.v delete mode 100644 techlibs/ecp5/cells_bb.v delete mode 100644 techlibs/ecp5/cells_ff.vh delete mode 100644 techlibs/ecp5/cells_io.vh delete mode 100644 techlibs/ecp5/cells_map.v delete mode 100644 techlibs/ecp5/cells_sim.v delete mode 100644 techlibs/ecp5/dsp_map.v delete mode 100644 techlibs/ecp5/latches_map.v delete mode 100644 techlibs/ecp5/lutrams.txt delete mode 100644 techlibs/ecp5/lutrams_map.v delete mode 100644 techlibs/ecp5/synth_ecp5.cc diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc deleted file mode 100644 index a1c9bfc52..000000000 --- a/techlibs/ecp5/Makefile.inc +++ /dev/null @@ -1,15 +0,0 @@ - -OBJS += techlibs/ecp5/synth_ecp5.o - -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams.txt)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams.txt)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v)) diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v deleted file mode 100644 index 9334785ae..000000000 --- a/techlibs/ecp5/arith_map.v +++ /dev/null @@ -1,90 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * Copyright (C) 2018 gatecat - * - * 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_ecp5_alu (A, B, CI, BI, X, Y, CO); - parameter A_SIGNED = 0; - parameter B_SIGNED = 0; - parameter A_WIDTH = 1; - parameter B_WIDTH = 1; - parameter Y_WIDTH = 1; - - (* force_downto *) - input [A_WIDTH-1:0] A; - (* force_downto *) - input [B_WIDTH-1:0] B; - (* force_downto *) - output [Y_WIDTH-1:0] X, Y; - - input CI, BI; - (* force_downto *) - output [Y_WIDTH-1:0] CO; - - wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; - - (* force_downto *) - wire [Y_WIDTH-1:0] A_buf, B_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)); - - function integer round_up2; - input integer N; - begin - round_up2 = ((N + 1) / 2) * 2; - end - endfunction - - localparam Y_WIDTH2 = round_up2(Y_WIDTH); - - (* force_downto *) - wire [Y_WIDTH2-1:0] AA = A_buf; - (* force_downto *) - wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf; - (* force_downto *) - wire [Y_WIDTH2-1:0] BX = B_buf; - (* force_downto *) - wire [Y_WIDTH2-1:0] C = {CO, CI}; - (* force_downto *) - wire [Y_WIDTH2-1:0] FCO, Y1; - - genvar i; - generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice - CCU2C #( - .INIT0(16'b1001011010101010), - .INIT1(16'b1001011010101010), - .INJECT1_0("NO"), - .INJECT1_1("NO") - ) ccu2c_i ( - .CIN(C[i]), - .A0(AA[i]), .B0(BX[i]), .C0(BI), .D0(1'b1), - .A1(AA[i+1]), .B1(BX[i+1]), .C1(BI), .D1(1'b1), - .S0(Y[i]), .S1(Y1[i]), - .COUT(FCO[i]) - ); - - assign CO[i] = (AA[i] && BB[i]) || (C[i] && (AA[i] || BB[i])); - if (i+1 < Y_WIDTH) begin - assign CO[i+1] = FCO[i]; - assign Y[i+1] = Y1[i]; - end - end endgenerate - - assign X = AA ^ BB; -endmodule diff --git a/techlibs/ecp5/brams.txt b/techlibs/ecp5/brams.txt deleted file mode 100644 index db28a40d7..000000000 --- a/techlibs/ecp5/brams.txt +++ /dev/null @@ -1,52 +0,0 @@ -ram block $__ECP5_DP16KD_ { - abits 14; - widths 1 2 4 9 18 per_port; - byte 9; - cost 128; - init no_undef; - port srsw "A" "B" { - clock anyedge; - clken; - wrbe_separate; - portoption "WRITEMODE" "NORMAL" { - rdwr no_change; - } - portoption "WRITEMODE" "WRITETHROUGH" { - rdwr new; - } - portoption "WRITEMODE" "READBEFOREWRITE" { - rdwr old; - } - option "RESETMODE" "SYNC" { - rdsrst zero ungated block_wr; - } - option "RESETMODE" "ASYNC" { - rdarst zero; - } - rdinit zero; - } -} - -ram block $__ECP5_PDPW16KD_ { - abits 14; - widths 1 2 4 9 18 36 per_port; - byte 9; - cost 128; - init no_undef; - port sr "R" { - clock anyedge; - clken; - option "RESETMODE" "SYNC" { - rdsrst zero ungated; - } - option "RESETMODE" "ASYNC" { - rdarst zero; - } - rdinit zero; - } - port sw "W" { - width 36; - clock anyedge; - clken; - } -} diff --git a/techlibs/ecp5/brams_map.v b/techlibs/ecp5/brams_map.v deleted file mode 100644 index 22e6e068e..000000000 --- a/techlibs/ecp5/brams_map.v +++ /dev/null @@ -1,489 +0,0 @@ -module $__ECP5_DP16KD_ (...); - -parameter INIT = 0; -parameter OPTION_RESETMODE = "SYNC"; - -parameter PORT_A_WIDTH = 18; -parameter PORT_A_WR_BE_WIDTH = 2; -parameter PORT_A_CLK_POL = 1; -parameter PORT_A_OPTION_WRITEMODE = "NORMAL"; - -input PORT_A_CLK; -input PORT_A_CLK_EN; -input PORT_A_WR_EN; -input PORT_A_RD_SRST; -input PORT_A_RD_ARST; -input [13:0] PORT_A_ADDR; -input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE; -input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; -output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; - -parameter PORT_B_WIDTH = 18; -parameter PORT_B_WR_BE_WIDTH = 2; -parameter PORT_B_CLK_POL = 1; -parameter PORT_B_OPTION_WRITEMODE = "NORMAL"; - -input PORT_B_CLK; -input PORT_B_CLK_EN; -input PORT_B_WR_EN; -input PORT_B_RD_SRST; -input PORT_B_RD_ARST; -input [13:0] PORT_B_ADDR; -input [PORT_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE; -input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA; -output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA; - -function [319:0] init_slice; - input integer idx; - integer i, j; - init_slice = 0; - for (i = 0; i < 16; i = i + 1) begin - init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18]; - end -endfunction - -wire [17:0] DOA; -wire [17:0] DOB; -wire [17:0] DIA = PORT_A_WR_DATA; -wire [17:0] DIB = PORT_B_WR_DATA; - -assign PORT_A_RD_DATA = DOA; -assign PORT_B_RD_DATA = DOB; - -DP16KD #( - .INITVAL_00(init_slice('h00)), - .INITVAL_01(init_slice('h01)), - .INITVAL_02(init_slice('h02)), - .INITVAL_03(init_slice('h03)), - .INITVAL_04(init_slice('h04)), - .INITVAL_05(init_slice('h05)), - .INITVAL_06(init_slice('h06)), - .INITVAL_07(init_slice('h07)), - .INITVAL_08(init_slice('h08)), - .INITVAL_09(init_slice('h09)), - .INITVAL_0A(init_slice('h0a)), - .INITVAL_0B(init_slice('h0b)), - .INITVAL_0C(init_slice('h0c)), - .INITVAL_0D(init_slice('h0d)), - .INITVAL_0E(init_slice('h0e)), - .INITVAL_0F(init_slice('h0f)), - .INITVAL_10(init_slice('h10)), - .INITVAL_11(init_slice('h11)), - .INITVAL_12(init_slice('h12)), - .INITVAL_13(init_slice('h13)), - .INITVAL_14(init_slice('h14)), - .INITVAL_15(init_slice('h15)), - .INITVAL_16(init_slice('h16)), - .INITVAL_17(init_slice('h17)), - .INITVAL_18(init_slice('h18)), - .INITVAL_19(init_slice('h19)), - .INITVAL_1A(init_slice('h1a)), - .INITVAL_1B(init_slice('h1b)), - .INITVAL_1C(init_slice('h1c)), - .INITVAL_1D(init_slice('h1d)), - .INITVAL_1E(init_slice('h1e)), - .INITVAL_1F(init_slice('h1f)), - .INITVAL_20(init_slice('h20)), - .INITVAL_21(init_slice('h21)), - .INITVAL_22(init_slice('h22)), - .INITVAL_23(init_slice('h23)), - .INITVAL_24(init_slice('h24)), - .INITVAL_25(init_slice('h25)), - .INITVAL_26(init_slice('h26)), - .INITVAL_27(init_slice('h27)), - .INITVAL_28(init_slice('h28)), - .INITVAL_29(init_slice('h29)), - .INITVAL_2A(init_slice('h2a)), - .INITVAL_2B(init_slice('h2b)), - .INITVAL_2C(init_slice('h2c)), - .INITVAL_2D(init_slice('h2d)), - .INITVAL_2E(init_slice('h2e)), - .INITVAL_2F(init_slice('h2f)), - .INITVAL_30(init_slice('h30)), - .INITVAL_31(init_slice('h31)), - .INITVAL_32(init_slice('h32)), - .INITVAL_33(init_slice('h33)), - .INITVAL_34(init_slice('h34)), - .INITVAL_35(init_slice('h35)), - .INITVAL_36(init_slice('h36)), - .INITVAL_37(init_slice('h37)), - .INITVAL_38(init_slice('h38)), - .INITVAL_39(init_slice('h39)), - .INITVAL_3A(init_slice('h3a)), - .INITVAL_3B(init_slice('h3b)), - .INITVAL_3C(init_slice('h3c)), - .INITVAL_3D(init_slice('h3d)), - .INITVAL_3E(init_slice('h3e)), - .INITVAL_3F(init_slice('h3f)), - .DATA_WIDTH_A(PORT_A_WIDTH), - .DATA_WIDTH_B(PORT_B_WIDTH), - .REGMODE_A("NOREG"), - .REGMODE_B("NOREG"), - .RESETMODE(OPTION_RESETMODE), - .ASYNC_RESET_RELEASE(OPTION_RESETMODE), - .CSDECODE_A("0b000"), - .CSDECODE_B("0b000"), - .CLKAMUX(PORT_A_CLK_POL ? "CLKA" : "INV"), - .CLKBMUX(PORT_B_CLK_POL ? "CLKB" : "INV"), - .WRITEMODE_A(PORT_A_OPTION_WRITEMODE), - .WRITEMODE_B(PORT_B_OPTION_WRITEMODE), - .GSR("AUTO") -) _TECHMAP_REPLACE_ ( - .CLKA(PORT_A_CLK), - .WEA(PORT_A_WIDTH == 18 ? PORT_A_WR_EN : (PORT_A_WR_EN | PORT_A_WR_BE[0])), - .CEA(PORT_A_CLK_EN), - .OCEA(1'b1), - .RSTA(OPTION_RESETMODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST), - .CSA0(1'b0), - .CSA1(1'b0), - .CSA2(1'b0), - .ADA0(PORT_A_WIDTH == 18 ? PORT_A_WR_BE[0] : PORT_A_ADDR[0]), - .ADA1(PORT_A_WIDTH == 18 ? PORT_A_WR_BE[1] : PORT_A_ADDR[1]), - .ADA2(PORT_A_ADDR[2]), - .ADA3(PORT_A_ADDR[3]), - .ADA4(PORT_A_ADDR[4]), - .ADA5(PORT_A_ADDR[5]), - .ADA6(PORT_A_ADDR[6]), - .ADA7(PORT_A_ADDR[7]), - .ADA8(PORT_A_ADDR[8]), - .ADA9(PORT_A_ADDR[9]), - .ADA10(PORT_A_ADDR[10]), - .ADA11(PORT_A_ADDR[11]), - .ADA12(PORT_A_ADDR[12]), - .ADA13(PORT_A_ADDR[13]), - .DIA0(DIA[0]), - .DIA1(DIA[1]), - .DIA2(DIA[2]), - .DIA3(DIA[3]), - .DIA4(DIA[4]), - .DIA5(DIA[5]), - .DIA6(DIA[6]), - .DIA7(DIA[7]), - .DIA8(DIA[8]), - .DIA9(DIA[9]), - .DIA10(DIA[10]), - .DIA11(DIA[11]), - .DIA12(DIA[12]), - .DIA13(DIA[13]), - .DIA14(DIA[14]), - .DIA15(DIA[15]), - .DIA16(DIA[16]), - .DIA17(DIA[17]), - .DOA0(DOA[0]), - .DOA1(DOA[1]), - .DOA2(DOA[2]), - .DOA3(DOA[3]), - .DOA4(DOA[4]), - .DOA5(DOA[5]), - .DOA6(DOA[6]), - .DOA7(DOA[7]), - .DOA8(DOA[8]), - .DOA9(DOA[9]), - .DOA10(DOA[10]), - .DOA11(DOA[11]), - .DOA12(DOA[12]), - .DOA13(DOA[13]), - .DOA14(DOA[14]), - .DOA15(DOA[15]), - .DOA16(DOA[16]), - .DOA17(DOA[17]), - - .CLKB(PORT_B_CLK), - .WEB(PORT_B_WIDTH == 18 ? PORT_B_WR_EN : (PORT_B_WR_EN | PORT_B_WR_BE[0])), - .CEB(PORT_B_CLK_EN), - .OCEB(1'b1), - .RSTB(OPTION_RESETMODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST), - .CSB0(1'b0), - .CSB1(1'b0), - .CSB2(1'b0), - .ADB0(PORT_B_WIDTH == 18 ? PORT_B_WR_BE[0] : PORT_B_ADDR[0]), - .ADB1(PORT_B_WIDTH == 18 ? PORT_B_WR_BE[1] : PORT_B_ADDR[1]), - .ADB2(PORT_B_ADDR[2]), - .ADB3(PORT_B_ADDR[3]), - .ADB4(PORT_B_ADDR[4]), - .ADB5(PORT_B_ADDR[5]), - .ADB6(PORT_B_ADDR[6]), - .ADB7(PORT_B_ADDR[7]), - .ADB8(PORT_B_ADDR[8]), - .ADB9(PORT_B_ADDR[9]), - .ADB10(PORT_B_ADDR[10]), - .ADB11(PORT_B_ADDR[11]), - .ADB12(PORT_B_ADDR[12]), - .ADB13(PORT_B_ADDR[13]), - .DIB0(DIB[0]), - .DIB1(DIB[1]), - .DIB2(DIB[2]), - .DIB3(DIB[3]), - .DIB4(DIB[4]), - .DIB5(DIB[5]), - .DIB6(DIB[6]), - .DIB7(DIB[7]), - .DIB8(DIB[8]), - .DIB9(DIB[9]), - .DIB10(DIB[10]), - .DIB11(DIB[11]), - .DIB12(DIB[12]), - .DIB13(DIB[13]), - .DIB14(DIB[14]), - .DIB15(DIB[15]), - .DIB16(DIB[16]), - .DIB17(DIB[17]), - .DOB0(DOB[0]), - .DOB1(DOB[1]), - .DOB2(DOB[2]), - .DOB3(DOB[3]), - .DOB4(DOB[4]), - .DOB5(DOB[5]), - .DOB6(DOB[6]), - .DOB7(DOB[7]), - .DOB8(DOB[8]), - .DOB9(DOB[9]), - .DOB10(DOB[10]), - .DOB11(DOB[11]), - .DOB12(DOB[12]), - .DOB13(DOB[13]), - .DOB14(DOB[14]), - .DOB15(DOB[15]), - .DOB16(DOB[16]), - .DOB17(DOB[17]), -); - -endmodule - - -module $__ECP5_PDPW16KD_ (...); - -parameter INIT = 0; -parameter OPTION_RESETMODE = "SYNC"; - -parameter PORT_R_WIDTH = 36; -parameter PORT_R_CLK_POL = 1; - -input PORT_R_CLK; -input PORT_R_CLK_EN; -input PORT_R_RD_SRST; -input PORT_R_RD_ARST; -input [13:0] PORT_R_ADDR; -output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA; - -parameter PORT_W_WIDTH = 36; -parameter PORT_W_WR_EN_WIDTH = 4; -parameter PORT_W_CLK_POL = 1; - -input PORT_W_CLK; -input PORT_W_CLK_EN; -input [13:0] PORT_W_ADDR; -input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN; -input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; - -function [319:0] init_slice; - input integer idx; - integer i, j; - init_slice = 0; - for (i = 0; i < 16; i = i + 1) begin - init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18]; - end -endfunction - -wire [35:0] DI = PORT_W_WR_DATA; -wire [35:0] DO; - -assign PORT_R_RD_DATA = PORT_R_WIDTH == 36 ? DO : DO[35:18]; - -DP16KD #( - .INITVAL_00(init_slice('h00)), - .INITVAL_01(init_slice('h01)), - .INITVAL_02(init_slice('h02)), - .INITVAL_03(init_slice('h03)), - .INITVAL_04(init_slice('h04)), - .INITVAL_05(init_slice('h05)), - .INITVAL_06(init_slice('h06)), - .INITVAL_07(init_slice('h07)), - .INITVAL_08(init_slice('h08)), - .INITVAL_09(init_slice('h09)), - .INITVAL_0A(init_slice('h0a)), - .INITVAL_0B(init_slice('h0b)), - .INITVAL_0C(init_slice('h0c)), - .INITVAL_0D(init_slice('h0d)), - .INITVAL_0E(init_slice('h0e)), - .INITVAL_0F(init_slice('h0f)), - .INITVAL_10(init_slice('h10)), - .INITVAL_11(init_slice('h11)), - .INITVAL_12(init_slice('h12)), - .INITVAL_13(init_slice('h13)), - .INITVAL_14(init_slice('h14)), - .INITVAL_15(init_slice('h15)), - .INITVAL_16(init_slice('h16)), - .INITVAL_17(init_slice('h17)), - .INITVAL_18(init_slice('h18)), - .INITVAL_19(init_slice('h19)), - .INITVAL_1A(init_slice('h1a)), - .INITVAL_1B(init_slice('h1b)), - .INITVAL_1C(init_slice('h1c)), - .INITVAL_1D(init_slice('h1d)), - .INITVAL_1E(init_slice('h1e)), - .INITVAL_1F(init_slice('h1f)), - .INITVAL_20(init_slice('h20)), - .INITVAL_21(init_slice('h21)), - .INITVAL_22(init_slice('h22)), - .INITVAL_23(init_slice('h23)), - .INITVAL_24(init_slice('h24)), - .INITVAL_25(init_slice('h25)), - .INITVAL_26(init_slice('h26)), - .INITVAL_27(init_slice('h27)), - .INITVAL_28(init_slice('h28)), - .INITVAL_29(init_slice('h29)), - .INITVAL_2A(init_slice('h2a)), - .INITVAL_2B(init_slice('h2b)), - .INITVAL_2C(init_slice('h2c)), - .INITVAL_2D(init_slice('h2d)), - .INITVAL_2E(init_slice('h2e)), - .INITVAL_2F(init_slice('h2f)), - .INITVAL_30(init_slice('h30)), - .INITVAL_31(init_slice('h31)), - .INITVAL_32(init_slice('h32)), - .INITVAL_33(init_slice('h33)), - .INITVAL_34(init_slice('h34)), - .INITVAL_35(init_slice('h35)), - .INITVAL_36(init_slice('h36)), - .INITVAL_37(init_slice('h37)), - .INITVAL_38(init_slice('h38)), - .INITVAL_39(init_slice('h39)), - .INITVAL_3A(init_slice('h3a)), - .INITVAL_3B(init_slice('h3b)), - .INITVAL_3C(init_slice('h3c)), - .INITVAL_3D(init_slice('h3d)), - .INITVAL_3E(init_slice('h3e)), - .INITVAL_3F(init_slice('h3f)), - .DATA_WIDTH_A(PORT_W_WIDTH), - .DATA_WIDTH_B(PORT_R_WIDTH), - .REGMODE_A("NOREG"), - .REGMODE_B("NOREG"), - .RESETMODE(OPTION_RESETMODE), - .ASYNC_RESET_RELEASE(OPTION_RESETMODE), - .CSDECODE_A("0b000"), - .CSDECODE_B("0b000"), - .CLKAMUX(PORT_W_CLK_POL ? "CLKA" : "INV"), - .CLKBMUX(PORT_R_CLK_POL ? "CLKB" : "INV"), - .GSR("AUTO") -) _TECHMAP_REPLACE_ ( - .CLKA(PORT_W_CLK), - .WEA(PORT_W_WIDTH >= 18 ? 1'b1 : PORT_W_WR_EN[0]), - .CEA(PORT_W_CLK_EN), - .OCEA(1'b0), - .RSTA(1'b0), - .CSA0(1'b0), - .CSA1(1'b0), - .CSA2(1'b0), - .ADA0(PORT_W_WIDTH >= 18 ? PORT_W_WR_EN[0] : PORT_W_ADDR[0]), - .ADA1(PORT_W_WIDTH >= 18 ? PORT_W_WR_EN[1] : PORT_W_ADDR[1]), - .ADA2(PORT_W_WIDTH >= 36 ? PORT_W_WR_EN[2] : PORT_W_ADDR[2]), - .ADA3(PORT_W_WIDTH >= 36 ? PORT_W_WR_EN[3] : PORT_W_ADDR[3]), - .ADA4(PORT_W_ADDR[4]), - .ADA5(PORT_W_ADDR[5]), - .ADA6(PORT_W_ADDR[6]), - .ADA7(PORT_W_ADDR[7]), - .ADA8(PORT_W_ADDR[8]), - .ADA9(PORT_W_ADDR[9]), - .ADA10(PORT_W_ADDR[10]), - .ADA11(PORT_W_ADDR[11]), - .ADA12(PORT_W_ADDR[12]), - .ADA13(PORT_W_ADDR[13]), - .DIA0(DI[0]), - .DIA1(DI[1]), - .DIA2(DI[2]), - .DIA3(DI[3]), - .DIA4(DI[4]), - .DIA5(DI[5]), - .DIA6(DI[6]), - .DIA7(DI[7]), - .DIA8(DI[8]), - .DIA9(DI[9]), - .DIA10(DI[10]), - .DIA11(DI[11]), - .DIA12(DI[12]), - .DIA13(DI[13]), - .DIA14(DI[14]), - .DIA15(DI[15]), - .DIA16(DI[16]), - .DIA17(DI[17]), - .DIB0(DI[18]), - .DIB1(DI[19]), - .DIB2(DI[20]), - .DIB3(DI[21]), - .DIB4(DI[22]), - .DIB5(DI[23]), - .DIB6(DI[24]), - .DIB7(DI[25]), - .DIB8(DI[26]), - .DIB9(DI[27]), - .DIB10(DI[28]), - .DIB11(DI[29]), - .DIB12(DI[30]), - .DIB13(DI[31]), - .DIB14(DI[32]), - .DIB15(DI[33]), - .DIB16(DI[34]), - .DIB17(DI[35]), - - .CLKB(PORT_R_CLK), - .WEB(1'b0), - .CEB(PORT_R_CLK_EN), - .OCEB(1'b1), - .RSTB(OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST), - .CSB0(1'b0), - .CSB1(1'b0), - .CSB2(1'b0), - .ADB0(PORT_R_ADDR[0]), - .ADB1(PORT_R_ADDR[1]), - .ADB2(PORT_R_ADDR[2]), - .ADB3(PORT_R_ADDR[3]), - .ADB4(PORT_R_ADDR[4]), - .ADB5(PORT_R_ADDR[5]), - .ADB6(PORT_R_ADDR[6]), - .ADB7(PORT_R_ADDR[7]), - .ADB8(PORT_R_ADDR[8]), - .ADB9(PORT_R_ADDR[9]), - .ADB10(PORT_R_ADDR[10]), - .ADB11(PORT_R_ADDR[11]), - .ADB12(PORT_R_ADDR[12]), - .ADB13(PORT_R_ADDR[13]), - .DOA0(DO[0]), - .DOA1(DO[1]), - .DOA2(DO[2]), - .DOA3(DO[3]), - .DOA4(DO[4]), - .DOA5(DO[5]), - .DOA6(DO[6]), - .DOA7(DO[7]), - .DOA8(DO[8]), - .DOA9(DO[9]), - .DOA10(DO[10]), - .DOA11(DO[11]), - .DOA12(DO[12]), - .DOA13(DO[13]), - .DOA14(DO[14]), - .DOA15(DO[15]), - .DOA16(DO[16]), - .DOA17(DO[17]), - .DOB0(DO[18]), - .DOB1(DO[19]), - .DOB2(DO[20]), - .DOB3(DO[21]), - .DOB4(DO[22]), - .DOB5(DO[23]), - .DOB6(DO[24]), - .DOB7(DO[25]), - .DOB8(DO[26]), - .DOB9(DO[27]), - .DOB10(DO[28]), - .DOB11(DO[29]), - .DOB12(DO[30]), - .DOB13(DO[31]), - .DOB14(DO[32]), - .DOB15(DO[33]), - .DOB16(DO[34]), - .DOB17(DO[35]), -); - -endmodule diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v deleted file mode 100644 index 316671f3c..000000000 --- a/techlibs/ecp5/cells_bb.v +++ /dev/null @@ -1,850 +0,0 @@ -// ECP5 Blackbox cells -// FIXME: Create sim models - -(* blackbox *) -module MULT18X18D( - input A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, - input B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, B17, - input C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, - input SIGNEDA, SIGNEDB, SOURCEA, SOURCEB, - input CLK0, CLK1, CLK2, CLK3, - input CE0, CE1, CE2, CE3, - input RST0, RST1, RST2, RST3, - input SRIA0, SRIA1, SRIA2, SRIA3, SRIA4, SRIA5, SRIA6, SRIA7, SRIA8, SRIA9, SRIA10, SRIA11, SRIA12, SRIA13, SRIA14, SRIA15, SRIA16, SRIA17, - input SRIB0, SRIB1, SRIB2, SRIB3, SRIB4, SRIB5, SRIB6, SRIB7, SRIB8, SRIB9, SRIB10, SRIB11, SRIB12, SRIB13, SRIB14, SRIB15, SRIB16, SRIB17, - output SROA0, SROA1, SROA2, SROA3, SROA4, SROA5, SROA6, SROA7, SROA8, SROA9, SROA10, SROA11, SROA12, SROA13, SROA14, SROA15, SROA16, SROA17, - output SROB0, SROB1, SROB2, SROB3, SROB4, SROB5, SROB6, SROB7, SROB8, SROB9, SROB10, SROB11, SROB12, SROB13, SROB14, SROB15, SROB16, SROB17, - output ROA0, ROA1, ROA2, ROA3, ROA4, ROA5, ROA6, ROA7, ROA8, ROA9, ROA10, ROA11, ROA12, ROA13, ROA14, ROA15, ROA16, ROA17, - output ROB0, ROB1, ROB2, ROB3, ROB4, ROB5, ROB6, ROB7, ROB8, ROB9, ROB10, ROB11, ROB12, ROB13, ROB14, ROB15, ROB16, ROB17, - output ROC0, ROC1, ROC2, ROC3, ROC4, ROC5, ROC6, ROC7, ROC8, ROC9, ROC10, ROC11, ROC12, ROC13, ROC14, ROC15, ROC16, ROC17, - output P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, - output SIGNEDP -); - parameter REG_INPUTA_CLK = "NONE"; - parameter REG_INPUTA_CE = "CE0"; - parameter REG_INPUTA_RST = "RST0"; - parameter REG_INPUTB_CLK = "NONE"; - parameter REG_INPUTB_CE = "CE0"; - parameter REG_INPUTB_RST = "RST0"; - parameter REG_INPUTC_CLK = "NONE"; - parameter REG_INPUTC_CE = "CE0"; - parameter REG_INPUTC_RST = "RST0"; - parameter REG_PIPELINE_CLK = "NONE"; - parameter REG_PIPELINE_CE = "CE0"; - parameter REG_PIPELINE_RST = "RST0"; - parameter REG_OUTPUT_CLK = "NONE"; - parameter REG_OUTPUT_CE = "CE0"; - parameter REG_OUTPUT_RST = "RST0"; - parameter [127:0] CLK0_DIV = "ENABLED"; - parameter [127:0] CLK1_DIV = "ENABLED"; - parameter [127:0] CLK2_DIV = "ENABLED"; - parameter [127:0] CLK3_DIV = "ENABLED"; - parameter HIGHSPEED_CLK = "NONE"; - parameter [127:0] GSR = "ENABLED"; - parameter CAS_MATCH_REG = "FALSE"; - parameter [127:0] SOURCEB_MODE = "B_SHIFT"; - parameter [127:0] MULT_BYPASS = "DISABLED"; - parameter [127:0] RESETMODE = "SYNC"; -endmodule - -(* blackbox *) -module ALU54B( - input CLK0, CLK1, CLK2, CLK3, - input CE0, CE1, CE2, CE3, - input RST0, RST1, RST2, RST3, - input SIGNEDIA, SIGNEDIB, SIGNEDCIN, - input A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, - input B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B20, B21, B22, B23, B24, B25, B26, B27, B28, B29, B30, B31, B32, B33, B34, B35, - input C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26, C27, C28, C29, C30, C31, C32, C33, C34, C35, C36, C37, C38, C39, C40, C41, C42, C43, C44, C45, C46, C47, C48, C49, C50, C51, C52, C53, - input CFB0, CFB1, CFB2, CFB3, CFB4, CFB5, CFB6, CFB7, CFB8, CFB9, CFB10, CFB11, CFB12, CFB13, CFB14, CFB15, CFB16, CFB17, CFB18, CFB19, CFB20, CFB21, CFB22, CFB23, CFB24, CFB25, CFB26, CFB27, CFB28, CFB29, CFB30, CFB31, CFB32, CFB33, CFB34, CFB35, CFB36, CFB37, CFB38, CFB39, CFB40, CFB41, CFB42, CFB43, CFB44, CFB45, CFB46, CFB47, CFB48, CFB49, CFB50, CFB51, CFB52, CFB53, - input MA0, MA1, MA2, MA3, MA4, MA5, MA6, MA7, MA8, MA9, MA10, MA11, MA12, MA13, MA14, MA15, MA16, MA17, MA18, MA19, MA20, MA21, MA22, MA23, MA24, MA25, MA26, MA27, MA28, MA29, MA30, MA31, MA32, MA33, MA34, MA35, - input MB0, MB1, MB2, MB3, MB4, MB5, MB6, MB7, MB8, MB9, MB10, MB11, MB12, MB13, MB14, MB15, MB16, MB17, MB18, MB19, MB20, MB21, MB22, MB23, MB24, MB25, MB26, MB27, MB28, MB29, MB30, MB31, MB32, MB33, MB34, MB35, - input CIN0, CIN1, CIN2, CIN3, CIN4, CIN5, CIN6, CIN7, CIN8, CIN9, CIN10, CIN11, CIN12, CIN13, CIN14, CIN15, CIN16, CIN17, CIN18, CIN19, CIN20, CIN21, CIN22, CIN23, CIN24, CIN25, CIN26, CIN27, CIN28, CIN29, CIN30, CIN31, CIN32, CIN33, CIN34, CIN35, CIN36, CIN37, CIN38, CIN39, CIN40, CIN41, CIN42, CIN43, CIN44, CIN45, CIN46, CIN47, CIN48, CIN49, CIN50, CIN51, CIN52, CIN53, - input OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7, OP8, OP9, OP10, - output R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, R32, R33, R34, R35, R36, R37, R38, R39, R40, R41, R42, R43, R44, R45, R46, R47, R48, R49, R50, R51, R52, R53, - output CO0, CO1, CO2, CO3, CO4, CO5, CO6, CO7, CO8, CO9, CO10, CO11, CO12, CO13, CO14, CO15, CO16, CO17, CO18, CO19, CO20, CO21, CO22, CO23, CO24, CO25, CO26, CO27, CO28, CO29, CO30, CO31, CO32, CO33, CO34, CO35, CO36, CO37, CO38, CO39, CO40, CO41, CO42, CO43, CO44, CO45, CO46, CO47, CO48, CO49, CO50, CO51, CO52, CO53, - output EQZ, EQZM, EQOM, EQPAT, EQPATB, - output OVER, UNDER, OVERUNDER, - output SIGNEDR -); - parameter REG_INPUTC0_CLK = "NONE"; - parameter REG_INPUTC0_CE = "CE0"; - parameter REG_INPUTC0_RST = "RST0"; - parameter REG_INPUTC1_CLK = "NONE"; - parameter REG_INPUTC1_CE = "CE0"; - parameter REG_INPUTC1_RST = "RST0"; - parameter REG_OPCODEOP0_0_CLK = "NONE"; - parameter REG_OPCODEOP0_0_CE = "CE0"; - parameter REG_OPCODEOP0_0_RST = "RST0"; - parameter REG_OPCODEOP1_0_CLK = "NONE"; - parameter REG_OPCODEOP0_1_CLK = "NONE"; - parameter REG_OPCODEOP0_1_CE = "CE0"; - parameter REG_OPCODEOP0_1_RST = "RST0"; - parameter REG_OPCODEOP1_1_CLK = "NONE"; - parameter REG_OPCODEIN_0_CLK = "NONE"; - parameter REG_OPCODEIN_0_CE = "CE0"; - parameter REG_OPCODEIN_0_RST = "RST0"; - parameter REG_OPCODEIN_1_CLK = "NONE"; - parameter REG_OPCODEIN_1_CE = "CE0"; - parameter REG_OPCODEIN_1_RST = "RST0"; - parameter REG_OUTPUT0_CLK = "NONE"; - parameter REG_OUTPUT0_CE = "CE0"; - parameter REG_OUTPUT0_RST = "RST0"; - parameter REG_OUTPUT1_CLK = "NONE"; - parameter REG_OUTPUT1_CE = "CE0"; - parameter REG_OUTPUT1_RST = "RST0"; - parameter REG_FLAG_CLK = "NONE"; - parameter REG_FLAG_CE = "CE0"; - parameter REG_FLAG_RST = "RST0"; - parameter REG_INPUTCFB_CLK = "NONE"; - parameter REG_INPUTCFB_CE = "CE0"; - parameter REG_INPUTCFB_RST = "RST0"; - parameter [127:0] MCPAT_SOURCE = "STATIC"; - parameter [127:0] MASKPAT_SOURCE = "STATIC"; - parameter MASK01 = "0x00000000000000"; - parameter [127:0] CLK0_DIV = "ENABLED"; - parameter [127:0] CLK1_DIV = "ENABLED"; - parameter [127:0] CLK2_DIV = "ENABLED"; - parameter [127:0] CLK3_DIV = "ENABLED"; - parameter MCPAT = "0x00000000000000"; - parameter MASKPAT = "0x00000000000000"; - parameter RNDPAT = "0x00000000000000"; - parameter [127:0] GSR = "ENABLED"; - parameter [127:0] RESETMODE = "SYNC"; - parameter MULT9_MODE = "DISABLED"; - parameter FORCE_ZERO_BARREL_SHIFT = "DISABLED"; - parameter LEGACY = "DISABLED"; -endmodule - -(* blackbox *) -module EHXPLLL ( - input CLKI, CLKFB, - input PHASESEL1, PHASESEL0, PHASEDIR, PHASESTEP, PHASELOADREG, - input STDBY, PLLWAKESYNC, - input RST, ENCLKOP, ENCLKOS, ENCLKOS2, ENCLKOS3, - output CLKOP, CLKOS, CLKOS2, CLKOS3, - output LOCK, INTLOCK, - output REFCLK, CLKINTFB -); - parameter CLKI_DIV = 1; - parameter CLKFB_DIV = 1; - parameter CLKOP_DIV = 8; - parameter CLKOS_DIV = 8; - parameter CLKOS2_DIV = 8; - parameter CLKOS3_DIV = 8; - parameter CLKOP_ENABLE = "ENABLED"; - parameter CLKOS_ENABLE = "DISABLED"; - parameter CLKOS2_ENABLE = "DISABLED"; - parameter CLKOS3_ENABLE = "DISABLED"; - parameter CLKOP_CPHASE = 0; - parameter CLKOS_CPHASE = 0; - parameter CLKOS2_CPHASE = 0; - parameter CLKOS3_CPHASE = 0; - parameter CLKOP_FPHASE = 0; - parameter CLKOS_FPHASE = 0; - parameter CLKOS2_FPHASE = 0; - parameter CLKOS3_FPHASE = 0; - parameter FEEDBK_PATH = "CLKOP"; - parameter CLKOP_TRIM_POL = "RISING"; - parameter CLKOP_TRIM_DELAY = 0; - parameter CLKOS_TRIM_POL = "RISING"; - parameter CLKOS_TRIM_DELAY = 0; - parameter OUTDIVIDER_MUXA = "DIVA"; - parameter OUTDIVIDER_MUXB = "DIVB"; - parameter OUTDIVIDER_MUXC = "DIVC"; - parameter OUTDIVIDER_MUXD = "DIVD"; - parameter PLL_LOCK_MODE = 0; - parameter PLL_LOCK_DELAY = 200; - parameter STDBY_ENABLE = "DISABLED"; - parameter REFIN_RESET = "DISABLED"; - parameter SYNC_ENABLE = "DISABLED"; - parameter INT_LOCK_STICKY = "ENABLED"; - parameter DPHASE_SOURCE = "DISABLED"; - parameter PLLRST_ENA = "DISABLED"; - parameter INTFB_WAKE = "DISABLED"; -endmodule - -(* blackbox *) -module DTR( - input STARTPULSE, - output DTROUT7, DTROUT6, DTROUT5, DTROUT4, DTROUT3, DTROUT2, DTROUT1, DTROUT0 -); -endmodule - -(* blackbox *) -module OSCG( - output OSC -); -parameter DIV = 128; -endmodule - -(* blackbox *) (* keep *) -module USRMCLK( - input USRMCLKI, USRMCLKTS, - output USRMCLKO -); -endmodule - -(* blackbox *) (* keep *) -module JTAGG( - (* iopad_external_pin *) - input TCK, - (* iopad_external_pin *) - input TMS, - (* iopad_external_pin *) - input TDI, - input JTDO2, JTDO1, - (* iopad_external_pin *) - output TDO, - output JTDI, JTCK, JRTI2, JRTI1, - output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1 -); -parameter ER1 = "ENABLED"; -parameter ER2 = "ENABLED"; -endmodule - -(* blackbox *) -module DELAYF( - input A, LOADN, MOVE, DIRECTION, - output Z, CFLAG -); - parameter DEL_MODE = "USER_DEFINED"; - parameter DEL_VALUE = 0; -endmodule - -(* blackbox *) -module DELAYG( - input A, - output Z -); - parameter DEL_MODE = "USER_DEFINED"; - parameter DEL_VALUE = 0; -endmodule - -(* blackbox *) -module IDDRX1F( - input D, SCLK, RST, - output Q0, Q1 -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module IDDRX2F( - input D, SCLK, ECLK, RST, ALIGNWD, - output Q0, Q1, Q2, Q3 -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module IDDR71B( - input D, SCLK, ECLK, RST, ALIGNWD, - output Q0, Q1, Q2, Q3, Q4, Q5, Q6 -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module IDDRX2DQA( - input D, DQSR90, ECLK, SCLK, RST, - input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, - output Q0, Q1, Q2, Q3, QWL -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module ODDRX1F( - input SCLK, RST, D0, D1, - output Q -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module ODDRX2F( - input SCLK, ECLK, RST, D0, D1, D2, D3, - output Q -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module ODDR71B( - input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6, - output Q -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module OSHX2A( - input D0, D1, RST, ECLK, SCLK, - output Q -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module ODDRX2DQA( - input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270, - output Q -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module ODDRX2DQSB( - input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW, - output Q -); - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module TSHX2DQA( - input T0, T1, SCLK, ECLK, DQSW270, RST, - output Q -); - parameter GSR = "ENABLED"; - parameter REGSET = "SET"; -endmodule - -(* blackbox *) -module TSHX2DQSA( - input T0, T1, SCLK, ECLK, DQSW, RST, - output Q -); - parameter GSR = "ENABLED"; - parameter REGSET = "SET"; -endmodule - -(* blackbox *) -module DQSBUFM( - input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL, - input ECLK, SCLK, - input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4, - input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0, - input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE, - output DQSR90, DQSW, DQSW270, - output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, - output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG -); - parameter DQS_LI_DEL_ADJ = "FACTORYONLY"; - parameter DQS_LI_DEL_VAL = 0; - parameter DQS_LO_DEL_ADJ = "FACTORYONLY"; - parameter DQS_LO_DEL_VAL = 0; - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module DDRDLLA( - input CLK, RST, UDDCNTLN, FREEZE, - output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0 -); - parameter FORCE_MAX_DELAY = "NO"; - parameter GSR = "ENABLED"; -endmodule - -(* blackbox *) -module DLLDELD( - input A, DDRDEL, LOADN, MOVE, DIRECTION, - output Z, CFLAG -); - parameter DEL_ADJ = "PLUS"; - parameter DEL_VAL = 0; -endmodule - -(* blackbox *) -module CLKDIVF( - input CLKI, RST, ALIGNWD, - output CDIVX -); - parameter GSR = "DISABLED"; - parameter DIV = "2.0"; -endmodule - -(* blackbox *) -module ECLKSYNCB( - input ECLKI, STOP, - output ECLKO -); -endmodule - -(* blackbox *) -module ECLKBRIDGECS( - input CLK0, CLK1, SEL, - output ECSOUT -); -endmodule - -(* blackbox *) -module DCCA( - input CLKI, CE, - output CLKO -); -endmodule - -(* blackbox *) -module DCSC( - input CLK1, CLK0, - input SEL1, SEL0, - input MODESEL, - output DCSOUT -); - parameter DCSMODE = "POS"; -endmodule - -(* blackbox *) (* keep *) -module DCUA( - (* iopad_external_pin *) - input CH0_HDINP, - (* iopad_external_pin *) - input CH1_HDINP, - (* iopad_external_pin *) - input CH0_HDINN, - (* iopad_external_pin *) - input CH1_HDINN, - input D_TXBIT_CLKP_FROM_ND, D_TXBIT_CLKN_FROM_ND, D_SYNC_ND, D_TXPLL_LOL_FROM_ND, - input CH0_RX_REFCLK, CH1_RX_REFCLK, CH0_FF_RXI_CLK, CH1_FF_RXI_CLK, CH0_FF_TXI_CLK, CH1_FF_TXI_CLK, CH0_FF_EBRD_CLK, CH1_FF_EBRD_CLK, - input CH0_FF_TX_D_0, CH1_FF_TX_D_0, CH0_FF_TX_D_1, CH1_FF_TX_D_1, CH0_FF_TX_D_2, CH1_FF_TX_D_2, CH0_FF_TX_D_3, CH1_FF_TX_D_3, - input CH0_FF_TX_D_4, CH1_FF_TX_D_4, CH0_FF_TX_D_5, CH1_FF_TX_D_5, CH0_FF_TX_D_6, CH1_FF_TX_D_6, CH0_FF_TX_D_7, CH1_FF_TX_D_7, - input CH0_FF_TX_D_8, CH1_FF_TX_D_8, CH0_FF_TX_D_9, CH1_FF_TX_D_9, CH0_FF_TX_D_10, CH1_FF_TX_D_10, CH0_FF_TX_D_11, CH1_FF_TX_D_11, - input CH0_FF_TX_D_12, CH1_FF_TX_D_12, CH0_FF_TX_D_13, CH1_FF_TX_D_13, CH0_FF_TX_D_14, CH1_FF_TX_D_14, CH0_FF_TX_D_15, CH1_FF_TX_D_15, - input CH0_FF_TX_D_16, CH1_FF_TX_D_16, CH0_FF_TX_D_17, CH1_FF_TX_D_17, CH0_FF_TX_D_18, CH1_FF_TX_D_18, CH0_FF_TX_D_19, CH1_FF_TX_D_19, - input CH0_FF_TX_D_20, CH1_FF_TX_D_20, CH0_FF_TX_D_21, CH1_FF_TX_D_21, CH0_FF_TX_D_22, CH1_FF_TX_D_22, CH0_FF_TX_D_23, CH1_FF_TX_D_23, - input CH0_FFC_EI_EN, CH1_FFC_EI_EN, CH0_FFC_PCIE_DET_EN, CH1_FFC_PCIE_DET_EN, CH0_FFC_PCIE_CT, CH1_FFC_PCIE_CT, CH0_FFC_SB_INV_RX, CH1_FFC_SB_INV_RX, - input CH0_FFC_ENABLE_CGALIGN, CH1_FFC_ENABLE_CGALIGN, CH0_FFC_SIGNAL_DETECT, CH1_FFC_SIGNAL_DETECT, CH0_FFC_FB_LOOPBACK, CH1_FFC_FB_LOOPBACK, CH0_FFC_SB_PFIFO_LP, CH1_FFC_SB_PFIFO_LP, - input CH0_FFC_PFIFO_CLR, CH1_FFC_PFIFO_CLR, CH0_FFC_RATE_MODE_RX, CH1_FFC_RATE_MODE_RX, CH0_FFC_RATE_MODE_TX, CH1_FFC_RATE_MODE_TX, CH0_FFC_DIV11_MODE_RX, CH1_FFC_DIV11_MODE_RX, CH0_FFC_RX_GEAR_MODE, CH1_FFC_RX_GEAR_MODE, CH0_FFC_TX_GEAR_MODE, CH1_FFC_TX_GEAR_MODE, - input CH0_FFC_DIV11_MODE_TX, CH1_FFC_DIV11_MODE_TX, CH0_FFC_LDR_CORE2TX_EN, CH1_FFC_LDR_CORE2TX_EN, CH0_FFC_LANE_TX_RST, CH1_FFC_LANE_TX_RST, CH0_FFC_LANE_RX_RST, CH1_FFC_LANE_RX_RST, - input CH0_FFC_RRST, CH1_FFC_RRST, CH0_FFC_TXPWDNB, CH1_FFC_TXPWDNB, CH0_FFC_RXPWDNB, CH1_FFC_RXPWDNB, CH0_LDR_CORE2TX, CH1_LDR_CORE2TX, - input D_SCIWDATA0, D_SCIWDATA1, D_SCIWDATA2, D_SCIWDATA3, D_SCIWDATA4, D_SCIWDATA5, D_SCIWDATA6, D_SCIWDATA7, - input D_SCIADDR0, D_SCIADDR1, D_SCIADDR2, D_SCIADDR3, D_SCIADDR4, D_SCIADDR5, D_SCIENAUX, D_SCISELAUX, - input CH0_SCIEN, CH1_SCIEN, CH0_SCISEL, CH1_SCISEL, D_SCIRD, D_SCIWSTN, D_CYAWSTN, D_FFC_SYNC_TOGGLE, - input D_FFC_DUAL_RST, D_FFC_MACRO_RST, D_FFC_MACROPDB, D_FFC_TRST, CH0_FFC_CDR_EN_BITSLIP, CH1_FFC_CDR_EN_BITSLIP, D_SCAN_ENABLE, D_SCAN_IN_0, - input D_SCAN_IN_1, D_SCAN_IN_2, D_SCAN_IN_3, D_SCAN_IN_4, D_SCAN_IN_5, D_SCAN_IN_6, D_SCAN_IN_7, D_SCAN_MODE, - input D_SCAN_RESET, D_CIN0, D_CIN1, D_CIN2, D_CIN3, D_CIN4, D_CIN5, D_CIN6,D_CIN7, D_CIN8, D_CIN9, D_CIN10, D_CIN11, - output CH0_HDOUTP, CH1_HDOUTP, CH0_HDOUTN, CH1_HDOUTN, D_TXBIT_CLKP_TO_ND, D_TXBIT_CLKN_TO_ND, D_SYNC_PULSE2ND, D_TXPLL_LOL_TO_ND, - output CH0_FF_RX_F_CLK, CH1_FF_RX_F_CLK, CH0_FF_RX_H_CLK, CH1_FF_RX_H_CLK, CH0_FF_TX_F_CLK, CH1_FF_TX_F_CLK, CH0_FF_TX_H_CLK, CH1_FF_TX_H_CLK, - output CH0_FF_RX_PCLK, CH1_FF_RX_PCLK, CH0_FF_TX_PCLK, CH1_FF_TX_PCLK, CH0_FF_RX_D_0, CH1_FF_RX_D_0, CH0_FF_RX_D_1, CH1_FF_RX_D_1, - output CH0_FF_RX_D_2, CH1_FF_RX_D_2, CH0_FF_RX_D_3, CH1_FF_RX_D_3, CH0_FF_RX_D_4, CH1_FF_RX_D_4, CH0_FF_RX_D_5, CH1_FF_RX_D_5, - output CH0_FF_RX_D_6, CH1_FF_RX_D_6, CH0_FF_RX_D_7, CH1_FF_RX_D_7, CH0_FF_RX_D_8, CH1_FF_RX_D_8, CH0_FF_RX_D_9, CH1_FF_RX_D_9, - output CH0_FF_RX_D_10, CH1_FF_RX_D_10, CH0_FF_RX_D_11, CH1_FF_RX_D_11, CH0_FF_RX_D_12, CH1_FF_RX_D_12, CH0_FF_RX_D_13, CH1_FF_RX_D_13, - output CH0_FF_RX_D_14, CH1_FF_RX_D_14, CH0_FF_RX_D_15, CH1_FF_RX_D_15, CH0_FF_RX_D_16, CH1_FF_RX_D_16, CH0_FF_RX_D_17, CH1_FF_RX_D_17, - output CH0_FF_RX_D_18, CH1_FF_RX_D_18, CH0_FF_RX_D_19, CH1_FF_RX_D_19, CH0_FF_RX_D_20, CH1_FF_RX_D_20, CH0_FF_RX_D_21, CH1_FF_RX_D_21, - output CH0_FF_RX_D_22, CH1_FF_RX_D_22, CH0_FF_RX_D_23, CH1_FF_RX_D_23, CH0_FFS_PCIE_DONE, CH1_FFS_PCIE_DONE, CH0_FFS_PCIE_CON, CH1_FFS_PCIE_CON, - output CH0_FFS_RLOS, CH1_FFS_RLOS, CH0_FFS_LS_SYNC_STATUS, CH1_FFS_LS_SYNC_STATUS, CH0_FFS_CC_UNDERRUN, CH1_FFS_CC_UNDERRUN, CH0_FFS_CC_OVERRUN, CH1_FFS_CC_OVERRUN, - output CH0_FFS_RXFBFIFO_ERROR, CH1_FFS_RXFBFIFO_ERROR, CH0_FFS_TXFBFIFO_ERROR, CH1_FFS_TXFBFIFO_ERROR, CH0_FFS_RLOL, CH1_FFS_RLOL, CH0_FFS_SKP_ADDED, CH1_FFS_SKP_ADDED, - output CH0_FFS_SKP_DELETED, CH1_FFS_SKP_DELETED, CH0_LDR_RX2CORE, CH1_LDR_RX2CORE, D_SCIRDATA0, D_SCIRDATA1, D_SCIRDATA2, D_SCIRDATA3, - output D_SCIRDATA4, D_SCIRDATA5, D_SCIRDATA6, D_SCIRDATA7, D_SCIINT, D_SCAN_OUT_0, D_SCAN_OUT_1, D_SCAN_OUT_2, D_SCAN_OUT_3, D_SCAN_OUT_4, D_SCAN_OUT_5, D_SCAN_OUT_6, D_SCAN_OUT_7, - output D_COUT0, D_COUT1, D_COUT2, D_COUT3, D_COUT4, D_COUT5, D_COUT6, D_COUT7, D_COUT8, D_COUT9, D_COUT10, D_COUT11, D_COUT12, D_COUT13, D_COUT14, D_COUT15, D_COUT16, D_COUT17, D_COUT18, D_COUT19, - - input D_REFCLKI, - output D_FFS_PLOL -); - parameter CH0_AUTO_CALIB_EN = "0b0"; - parameter CH0_AUTO_FACQ_EN = "0b0"; - parameter CH0_BAND_THRESHOLD = "0b000000"; - parameter CH0_CALIB_CK_MODE = "0b0"; - parameter CH0_CC_MATCH_1 = "0b0000000000"; - parameter CH0_CC_MATCH_2 = "0b0000000000"; - parameter CH0_CC_MATCH_3 = "0b0000000000"; - parameter CH0_CC_MATCH_4 = "0b0000000000"; - parameter CH0_CDR_CNT4SEL = "0b00"; - parameter CH0_CDR_CNT8SEL = "0b00"; - parameter CH0_CTC_BYPASS = "0b0"; - parameter CH0_DCOATDCFG = "0b00"; - parameter CH0_DCOATDDLY = "0b00"; - parameter CH0_DCOBYPSATD = "0b0"; - parameter CH0_DCOCALDIV = "0b000"; - parameter CH0_DCOCTLGI = "0b000"; - parameter CH0_DCODISBDAVOID = "0b0"; - parameter CH0_DCOFLTDAC = "0b00"; - parameter CH0_DCOFTNRG = "0b000"; - parameter CH0_DCOIOSTUNE = "0b000"; - parameter CH0_DCOITUNE = "0b00"; - parameter CH0_DCOITUNE4LSB = "0b000"; - parameter CH0_DCOIUPDNX2 = "0b0"; - parameter CH0_DCONUOFLSB = "0b000"; - parameter CH0_DCOSCALEI = "0b00"; - parameter CH0_DCOSTARTVAL = "0b000"; - parameter CH0_DCOSTEP = "0b00"; - parameter CH0_DEC_BYPASS = "0b0"; - parameter CH0_ENABLE_CG_ALIGN = "0b0"; - parameter CH0_ENC_BYPASS = "0b0"; - parameter CH0_FF_RX_F_CLK_DIS = "0b0"; - parameter CH0_FF_RX_H_CLK_EN = "0b0"; - parameter CH0_FF_TX_F_CLK_DIS = "0b0"; - parameter CH0_FF_TX_H_CLK_EN = "0b0"; - parameter CH0_GE_AN_ENABLE = "0b0"; - parameter CH0_INVERT_RX = "0b0"; - parameter CH0_INVERT_TX = "0b0"; - parameter CH0_LDR_CORE2TX_SEL = "0b0"; - parameter CH0_LDR_RX2CORE_SEL = "0b0"; - parameter CH0_LEQ_OFFSET_SEL = "0b0"; - parameter CH0_LEQ_OFFSET_TRIM = "0b000"; - parameter CH0_LSM_DISABLE = "0b0"; - parameter CH0_MATCH_2_ENABLE = "0b0"; - parameter CH0_MATCH_4_ENABLE = "0b0"; - parameter CH0_MIN_IPG_CNT = "0b00"; - parameter CH0_PCIE_EI_EN = "0b0"; - parameter CH0_PCIE_MODE = "0b0"; - parameter CH0_PCS_DET_TIME_SEL = "0b00"; - parameter CH0_PDEN_SEL = "0b0"; - parameter CH0_PRBS_ENABLE = "0b0"; - parameter CH0_PRBS_LOCK = "0b0"; - parameter CH0_PRBS_SELECTION = "0b0"; - parameter CH0_RATE_MODE_RX = "0b0"; - parameter CH0_RATE_MODE_TX = "0b0"; - parameter CH0_RCV_DCC_EN = "0b0"; - parameter CH0_REG_BAND_OFFSET = "0b0000"; - parameter CH0_REG_BAND_SEL = "0b000000"; - parameter CH0_REG_IDAC_EN = "0b0"; - parameter CH0_REG_IDAC_SEL = "0b0000000000"; - parameter CH0_REQ_EN = "0b0"; - parameter CH0_REQ_LVL_SET = "0b00"; - parameter CH0_RIO_MODE = "0b0"; - parameter CH0_RLOS_SEL = "0b0"; - parameter CH0_RPWDNB = "0b0"; - parameter CH0_RTERM_RX = "0b00000"; - parameter CH0_RTERM_TX = "0b00000"; - parameter CH0_RXIN_CM = "0b00"; - parameter CH0_RXTERM_CM = "0b00"; - parameter CH0_RX_DCO_CK_DIV = "0b000"; - parameter CH0_RX_DIV11_SEL = "0b0"; - parameter CH0_RX_GEAR_BYPASS = "0b0"; - parameter CH0_RX_GEAR_MODE = "0b0"; - parameter CH0_RX_LOS_CEQ = "0b00"; - parameter CH0_RX_LOS_EN = "0b0"; - parameter CH0_RX_LOS_HYST_EN = "0b0"; - parameter CH0_RX_LOS_LVL = "0b000"; - parameter CH0_RX_RATE_SEL = "0b0000"; - parameter CH0_RX_SB_BYPASS = "0b0"; - parameter CH0_SB_BYPASS = "0b0"; - parameter CH0_SEL_SD_RX_CLK = "0b0"; - parameter CH0_TDRV_DAT_SEL = "0b00"; - parameter CH0_TDRV_POST_EN = "0b0"; - parameter CH0_TDRV_PRE_EN = "0b0"; - parameter CH0_TDRV_SLICE0_CUR = "0b000"; - parameter CH0_TDRV_SLICE0_SEL = "0b00"; - parameter CH0_TDRV_SLICE1_CUR = "0b000"; - parameter CH0_TDRV_SLICE1_SEL = "0b00"; - parameter CH0_TDRV_SLICE2_CUR = "0b00"; - parameter CH0_TDRV_SLICE2_SEL = "0b00"; - parameter CH0_TDRV_SLICE3_CUR = "0b00"; - parameter CH0_TDRV_SLICE3_SEL = "0b00"; - parameter CH0_TDRV_SLICE4_CUR = "0b00"; - parameter CH0_TDRV_SLICE4_SEL = "0b00"; - parameter CH0_TDRV_SLICE5_CUR = "0b00"; - parameter CH0_TDRV_SLICE5_SEL = "0b00"; - parameter CH0_TPWDNB = "0b0"; - parameter CH0_TX_CM_SEL = "0b00"; - parameter CH0_TX_DIV11_SEL = "0b0"; - parameter CH0_TX_GEAR_BYPASS = "0b0"; - parameter CH0_TX_GEAR_MODE = "0b0"; - parameter CH0_TX_POST_SIGN = "0b0"; - parameter CH0_TX_PRE_SIGN = "0b0"; - parameter CH0_UC_MODE = "0b0"; - parameter CH0_UDF_COMMA_A = "0b0000000000"; - parameter CH0_UDF_COMMA_B = "0b0000000000"; - parameter CH0_UDF_COMMA_MASK = "0b0000000000"; - parameter CH0_WA_BYPASS = "0b0"; - parameter CH0_WA_MODE = "0b0"; - parameter CH1_AUTO_CALIB_EN = "0b0"; - parameter CH1_AUTO_FACQ_EN = "0b0"; - parameter CH1_BAND_THRESHOLD = "0b000000"; - parameter CH1_CALIB_CK_MODE = "0b0"; - parameter CH1_CC_MATCH_1 = "0b0000000000"; - parameter CH1_CC_MATCH_2 = "0b0000000000"; - parameter CH1_CC_MATCH_3 = "0b0000000000"; - parameter CH1_CC_MATCH_4 = "0b0000000000"; - parameter CH1_CDR_CNT4SEL = "0b00"; - parameter CH1_CDR_CNT8SEL = "0b00"; - parameter CH1_CTC_BYPASS = "0b0"; - parameter CH1_DCOATDCFG = "0b00"; - parameter CH1_DCOATDDLY = "0b00"; - parameter CH1_DCOBYPSATD = "0b0"; - parameter CH1_DCOCALDIV = "0b000"; - parameter CH1_DCOCTLGI = "0b000"; - parameter CH1_DCODISBDAVOID = "0b0"; - parameter CH1_DCOFLTDAC = "0b00"; - parameter CH1_DCOFTNRG = "0b000"; - parameter CH1_DCOIOSTUNE = "0b000"; - parameter CH1_DCOITUNE = "0b00"; - parameter CH1_DCOITUNE4LSB = "0b000"; - parameter CH1_DCOIUPDNX2 = "0b0"; - parameter CH1_DCONUOFLSB = "0b000"; - parameter CH1_DCOSCALEI = "0b00"; - parameter CH1_DCOSTARTVAL = "0b000"; - parameter CH1_DCOSTEP = "0b00"; - parameter CH1_DEC_BYPASS = "0b0"; - parameter CH1_ENABLE_CG_ALIGN = "0b0"; - parameter CH1_ENC_BYPASS = "0b0"; - parameter CH1_FF_RX_F_CLK_DIS = "0b0"; - parameter CH1_FF_RX_H_CLK_EN = "0b0"; - parameter CH1_FF_TX_F_CLK_DIS = "0b0"; - parameter CH1_FF_TX_H_CLK_EN = "0b0"; - parameter CH1_GE_AN_ENABLE = "0b0"; - parameter CH1_INVERT_RX = "0b0"; - parameter CH1_INVERT_TX = "0b0"; - parameter CH1_LDR_CORE2TX_SEL = "0b0"; - parameter CH1_LDR_RX2CORE_SEL = "0b0"; - parameter CH1_LEQ_OFFSET_SEL = "0b0"; - parameter CH1_LEQ_OFFSET_TRIM = "0b000"; - parameter CH1_LSM_DISABLE = "0b0"; - parameter CH1_MATCH_2_ENABLE = "0b0"; - parameter CH1_MATCH_4_ENABLE = "0b0"; - parameter CH1_MIN_IPG_CNT = "0b00"; - parameter CH1_PCIE_EI_EN = "0b0"; - parameter CH1_PCIE_MODE = "0b0"; - parameter CH1_PCS_DET_TIME_SEL = "0b00"; - parameter CH1_PDEN_SEL = "0b0"; - parameter CH1_PRBS_ENABLE = "0b0"; - parameter CH1_PRBS_LOCK = "0b0"; - parameter CH1_PRBS_SELECTION = "0b0"; - parameter CH1_RATE_MODE_RX = "0b0"; - parameter CH1_RATE_MODE_TX = "0b0"; - parameter CH1_RCV_DCC_EN = "0b0"; - parameter CH1_REG_BAND_OFFSET = "0b0000"; - parameter CH1_REG_BAND_SEL = "0b000000"; - parameter CH1_REG_IDAC_EN = "0b0"; - parameter CH1_REG_IDAC_SEL = "0b0000000000"; - parameter CH1_REQ_EN = "0b0"; - parameter CH1_REQ_LVL_SET = "0b00"; - parameter CH1_RIO_MODE = "0b0"; - parameter CH1_RLOS_SEL = "0b0"; - parameter CH1_RPWDNB = "0b0"; - parameter CH1_RTERM_RX = "0b00000"; - parameter CH1_RTERM_TX = "0b00000"; - parameter CH1_RXIN_CM = "0b00"; - parameter CH1_RXTERM_CM = "0b00"; - parameter CH1_RX_DCO_CK_DIV = "0b000"; - parameter CH1_RX_DIV11_SEL = "0b0"; - parameter CH1_RX_GEAR_BYPASS = "0b0"; - parameter CH1_RX_GEAR_MODE = "0b0"; - parameter CH1_RX_LOS_CEQ = "0b00"; - parameter CH1_RX_LOS_EN = "0b0"; - parameter CH1_RX_LOS_HYST_EN = "0b0"; - parameter CH1_RX_LOS_LVL = "0b000"; - parameter CH1_RX_RATE_SEL = "0b0000"; - parameter CH1_RX_SB_BYPASS = "0b0"; - parameter CH1_SB_BYPASS = "0b0"; - parameter CH1_SEL_SD_RX_CLK = "0b0"; - parameter CH1_TDRV_DAT_SEL = "0b00"; - parameter CH1_TDRV_POST_EN = "0b0"; - parameter CH1_TDRV_PRE_EN = "0b0"; - parameter CH1_TDRV_SLICE0_CUR = "0b000"; - parameter CH1_TDRV_SLICE0_SEL = "0b00"; - parameter CH1_TDRV_SLICE1_CUR = "0b000"; - parameter CH1_TDRV_SLICE1_SEL = "0b00"; - parameter CH1_TDRV_SLICE2_CUR = "0b00"; - parameter CH1_TDRV_SLICE2_SEL = "0b00"; - parameter CH1_TDRV_SLICE3_CUR = "0b00"; - parameter CH1_TDRV_SLICE3_SEL = "0b00"; - parameter CH1_TDRV_SLICE4_CUR = "0b00"; - parameter CH1_TDRV_SLICE4_SEL = "0b00"; - parameter CH1_TDRV_SLICE5_CUR = "0b00"; - parameter CH1_TDRV_SLICE5_SEL = "0b00"; - parameter CH1_TPWDNB = "0b0"; - parameter CH1_TX_CM_SEL = "0b00"; - parameter CH1_TX_DIV11_SEL = "0b0"; - parameter CH1_TX_GEAR_BYPASS = "0b0"; - parameter CH1_TX_GEAR_MODE = "0b0"; - parameter CH1_TX_POST_SIGN = "0b0"; - parameter CH1_TX_PRE_SIGN = "0b0"; - parameter CH1_UC_MODE = "0b0"; - parameter CH1_UDF_COMMA_A = "0b0000000000"; - parameter CH1_UDF_COMMA_B = "0b0000000000"; - parameter CH1_UDF_COMMA_MASK = "0b0000000000"; - parameter CH1_WA_BYPASS = "0b0"; - parameter CH1_WA_MODE = "0b0"; - parameter D_BITCLK_FROM_ND_EN = "0b0"; - parameter D_BITCLK_LOCAL_EN = "0b0"; - parameter D_BITCLK_ND_EN = "0b0"; - parameter D_BUS8BIT_SEL = "0b0"; - parameter D_CDR_LOL_SET = "0b00"; - parameter D_CMUSETBIASI = "0b00"; - parameter D_CMUSETI4CPP = "0b0000"; - parameter D_CMUSETI4CPZ = "0b0000"; - parameter D_CMUSETI4VCO = "0b00"; - parameter D_CMUSETICP4P = "0b00"; - parameter D_CMUSETICP4Z = "0b000"; - parameter D_CMUSETINITVCT = "0b00"; - parameter D_CMUSETISCL4VCO = "0b000"; - parameter D_CMUSETP1GM = "0b000"; - parameter D_CMUSETP2AGM = "0b000"; - parameter D_CMUSETZGM = "0b000"; - parameter D_DCO_CALIB_TIME_SEL = "0b00"; - parameter D_HIGH_MARK = "0b0000"; - parameter D_IB_PWDNB = "0b0"; - parameter D_ISETLOS = "0b00000000"; - parameter D_LOW_MARK = "0b0000"; - parameter D_MACROPDB = "0b0"; - parameter D_PD_ISET = "0b00"; - parameter D_PLL_LOL_SET = "0b00"; - parameter D_REFCK_MODE = "0b000"; - parameter D_REQ_ISET = "0b000"; - parameter D_RG_EN = "0b0"; - parameter D_RG_SET = "0b00"; - parameter D_SETICONST_AUX = "0b00"; - parameter D_SETICONST_CH = "0b00"; - parameter D_SETIRPOLY_AUX = "0b00"; - parameter D_SETIRPOLY_CH = "0b00"; - parameter D_SETPLLRC = "0b000000"; - parameter D_SYNC_LOCAL_EN = "0b0"; - parameter D_SYNC_ND_EN = "0b0"; - parameter D_TXPLL_PWDNB = "0b0"; - parameter D_TX_VCO_CK_DIV = "0b000"; - parameter D_XGE_MODE = "0b0"; - -// These parameters don't do anything but are -// needed for compatibility with Diamond - parameter D_TX_MAX_RATE = "2.5"; - parameter D_RX_MAX_RATE = "2.5"; - parameter CH0_TXAMPLITUDE = "0d1300"; - parameter CH1_TXAMPLITUDE = "0d1300"; - parameter CH0_PROTOCOL = "8B10B"; - parameter CH1_PROTOCOL = "8B10B"; - parameter CH0_CDR_MAX_RATE = "2.5"; - parameter CH1_CDR_MAX_RATE = "2.5"; - parameter CH0_TXDEPRE = "DISABLED"; - parameter CH1_TXDEPRE = "DISABLED"; - parameter CH0_TXDEPOST = "DISABLED"; - parameter CH1_TXDEPOST = "DISABLED"; -endmodule - -(* blackbox *) -module EXTREFB ( - (* iopad_external_pin *) - input REFCLKP, - (* iopad_external_pin *) - input REFCLKN, - output REFCLKO -); - parameter REFCK_PWDNB = "0b0"; - parameter REFCK_RTERM = "0b0"; - parameter REFCK_DCBIAS_EN = "0b0"; -endmodule - -(* blackbox *) -module PCSCLKDIV ( - input CLKI, RST, SEL2, SEL1, SEL0, - output CDIV1, CDIVX -); - parameter GSR = "DISABLED"; -endmodule - -// Note: this module is not marked keep as we want it swept away in synth (sim use only) -(* blackbox *) -module PUR ( - input PUR -); - parameter RST_PULSE = 1; -endmodule - -(* blackbox, keep *) -module GSR ( - input GSR -); -endmodule - -(* blackbox, keep *) -module SGSR ( - input GSR, CLK -); -endmodule - - -(* blackbox *) -module PDPW16KD ( - input DI35, DI34, DI33, DI32, DI31, DI30, DI29, DI28, DI27, DI26, DI25, DI24, DI23, DI22, DI21, DI20, DI19, DI18, - input DI17, DI16, DI15, DI14, DI13, DI12, DI11, DI10, DI9, DI8, DI7, DI6, DI5, DI4, DI3, DI2, DI1, DI0, - input ADW8, ADW7, ADW6, ADW5, ADW4, ADW3, ADW2, ADW1, ADW0, - input BE3, BE2, BE1, BE0, CEW, CLKW, CSW2, CSW1, CSW0, - input ADR13, ADR12, ADR11, ADR10, ADR9, ADR8, ADR7, ADR6, ADR5, ADR4, ADR3, ADR2, ADR1, ADR0, - input CER, OCER, CLKR, CSR2, CSR1, CSR0, RST, - output DO35, DO34, DO33, DO32, DO31, DO30, DO29, DO28, DO27, DO26, DO25, DO24, DO23, DO22, DO21, DO20, DO19, DO18, - output DO17, DO16, DO15, DO14, DO13, DO12, DO11, DO10, DO9, DO8, DO7, DO6, DO5, DO4, DO3, DO2, DO1, DO0 -); - parameter DATA_WIDTH_W = 36; - parameter DATA_WIDTH_R = 36; - parameter GSR = "ENABLED"; - - parameter REGMODE = "NOREG"; - - parameter RESETMODE = "SYNC"; - parameter ASYNC_RESET_RELEASE = "SYNC"; - - parameter CSDECODE_W = "0b000"; - parameter CSDECODE_R = "0b000"; - - parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INIT_DATA = "STATIC"; - parameter CLKWMUX = "CLKW"; - parameter CLKRMUX = "CLKR"; - -endmodule diff --git a/techlibs/ecp5/cells_ff.vh b/techlibs/ecp5/cells_ff.vh deleted file mode 100644 index 6b745f391..000000000 --- a/techlibs/ecp5/cells_ff.vh +++ /dev/null @@ -1,40 +0,0 @@ -// Diamond flip-flops -module FD1P3AX(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .CE(SP), .DI(D), .Q(Q)); endmodule -module FD1P3AY(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .CE(SP), .DI(D), .Q(Q)); endmodule -module FD1P3BX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule -module FD1P3DX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule -module FD1P3IX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule -module FD1P3JX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule -module FD1S3AX(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .DI(D), .Q(Q)); endmodule -module FD1S3AY(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .DI(D), .Q(Q)); endmodule -module FD1S3BX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule -module FD1S3DX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule -module FD1S3IX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule -module FD1S3JX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule - -// TODO: Diamond latches -// module FL1P3AY(); endmodule -// module FL1P3AZ(); endmodule -// module FL1P3BX(); endmodule -// module FL1P3DX(); endmodule -// module FL1P3IY(); endmodule -// module FL1P3JY(); endmodule -// module FL1S3AX(); endmodule -// module FL1S3AY(); endmodule - -// Diamond I/O registers -module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule -module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule -module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule -module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule - -module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule -module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule -module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule -module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule - -// TODO: Diamond I/O latches -// module IFS1S1B(input PD, D, SCLK, output Q); endmodule -// module IFS1S1D(input CD, D, SCLK, output Q); endmodule -// module IFS1S1I(input PD, D, SCLK, output Q); endmodule -// module IFS1S1J(input CD, D, SCLK, output Q); endmodule diff --git a/techlibs/ecp5/cells_io.vh b/techlibs/ecp5/cells_io.vh deleted file mode 100644 index 220460c44..000000000 --- a/techlibs/ecp5/cells_io.vh +++ /dev/null @@ -1,14 +0,0 @@ -// Diamond I/O buffers -module IB ((* iopad_external_pin *) input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule -module IBPU ((* iopad_external_pin *) input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule -module IBPD ((* iopad_external_pin *) input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule -module OB (input I, (* iopad_external_pin *) output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule -module OBZ (input I, T, (* iopad_external_pin *) output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule -module OBZPU(input I, T, (* iopad_external_pin *) output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule -module OBZPD(input I, T, (* iopad_external_pin *) 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 olvds (.A(I), .Z(OT), .ZN(OC)); endmodule -module BB (input I, T, output O, (* iopad_external_pin *) 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, (* iopad_external_pin *) 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, (* iopad_external_pin *) inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule -module ILVDS(input A, AN, (* iopad_external_pin *) output Z ); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule -module OLVDS(input A, (* iopad_external_pin *) output Z, output ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v deleted file mode 100644 index 4944ece45..000000000 --- a/techlibs/ecp5/cells_map.v +++ /dev/null @@ -1,191 +0,0 @@ -module \$_DFF_N_ (input D, C, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); - else - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; -endmodule - -module \$_DFF_P_ (input D, C, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); - else - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; -endmodule - -module \$_DFFE_NN_ (input D, C, E, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - else - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; -endmodule - -module \$_DFFE_PN_ (input D, C, E, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - else - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; -endmodule - -module \$_DFFE_NP_ (input D, C, E, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - else - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; -endmodule - -module \$_DFFE_PP_ (input D, C, E, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - else - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; -endmodule - -module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule - -module \$_SDFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule - -module \$_DFFE_NP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_NP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_PP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule - -module \$_DFFE_NP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_NP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_PP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_PP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule - -module \$_SDFFE_NP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_NP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule - -module \$_SDFFE_NP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_NP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule - -module \$_ALDFF_NP_ (input C, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule -module \$_ALDFF_PP_ (input C, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule - -module \$_ALDFFE_NPN_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule -module \$_ALDFFE_NPP_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule -module \$_ALDFFE_PPN_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule -module \$_ALDFFE_PPP_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule - -`include "cells_ff.vh" -`include "cells_io.vh" - -`ifndef NO_LUT -module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; - - (* force_downto *) - input [WIDTH-1:0] A; - output Y; - - generate - if (WIDTH == 1) begin - localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}}; - LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), - .A(1'b0), .B(1'b0), .C(1'b0), .D(A[0])); - end else - if (WIDTH == 2) begin - localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}}; - LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), - .A(1'b0), .B(1'b0), .C(A[0]), .D(A[1])); - end else - if (WIDTH == 3) begin - localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}}; - LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), - .A(1'b0), .B(A[0]), .C(A[1]), .D(A[2])); - end else - if (WIDTH == 4) begin - LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - `ifndef NO_PFUMUX - end else - if (WIDTH == 5) begin - wire f0, f1; - LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y)); - end else - if (WIDTH == 6) begin - wire f0, f1, f2, f3, g0, g1; - LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - - LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - - PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); - PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); - L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y)); - end else - if (WIDTH == 7) begin - wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1; - LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - - LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - - LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - - LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7), - .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); - - PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); - PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); - PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2)); - PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3)); - L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0)); - L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1)); - L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y)); - `endif - end else begin - wire _TECHMAP_FAIL_ = 1; - end - endgenerate -endmodule -`endif diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v deleted file mode 100644 index eec211d6b..000000000 --- a/techlibs/ecp5/cells_sim.v +++ /dev/null @@ -1,681 +0,0 @@ -// --------------------------------------- - -(* abc9_lut=1, lib_whitebox *) -module LUT4(input A, B, C, D, output Z); - parameter [15:0] INIT = 16'h0000; - wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0]; - wire [3:0] s2 = C ? s3[ 7:4] : s3[3:0]; - wire [1:0] s1 = B ? s2[ 3:2] : s2[1:0]; - assign Z = A ? s1[1] : s1[0]; - specify - (A => Z) = 141; - (B => Z) = 275; - (C => Z) = 379; - (D => Z) = 379; - endspecify -endmodule - -// This is a placeholder for ABC9 to extract the area/delay -// cost of 5-input LUTs and is not intended to be instantiated -// LUT5 = 2x LUT4 + PFUMX -(* abc9_lut=2 *) -module \$__ABC9_LUT5 (input M0, D, C, B, A, output Z); - specify - (M0 => Z) = 151; - (D => Z) = 239; - (C => Z) = 373; - (B => Z) = 477; - (A => Z) = 477; - endspecify -endmodule - -// This is a placeholder for ABC9 to extract the area/delay -// of 6-input LUTs and is not intended to be instantiated -// LUT6 = 2x LUT5 + MUX2 -(* abc9_lut=4 *) -module \$__ABC9_LUT6 (input M1, M0, D, C, B, A, output Z); - specify - (M1 => Z) = 148; - (M0 => Z) = 292; - (D => Z) = 380; - (C => Z) = 514; - (B => Z) = 618; - (A => Z) = 618; - endspecify -endmodule - -// This is a placeholder for ABC9 to extract the area/delay -// of 7-input LUTs and is not intended to be instantiated -// LUT7 = 2x LUT6 + MUX2 -(* abc9_lut=8 *) -module \$__ABC9_LUT7 (input M2, M1, M0, D, C, B, A, output Z); - specify - (M2 => Z) = 148; - (M1 => Z) = 289; - (M0 => Z) = 433; - (D => Z) = 521; - (C => Z) = 655; - (B => Z) = 759; - (A => Z) = 759; - endspecify -endmodule - -// --------------------------------------- -(* abc9_box, lib_whitebox *) -module L6MUX21 (input D0, D1, SD, output Z); - assign Z = SD ? D1 : D0; - specify - (D0 => Z) = 140; - (D1 => Z) = 141; - (SD => Z) = 148; - endspecify -endmodule - -// --------------------------------------- -(* abc9_box, lib_whitebox *) -module CCU2C( - (* abc9_carry *) - input CIN, - input A0, B0, C0, D0, A1, B1, C1, D1, - output S0, S1, - (* abc9_carry *) - output COUT -); - parameter [15:0] INIT0 = 16'h0000; - parameter [15:0] INIT1 = 16'h0000; - parameter INJECT1_0 = "YES"; - parameter INJECT1_1 = "YES"; - - // First half - wire LUT4_0, LUT2_0; - LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0)); - LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0)); - wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN; - assign S0 = LUT4_0 ^ gated_cin_0; - - wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0; - wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN); - - // Second half - wire LUT4_1, LUT2_1; - LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1)); - LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1)); - wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0; - assign S1 = LUT4_1 ^ gated_cin_1; - - wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1; - assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0); - - specify - (A0 => S0) = 379; - (B0 => S0) = 379; - (C0 => S0) = 275; - (D0 => S0) = 141; - (CIN => S0) = 257; - (A0 => S1) = 630; - (B0 => S1) = 630; - (C0 => S1) = 526; - (D0 => S1) = 392; - (A1 => S1) = 379; - (B1 => S1) = 379; - (C1 => S1) = 275; - (D1 => S1) = 141; - (CIN => S1) = 273; - (A0 => COUT) = 516; - (B0 => COUT) = 516; - (C0 => COUT) = 412; - (D0 => COUT) = 278; - (A1 => COUT) = 516; - (B1 => COUT) = 516; - (C1 => COUT) = 412; - (D1 => COUT) = 278; - (CIN => COUT) = 43; - endspecify -endmodule - -// --------------------------------------- - -module TRELLIS_RAM16X2 ( - input DI0, DI1, - input WAD0, WAD1, WAD2, WAD3, - input WRE, WCK, - input RAD0, RAD1, RAD2, RAD3, - output DO0, DO1 -); - parameter WCKMUX = "WCK"; - parameter WREMUX = "WRE"; - parameter INITVAL_0 = 16'h0000; - parameter INITVAL_1 = 16'h0000; - - reg [1:0] mem[15:0]; - - integer i; - initial begin - for (i = 0; i < 16; i = i + 1) - mem[i] <= {INITVAL_1[i], INITVAL_0[i]}; - end - - wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK; - - reg muxwre; - always @(*) - case (WREMUX) - "1": muxwre = 1'b1; - "0": muxwre = 1'b0; - "INV": muxwre = ~WRE; - default: muxwre = WRE; - endcase - - - always @(posedge muxwck) - if (muxwre) - mem[{WAD3, WAD2, WAD1, WAD0}] <= {DI1, DI0}; - - assign {DO1, DO0} = mem[{RAD3, RAD2, RAD1, RAD0}]; -endmodule - -// --------------------------------------- -(* abc9_box, lib_whitebox *) -module PFUMX (input ALUT, BLUT, C0, output Z); - assign Z = C0 ? ALUT : BLUT; - specify - (ALUT => Z) = 98; - (BLUT => Z) = 98; - (C0 => Z) = 151; - endspecify -endmodule - -// --------------------------------------- -(* abc9_box, lib_whitebox *) -module TRELLIS_DPR16X4 ( - input [3:0] DI, - input [3:0] WAD, - input WRE, - input WCK, - input [3:0] RAD, - output [3:0] DO -); - parameter WCKMUX = "WCK"; - parameter WREMUX = "WRE"; - parameter [63:0] INITVAL = 64'h0000000000000000; - - reg [3:0] mem[15:0]; - - integer i; - initial begin - for (i = 0; i < 16; i = i + 1) - mem[i] <= INITVAL[4*i +: 4]; - end - - wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK; - - reg muxwre; - always @(*) - case (WREMUX) - "1": muxwre = 1'b1; - "0": muxwre = 1'b0; - "INV": muxwre = ~WRE; - default: muxwre = WRE; - endcase - - always @(posedge muxwck) - if (muxwre) - mem[WAD] <= DI; - - assign DO = mem[RAD]; - - specify - // TODO - (RAD *> DO) = 0; - endspecify -endmodule - -// --------------------------------------- - -(* abc9_box, lib_whitebox *) -module DPR16X4C ( - input [3:0] DI, - input WCK, WRE, - input [3:0] RAD, - input [3:0] WAD, - output [3:0] DO -); - // For legacy Lattice compatibility, INITIVAL is a hex - // string rather than a numeric parameter - parameter INITVAL = "0x0000000000000000"; - - function [63:0] convert_initval; - input [143:0] hex_initval; - reg done; - reg [63:0] temp; - reg [7:0] char; - integer i; - begin - done = 1'b0; - temp = 0; - for (i = 0; i < 16; i = i + 1) begin - if (!done) begin - char = hex_initval[8*i +: 8]; - if (char == "x") begin - done = 1'b1; - end else begin - if (char >= "0" && char <= "9") - temp[4*i +: 4] = char - "0"; - else if (char >= "A" && char <= "F") - temp[4*i +: 4] = 10 + char - "A"; - else if (char >= "a" && char <= "f") - temp[4*i +: 4] = 10 + char - "a"; - end - end - end - convert_initval = temp; - end - endfunction - - localparam conv_initval = convert_initval(INITVAL); - - reg [3:0] ram[0:15]; - integer i; - initial begin - for (i = 0; i < 15; i = i + 1) begin - ram[i] <= conv_initval[4*i +: 4]; - end - end - - always @(posedge WCK) - if (WRE) - ram[WAD] <= DI; - - assign DO = ram[RAD]; - - specify - // TODO - (RAD *> DO) = 0; - endspecify -endmodule - -// --------------------------------------- - -(* lib_whitebox *) -module LUT2(input A, B, output Z); - parameter [3:0] INIT = 4'h0; - wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0]; - assign Z = A ? s1[1] : s1[0]; -endmodule - -// --------------------------------------- - -`ifdef YOSYS -(* abc9_flop=(SRMODE != "ASYNC"), abc9_box=(SRMODE == "ASYNC"), lib_whitebox *) -`endif -module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); - parameter GSR = "ENABLED"; - parameter [127:0] CEMUX = "1"; - parameter CLKMUX = "CLK"; - parameter LSRMUX = "LSR"; - parameter SRMODE = "LSR_OVER_CE"; - parameter REGSET = "RESET"; - parameter [127:0] LSRMODE = "LSR"; - - wire muxce; - generate - case (CEMUX) - "1": assign muxce = 1'b1; - "0": assign muxce = 1'b0; - "INV": assign muxce = ~CE; - default: assign muxce = CE; - endcase - endgenerate - - wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; - wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; - wire srval; - generate - if (LSRMODE == "PRLD") - assign srval = M; - else - assign srval = (REGSET == "SET") ? 1'b1 : 1'b0; - endgenerate - - initial Q = srval; - - generate - if (SRMODE == "ASYNC") begin - always @(posedge muxclk, posedge muxlsr) - if (muxlsr) - Q <= srval; - else if (muxce) - Q <= DI; - end else begin - always @(posedge muxclk) - if (muxlsr) - Q <= srval; - else if (muxce) - Q <= DI; - end - endgenerate - - specify - $setup(DI, negedge CLK &&& CLKMUX == "INV", 0); - $setup(CE, negedge CLK &&& CLKMUX == "INV", 0); - $setup(LSR, negedge CLK &&& CLKMUX == "INV", 0); - $setup(DI, posedge CLK &&& CLKMUX != "INV", 0); - $setup(CE, posedge CLK &&& CLKMUX != "INV", 0); - $setup(LSR, posedge CLK &&& CLKMUX != "INV", 0); -`ifndef YOSYS - if (SRMODE == "ASYNC" && muxlsr && CLKMUX == "INV") (negedge CLK => (Q : srval)) = 0; - if (SRMODE == "ASYNC" && muxlsr && CLKMUX != "INV") (posedge CLK => (Q : srval)) = 0; -`else - if (SRMODE == "ASYNC" && muxlsr) (LSR => Q) = 0; // Technically, this should be an edge sensitive path - // but for facilitating a bypass box, let's pretend it's - // a simple path -`endif - if (!muxlsr && muxce && CLKMUX == "INV") (negedge CLK => (Q : DI)) = 0; - if (!muxlsr && muxce && CLKMUX != "INV") (posedge CLK => (Q : DI)) = 0; - endspecify -endmodule - -// --------------------------------------- -(* keep *) -module TRELLIS_IO( - (* iopad_external_pin *) - inout B, - input I, - input T, - output O -); - parameter DIR = "INPUT"; - reg T_pd; - always @(*) if (T === 1'bz) T_pd = 1'b0; else T_pd = T; - - generate - if (DIR == "INPUT") begin - assign B = 1'bz; - assign O = B; - end else if (DIR == "OUTPUT") begin - assign B = T_pd ? 1'bz : I; - assign O = 1'bx; - end else if (DIR == "BIDIR") begin - assign B = T_pd ? 1'bz : I; - assign O = B; - end else begin - ERROR_UNKNOWN_IO_MODE error(); - end - endgenerate - -endmodule - -// --------------------------------------- - -module INV(input A, output Z); - assign Z = !A; -endmodule - -// --------------------------------------- - -module TRELLIS_COMB( - input A, B, C, D, M, - input FCI, F1, FXA, FXB, - input WD, - input WAD0, WAD1, WAD2, WAD3, - input WRE, WCK, - output F, FCO, OFX -); - parameter MODE = "LOGIC"; - parameter INITVAL = 16'h0; - parameter CCU2_INJECT1 = "NO"; - parameter WREMUX = "WRE"; - parameter IS_Z1 = 1'b0; - - generate - if (MODE == "LOGIC") begin: mode_logic - LUT4 #(.INIT(INITVAL)) lut4 (.A(A), .B(B), .C(C), .D(D), .Z(F)); - end else if (MODE == "CCU2") begin: mode_ccu2 - wire l4o, l2o; - LUT4 #(.INIT(INITVAL)) lut4_0(.A(A), .B(B), .C(C), .D(D), .Z(l4o)); - LUT2 #(.INIT(INITVAL[3:0])) lut2_0(.A(A), .B(B), .Z(l2o)); - wire gated_cin_0 = (CCU2_INJECT1 == "YES") ? 1'b0 : FCI; - assign F = l4o ^ gated_cin_0; - wire gated_lut2_0 = (CCU2_INJECT1 == "YES") ? 1'b0 : l2o; - wire FCO = (~l4o & gated_lut2_0) | (l4o & FCI); - end else if (MODE == "DPRAM") begin: mode_dpram - reg [15:0] ram = INITVAL; - always @(posedge WCK) - if (WRE) - ram[{WAD3, WAD2, WAD1, WAD0}] <= WD; - assign F = ram[{A, C, B, D}]; - end else begin - $error("unsupported COMB mode %s", MODE); - end - - if (IS_Z1) - L6MUX21 lutx_mux (.D0(FXA), .D1(FXB), .SD(M), .Z(OFX)); - else - PFUMX lut5_mux (.ALUT(F1), .BLUT(F), .C0(M), .Z(OFX)); - endgenerate - -endmodule - -(* blackbox *) -module DP16KD( - input DIA17, DIA16, DIA15, DIA14, DIA13, DIA12, DIA11, DIA10, DIA9, DIA8, DIA7, DIA6, DIA5, DIA4, DIA3, DIA2, DIA1, DIA0, - input ADA13, ADA12, ADA11, ADA10, ADA9, ADA8, ADA7, ADA6, ADA5, ADA4, ADA3, ADA2, ADA1, ADA0, - input CEA, OCEA, CLKA, WEA, RSTA, - input CSA2, CSA1, CSA0, - output DOA17, DOA16, DOA15, DOA14, DOA13, DOA12, DOA11, DOA10, DOA9, DOA8, DOA7, DOA6, DOA5, DOA4, DOA3, DOA2, DOA1, DOA0, - - input DIB17, DIB16, DIB15, DIB14, DIB13, DIB12, DIB11, DIB10, DIB9, DIB8, DIB7, DIB6, DIB5, DIB4, DIB3, DIB2, DIB1, DIB0, - input ADB13, ADB12, ADB11, ADB10, ADB9, ADB8, ADB7, ADB6, ADB5, ADB4, ADB3, ADB2, ADB1, ADB0, - input CEB, OCEB, CLKB, WEB, RSTB, - input CSB2, CSB1, CSB0, - output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0 -); - parameter DATA_WIDTH_A = 18; - parameter DATA_WIDTH_B = 18; - - parameter REGMODE_A = "NOREG"; - parameter REGMODE_B = "NOREG"; - - parameter RESETMODE = "SYNC"; - parameter ASYNC_RESET_RELEASE = "SYNC"; - - parameter CSDECODE_A = "0b000"; - parameter CSDECODE_B = "0b000"; - - parameter WRITEMODE_A = "NORMAL"; - parameter WRITEMODE_B = "NORMAL"; - - parameter DIA17MUX = "DIA17"; - parameter DIA16MUX = "DIA16"; - parameter DIA15MUX = "DIA15"; - parameter DIA14MUX = "DIA14"; - parameter DIA13MUX = "DIA13"; - parameter DIA12MUX = "DIA12"; - parameter DIA11MUX = "DIA11"; - parameter DIA10MUX = "DIA10"; - parameter DIA9MUX = "DIA9"; - parameter DIA8MUX = "DIA8"; - parameter DIA7MUX = "DIA7"; - parameter DIA6MUX = "DIA6"; - parameter DIA5MUX = "DIA5"; - parameter DIA4MUX = "DIA4"; - parameter DIA3MUX = "DIA3"; - parameter DIA2MUX = "DIA2"; - parameter DIA1MUX = "DIA1"; - parameter DIA0MUX = "DIA0"; - parameter ADA13MUX = "ADA13"; - parameter ADA12MUX = "ADA12"; - parameter ADA11MUX = "ADA11"; - parameter ADA10MUX = "ADA10"; - parameter ADA9MUX = "ADA9"; - parameter ADA8MUX = "ADA8"; - parameter ADA7MUX = "ADA7"; - parameter ADA6MUX = "ADA6"; - parameter ADA5MUX = "ADA5"; - parameter ADA4MUX = "ADA4"; - parameter ADA3MUX = "ADA3"; - parameter ADA2MUX = "ADA2"; - parameter ADA1MUX = "ADA1"; - parameter ADA0MUX = "ADA0"; - parameter CEAMUX = "CEA"; - parameter OCEAMUX = "OCEA"; - parameter CLKAMUX = "CLKA"; - parameter WEAMUX = "WEA"; - parameter RSTAMUX = "RSTA"; - parameter CSA2MUX = "CSA2"; - parameter CSA1MUX = "CSA1"; - parameter CSA0MUX = "CSA0"; - parameter DOA17MUX = "DOA17"; - parameter DOA16MUX = "DOA16"; - parameter DOA15MUX = "DOA15"; - parameter DOA14MUX = "DOA14"; - parameter DOA13MUX = "DOA13"; - parameter DOA12MUX = "DOA12"; - parameter DOA11MUX = "DOA11"; - parameter DOA10MUX = "DOA10"; - parameter DOA9MUX = "DOA9"; - parameter DOA8MUX = "DOA8"; - parameter DOA7MUX = "DOA7"; - parameter DOA6MUX = "DOA6"; - parameter DOA5MUX = "DOA5"; - parameter DOA4MUX = "DOA4"; - parameter DOA3MUX = "DOA3"; - parameter DOA2MUX = "DOA2"; - parameter DOA1MUX = "DOA1"; - parameter DOA0MUX = "DOA0"; - parameter DIB17MUX = "DIB17"; - parameter DIB16MUX = "DIB16"; - parameter DIB15MUX = "DIB15"; - parameter DIB14MUX = "DIB14"; - parameter DIB13MUX = "DIB13"; - parameter DIB12MUX = "DIB12"; - parameter DIB11MUX = "DIB11"; - parameter DIB10MUX = "DIB10"; - parameter DIB9MUX = "DIB9"; - parameter DIB8MUX = "DIB8"; - parameter DIB7MUX = "DIB7"; - parameter DIB6MUX = "DIB6"; - parameter DIB5MUX = "DIB5"; - parameter DIB4MUX = "DIB4"; - parameter DIB3MUX = "DIB3"; - parameter DIB2MUX = "DIB2"; - parameter DIB1MUX = "DIB1"; - parameter DIB0MUX = "DIB0"; - parameter ADB13MUX = "ADB13"; - parameter ADB12MUX = "ADB12"; - parameter ADB11MUX = "ADB11"; - parameter ADB10MUX = "ADB10"; - parameter ADB9MUX = "ADB9"; - parameter ADB8MUX = "ADB8"; - parameter ADB7MUX = "ADB7"; - parameter ADB6MUX = "ADB6"; - parameter ADB5MUX = "ADB5"; - parameter ADB4MUX = "ADB4"; - parameter ADB3MUX = "ADB3"; - parameter ADB2MUX = "ADB2"; - parameter ADB1MUX = "ADB1"; - parameter ADB0MUX = "ADB0"; - parameter CEBMUX = "CEB"; - parameter OCEBMUX = "OCEB"; - parameter CLKBMUX = "CLKB"; - parameter WEBMUX = "WEB"; - parameter RSTBMUX = "RSTB"; - parameter CSB2MUX = "CSB2"; - parameter CSB1MUX = "CSB1"; - parameter CSB0MUX = "CSB0"; - parameter DOB17MUX = "DOB17"; - parameter DOB16MUX = "DOB16"; - parameter DOB15MUX = "DOB15"; - parameter DOB14MUX = "DOB14"; - parameter DOB13MUX = "DOB13"; - parameter DOB12MUX = "DOB12"; - parameter DOB11MUX = "DOB11"; - parameter DOB10MUX = "DOB10"; - parameter DOB9MUX = "DOB9"; - parameter DOB8MUX = "DOB8"; - parameter DOB7MUX = "DOB7"; - parameter DOB6MUX = "DOB6"; - parameter DOB5MUX = "DOB5"; - parameter DOB4MUX = "DOB4"; - parameter DOB3MUX = "DOB3"; - parameter DOB2MUX = "DOB2"; - parameter DOB1MUX = "DOB1"; - parameter DOB0MUX = "DOB0"; - - parameter WID = 0; - - parameter GSR = "ENABLED"; - - parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INIT_DATA = "STATIC"; -endmodule - -`ifndef NO_INCLUDES - -`include "cells_ff.vh" -`include "cells_io.vh" - -`endif diff --git a/techlibs/ecp5/dsp_map.v b/techlibs/ecp5/dsp_map.v deleted file mode 100644 index df54d1d9f..000000000 --- a/techlibs/ecp5/dsp_map.v +++ /dev/null @@ -1,17 +0,0 @@ -module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); - - parameter A_WIDTH = 18; - parameter B_WIDTH = 18; - parameter Y_WIDTH = 36; - parameter A_SIGNED = 0; - parameter B_SIGNED = 0; - - MULT18X18D _TECHMAP_REPLACE_ ( - .A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .A4(A[4]), .A5(A[5]), .A6(A[6]), .A7(A[7]), .A8(A[8]), .A9(A[9]), .A10(A[10]), .A11(A[11]), .A12(A[12]), .A13(A[13]), .A14(A[14]), .A15(A[15]), .A16(A[16]), .A17(A[17]), - .B0(B[0]), .B1(B[1]), .B2(B[2]), .B3(B[3]), .B4(B[4]), .B5(B[5]), .B6(B[6]), .B7(B[7]), .B8(B[8]), .B9(B[9]), .B10(B[10]), .B11(B[11]), .B12(B[12]), .B13(B[13]), .B14(B[14]), .B15(B[15]), .B16(B[16]), .B17(B[17]), - .C17(1'b0), .C16(1'b0), .C15(1'b0), .C14(1'b0), .C13(1'b0), .C12(1'b0), .C11(1'b0), .C10(1'b0), .C9(1'b0), .C8(1'b0), .C7(1'b0), .C6(1'b0), .C5(1'b0), .C4(1'b0), .C3(1'b0), .C2(1'b0), .C1(1'b0), .C0(1'b0), - .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), .SOURCEA(1'b0), .SOURCEB(1'b0), - - .P0(Y[0]), .P1(Y[1]), .P2(Y[2]), .P3(Y[3]), .P4(Y[4]), .P5(Y[5]), .P6(Y[6]), .P7(Y[7]), .P8(Y[8]), .P9(Y[9]), .P10(Y[10]), .P11(Y[11]), .P12(Y[12]), .P13(Y[13]), .P14(Y[14]), .P15(Y[15]), .P16(Y[16]), .P17(Y[17]), .P18(Y[18]), .P19(Y[19]), .P20(Y[20]), .P21(Y[21]), .P22(Y[22]), .P23(Y[23]), .P24(Y[24]), .P25(Y[25]), .P26(Y[26]), .P27(Y[27]), .P28(Y[28]), .P29(Y[29]), .P30(Y[30]), .P31(Y[31]), .P32(Y[32]), .P33(Y[33]), .P34(Y[34]), .P35(Y[35]) - ); -endmodule diff --git a/techlibs/ecp5/latches_map.v b/techlibs/ecp5/latches_map.v deleted file mode 100644 index c28f88cf7..000000000 --- a/techlibs/ecp5/latches_map.v +++ /dev/null @@ -1,11 +0,0 @@ -module \$_DLATCH_N_ (E, D, Q); - wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; - input E, D; - output Q = !E ? D : Q; -endmodule - -module \$_DLATCH_P_ (E, D, Q); - wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; - input E, D; - output Q = E ? D : Q; -endmodule diff --git a/techlibs/ecp5/lutrams.txt b/techlibs/ecp5/lutrams.txt deleted file mode 100644 index ea42d4fcb..000000000 --- a/techlibs/ecp5/lutrams.txt +++ /dev/null @@ -1,12 +0,0 @@ -ram distributed $__TRELLIS_DPR16X4_ { - abits 4; - width 4; - cost 4; - init any; - prune_rom; - port sw "W" { - clock anyedge; - } - port ar "R" { - } -} diff --git a/techlibs/ecp5/lutrams_map.v b/techlibs/ecp5/lutrams_map.v deleted file mode 100644 index 3cb325f04..000000000 --- a/techlibs/ecp5/lutrams_map.v +++ /dev/null @@ -1,30 +0,0 @@ -module $__TRELLIS_DPR16X4_(...); - -parameter INIT = 64'bx; -parameter PORT_W_CLK_POL = 1; - -input PORT_W_CLK; -input [3:0] PORT_W_ADDR; -input [3:0] PORT_W_WR_DATA; -input PORT_W_WR_EN; - -input [3:0] PORT_R_ADDR; -output [3:0] PORT_R_RD_DATA; - -localparam WCKMUX = PORT_W_CLK_POL ? "WCK" : "INV"; - -TRELLIS_DPR16X4 #( - .INITVAL(INIT), - .WCKMUX(WCKMUX), - .WREMUX("WRE") -) _TECHMAP_REPLACE_ ( - .RAD(PORT_R_ADDR), - .DO(PORT_R_RD_DATA), - - .WAD(PORT_W_ADDR), - .DI(PORT_W_WR_DATA), - .WCK(PORT_W_CLK), - .WRE(PORT_W_WR_EN) -); - -endmodule diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc deleted file mode 100644 index 8960df70c..000000000 --- a/techlibs/ecp5/synth_ecp5.cc +++ /dev/null @@ -1,457 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * Copyright (C) 2018 gatecat - * - * 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/register.h" -#include "kernel/celltypes.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct SynthEcp5Pass : public ScriptPass -{ - SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { } - - void on_register() override - { - RTLIL::constpad["synth_ecp5.abc9.W"] = "300"; - } - - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" synth_ecp5 [options]\n"); - log("\n"); - log("This command runs synthesis for ECP5 FPGAs.\n"); - log("\n"); - log(" -top \n"); - log(" use the specified module as top module\n"); - log("\n"); - log(" -blif \n"); - log(" write the design to the specified BLIF file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -edif \n"); - log(" write the design to the specified EDIF file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -json \n"); - log(" write the design to the specified JSON file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -run :\n"); - log(" only run the commands between the labels (see below). an empty\n"); - log(" from label is synonymous to 'begin', and empty to label is\n"); - log(" synonymous to the end of the command list.\n"); - log("\n"); - log(" -noflatten\n"); - log(" do not flatten design before synthesis\n"); - log("\n"); - log(" -dff\n"); - log(" run 'abc'/'abc9' with -dff option\n"); - log("\n"); - log(" -retime\n"); - log(" run 'abc' with '-dff -D 1' options\n"); - log("\n"); - log(" -noccu2\n"); - log(" do not use CCU2 cells in output netlist\n"); - log("\n"); - log(" -nodffe\n"); - log(" do not use flipflops with CE in output netlist\n"); - log("\n"); - log(" -nobram\n"); - log(" do not use block RAM cells in output netlist\n"); - log("\n"); - log(" -nolutram\n"); - log(" do not use LUT RAM cells in output netlist\n"); - log("\n"); - log(" -nowidelut\n"); - log(" do not use PFU muxes to implement LUTs larger than LUT4s\n"); - log("\n"); - log(" -asyncprld\n"); - log(" use async PRLD mode to implement ALDFF (EXPERIMENTAL)\n"); - log("\n"); - log(" -abc2\n"); - log(" run two passes of 'abc' for slightly improved logic density\n"); - log("\n"); - log(" -noabc9\n"); - log(" disable use of new ABC9 flow\n"); - log("\n"); - log(" -vpr\n"); - log(" generate an output netlist (and BLIF file) suitable for VPR\n"); - log(" (this feature is experimental and incomplete)\n"); - log("\n"); - log(" -iopad\n"); - log(" insert IO buffers\n"); - log("\n"); - log(" -nodsp\n"); - log(" do not map multipliers to MULT18X18D\n"); - log("\n"); - log(" -no-rw-check\n"); - log(" marks all recognized read ports as \"return don't-care value on\n"); - log(" read/write collision\" (same result as setting the no_rw_check\n"); - log(" attribute on all memories).\n"); - log("\n"); - log("\n"); - log("The following commands are executed by this synthesis command:\n"); - help_script(); - log("\n"); - } - - string top_opt, blif_file, edif_file, json_file; - bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, retime, abc2, abc9, iopad, nodsp, vpr, no_rw_check; - - void clear_flags() override - { - top_opt = "-auto-top"; - blif_file = ""; - edif_file = ""; - json_file = ""; - noccu2 = false; - nodffe = false; - nobram = false; - nolutram = false; - nowidelut = false; - asyncprld = false; - flatten = true; - dff = false; - retime = false; - abc2 = false; - vpr = false; - abc9 = true; - iopad = false; - nodsp = false; - no_rw_check = false; - } - - void execute(std::vector args, RTLIL::Design *design) override - { - string run_from, run_to; - clear_flags(); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_opt = "-top " + args[++argidx]; - continue; - } - if (args[argidx] == "-blif" && argidx+1 < args.size()) { - blif_file = args[++argidx]; - continue; - } - if (args[argidx] == "-edif" && argidx+1 < args.size()) { - edif_file = args[++argidx]; - continue; - } - if (args[argidx] == "-json" && argidx+1 < args.size()) { - json_file = args[++argidx]; - continue; - } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); - if (pos == std::string::npos) - break; - run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); - continue; - } - if (args[argidx] == "-flatten") { - flatten = true; - continue; - } - if (args[argidx] == "-noflatten") { - flatten = false; - continue; - } - if (args[argidx] == "-dff") { - dff = true; - continue; - } - if (args[argidx] == "-retime") { - retime = true; - continue; - } - if (args[argidx] == "-noccu2") { - noccu2 = true; - continue; - } - if (args[argidx] == "-nodffe") { - nodffe = true; - continue; - } - if (args[argidx] == "-nobram") { - nobram = true; - continue; - } - if (args[argidx] == "-asyncprld") { - asyncprld = true; - continue; - } - if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") { - nolutram = true; - continue; - } - if (args[argidx] == "-nowidelut" || /*deprecated alias*/ args[argidx] == "-nomux") { - nowidelut = true; - continue; - } - if (args[argidx] == "-abc2") { - abc2 = true; - continue; - } - if (args[argidx] == "-vpr") { - vpr = true; - continue; - } - if (args[argidx] == "-abc9") { - // removed, ABC9 is on by default. - continue; - } - if (args[argidx] == "-noabc9") { - abc9 = false; - continue; - } - if (args[argidx] == "-iopad") { - iopad = true; - continue; - } - if (args[argidx] == "-nodsp") { - nodsp = true; - continue; - } - if (args[argidx] == "-no-rw-check") { - no_rw_check = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - if (!design->full_selection()) - log_cmd_error("This command only operates on fully selected designs!\n"); - - if (abc9 && retime) - log_cmd_error("-retime option not currently compatible with -abc9!\n"); - - log_header(design, "Executing SYNTH_ECP5 pass.\n"); - log_push(); - - run_script(design, run_from, run_to); - - log_pop(); - } - - void script() override - { - std::string no_rw_check_opt = ""; - if (no_rw_check) - no_rw_check_opt = " -no-rw-check"; - if (help_mode) - no_rw_check_opt = " [-no-rw-check]"; - - if (check_label("begin")) - { - run("read_verilog -lib -specify +/ecp5/cells_sim.v +/ecp5/cells_bb.v"); - run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt)); - } - - if (check_label("coarse")) - { - run("proc"); - if (flatten || help_mode) - run("flatten"); - run("tribuf -logic"); - run("deminout"); - run("opt_expr"); - run("opt_clean"); - run("check"); - run("opt -nodffe -nosdff"); - run("fsm"); - run("opt"); - run("wreduce"); - run("peepopt"); - run("opt_clean"); - run("share"); - run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); - run("opt_expr"); - run("opt_clean"); - if (!nodsp) { - run("techmap -map +/mul2dsp.v -map +/ecp5/dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=$__MUL18X18", "(unless -nodsp)"); - run("chtype -set $mul t:$__soft_mul", "(unless -nodsp)"); - } - run("alumacc"); - run("opt"); - run("memory -nomap" + no_rw_check_opt); - run("opt_clean"); - } - - if (check_label("map_ram")) - { - std::string args = ""; - if (help_mode) - args += " [-no-auto-block] [-no-auto-distributed]"; - else { - if (nobram) - args += " -no-auto-block"; - if (nolutram) - args += " -no-auto-distributed"; - } - run("memory_libmap -lib +/ecp5/lutrams.txt -lib +/ecp5/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); - run("techmap -map +/ecp5/lutrams_map.v -map +/ecp5/brams_map.v"); - } - - if (check_label("map_ffram")) - { - run("opt -fast -mux_undef -undriven -fine"); - run("memory_map"); - run("opt -undriven -fine"); - } - - if (check_label("map_gates")) - { - if (noccu2) - run("techmap"); - else - run("techmap -map +/techmap.v -map +/ecp5/arith_map.v"); - if (help_mode || iopad) { - run("iopadmap -bits -outpad OB I:O -inpad IB O:I -toutpad OBZ ~T:I:O -tinoutpad BB ~T:O:I:B A:top", "(only if '-iopad')"); - run("attrmvcp -attr src -attr LOC t:OB %x:+[O] t:OBZ %x:+[O] t:BB %x:+[B]"); - run("attrmvcp -attr src -attr LOC -driven t:IB %x:+[I]"); - } - run("opt -fast"); - if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); - } - - if (check_label("map_ffs")) - { - run("opt_clean"); - std::string dfflegalize_args = " -cell $_DFF_?_ 01 -cell $_DFF_?P?_ r -cell $_SDFF_?P?_ r"; - if (help_mode) { - dfflegalize_args += " [-cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r]"; - } else if (!nodffe) { - dfflegalize_args += " -cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r"; - } - if (help_mode) { - dfflegalize_args += " [-cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x] [-cell $_DLATCH_?_ x]"; - } else if (asyncprld) { - dfflegalize_args += " -cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x"; - } else { - dfflegalize_args += " -cell $_DLATCH_?_ x"; - } - run("dfflegalize" + dfflegalize_args, "($_ALDFF_*_ only if -asyncprld, $_DLATCH_* only if not -asyncprld, $_*DFFE_* only if not -nodffe)"); - if ((abc9 && dff) || help_mode) - run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff)"); - run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); - run("opt_expr -undriven -mux_undef"); - run("simplemap"); - run("lattice_gsr"); - run("attrmvcp -copy -attr syn_useioff"); - run("opt_clean"); - } - - if (check_label("map_luts")) - { - if (abc2 || help_mode) - run("abc", " (only if -abc2)"); - if (!asyncprld || help_mode) - run("techmap -map +/ecp5/latches_map.v", "(skip if -asyncprld)"); - - if (abc9) { - std::string abc9_opts; - if (nowidelut) - abc9_opts += " -maxlut 4"; - std::string k = "synth_ecp5.abc9.W"; - if (active_design && active_design->scratchpad.count(k)) - abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k)); - else - abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k)); - if (nowidelut) - abc9_opts += " -maxlut 4"; - if (dff) - abc9_opts += " -dff"; - run("abc9" + abc9_opts); - } else { - std::string abc_args = " -dress"; - if (nowidelut) - abc_args += " -lut 4"; - else - abc_args += " -lut 4:7"; - if (dff) - abc_args += " -dff"; - run("abc" + abc_args); - } - run("clean"); - } - - if (check_label("map_cells")) - { - if (help_mode) - run("techmap -map +/ecp5/cells_map.v", "(skip if -vpr)"); - else if (!vpr) - run("techmap -map +/ecp5/cells_map.v"); - run("opt_lut_ins -tech lattice"); - run("clean"); - } - - if (check_label("check")) - { - run("autoname"); - run("hierarchy -check"); - run("stat"); - run("check -noinit"); - run("blackbox =A:whitebox"); - } - - if (check_label("blif")) - { - if (!blif_file.empty() || help_mode) { - if (vpr || help_mode) { - run(stringf("opt_clean -purge"), - " (vpr mode)"); - run(stringf("write_blif -attr -cname -conn -param %s", - help_mode ? "" : blif_file.c_str()), - " (vpr mode)"); - } - if (!vpr) - run(stringf("write_blif -gates -attr -param %s", - help_mode ? "" : blif_file.c_str()), - " (non-vpr mode)"); - } - } - - if (check_label("edif")) - { - if (!edif_file.empty() || help_mode) - run(stringf("write_edif %s", help_mode ? "" : edif_file)); - } - - if (check_label("json")) - { - if (!json_file.empty() || help_mode) - run(stringf("write_json %s", help_mode ? "" : json_file)); - } - } -} SynthEcp5Pass; - -PRIVATE_NAMESPACE_END diff --git a/techlibs/lattice/common_sim.vh b/techlibs/lattice/common_sim.vh index 2f8e1db1a..fe479cc5a 100644 --- a/techlibs/lattice/common_sim.vh +++ b/techlibs/lattice/common_sim.vh @@ -324,7 +324,7 @@ module TRELLIS_IO( ); parameter DIR = "INPUT"; reg T_pd; - always @(*) if (T === 1'bz) T_pd <= 1'b0; else T_pd <= T; + always @(*) if (T === 1'bz) T_pd = 1'b0; else T_pd = T; generate if (DIR == "INPUT") begin From 4a7f94f1c16cc70fdc1b47b95c9735002f1a22fe Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 28 Aug 2023 16:50:25 +0200 Subject: [PATCH 09/49] Enable synth_ecp5 wrapper and copy sim files for backwards compatibility --- Makefile | 7 +++++++ techlibs/lattice/Makefile.inc | 8 ++++++++ techlibs/lattice/synth_lattice.cc | 2 -- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 02f8fa0e9..6a0c1d058 100644 --- a/Makefile +++ b/Makefile @@ -561,6 +561,13 @@ $(subst //,/,$(1)/$(notdir $(2))): $(2) $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(notdir $(2))) endef +define add_share_file_and_rename +EXTRA_TARGETS += $(subst //,/,$(1)/$(3)) +$(subst //,/,$(1)/$(3)): $(2) + $$(P) mkdir -p $(1) + $$(Q) cp "$(YOSYS_SRC)"/$(2) $(subst //,/,$(1)/$(3)) +endef + define add_gen_share_file EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) $(subst //,/,$(1)/$(notdir $(2))): $(2) diff --git a/techlibs/lattice/Makefile.inc b/techlibs/lattice/Makefile.inc index fd9ec2ed5..7cb034f4e 100644 --- a/techlibs/lattice/Makefile.inc +++ b/techlibs/lattice/Makefile.inc @@ -26,3 +26,11 @@ $(eval $(call add_share_file,share/lattice,techlibs/lattice/arith_map_ccu2c.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/arith_map_ccu2d.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/latches_map.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/dsp_map_18x18.v)) + + +$(eval $(call add_share_file,share/ecp5,techlibs/lattice/cells_ff.vh)) +$(eval $(call add_share_file,share/ecp5,techlibs/lattice/cells_io.vh)) +$(eval $(call add_share_file,share/ecp5,techlibs/lattice/common_sim.vh)) +$(eval $(call add_share_file,share/ecp5,techlibs/lattice/ccu2c_sim.vh)) +$(eval $(call add_share_file_and_rename,share/ecp5,techlibs/lattice/cells_sim_ecp5.v,cells_sim.v)) +$(eval $(call add_share_file_and_rename,share/ecp5,techlibs/lattice/cells_bb_ecp5.v,cells_bb.v)) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index b13c22518..f08970118 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -500,7 +500,6 @@ struct SynthLatticePass : public ScriptPass } } SynthLatticePass; -/* struct SynthEcp5Pass : public Pass { SynthEcp5Pass() : Pass("synth_ecp5", "synthesis for ECP5 FPGAs") { } @@ -515,6 +514,5 @@ struct SynthEcp5Pass : public Pass Pass::call(design, args); } } SynthEcp5Pass; -*/ PRIVATE_NAMESPACE_END From 47a2215fe03663b955cd4337d5bfa2dfac51deab Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 29 Aug 2023 12:32:19 +0200 Subject: [PATCH 10/49] Update filenames and location for test script --- techlibs/lattice/tests/test_diamond_ffs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/lattice/tests/test_diamond_ffs.py b/techlibs/lattice/tests/test_diamond_ffs.py index 1ed85ce8b..8243b55da 100644 --- a/techlibs/lattice/tests/test_diamond_ffs.py +++ b/techlibs/lattice/tests/test_diamond_ffs.py @@ -77,6 +77,6 @@ end print(" endtask", file=f) print("endmodule", file=f) -diamond_models = "/usr/local/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u" -subprocess.call(["iverilog", "-s", "testbench", "-o", "work_ff/testbench", "-Dmixed_hdl", "-DNO_INCLUDES", "-y", diamond_models, "work_ff/cells_ff_gate.v", "../cells_sim.v", "work_ff/testbench.v"]) +diamond_models = "/usr/local/diamond/3.12/cae_library/simulation/verilog/ecp5u" +subprocess.call(["iverilog", "-s", "testbench", "-o", "work_ff/testbench", "-Dmixed_hdl", "-DNO_INCLUDES", "-I..", "-y", diamond_models, "work_ff/cells_ff_gate.v", "../cells_sim_ecp5.v", "work_ff/testbench.v"]) subprocess.call(["vvp", "work_ff/testbench"]) From faf82a5ff5cadefc79c1ca7c6811f2ebbccba0af Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 29 Aug 2023 13:12:44 +0200 Subject: [PATCH 11/49] Add help message for synth_ecp5 --- techlibs/lattice/synth_lattice.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index f08970118..15524608b 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -504,6 +504,18 @@ struct SynthEcp5Pass : public Pass { SynthEcp5Pass() : Pass("synth_ecp5", "synthesis for ECP5 FPGAs") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_ecp5 [options]\n"); + log("\n"); + log("This command runs synthesis for ECP5 FPGAs.\n"); + log("\n"); + log("This is wrapper pass, for details take a look at help message for synth_lattice.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override { args[0] = "synth_lattice"; From 4b9e4bfae92d43c0c9392d9601aa84d0894c7381 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Mon, 13 Nov 2023 17:06:39 +0100 Subject: [PATCH 12/49] Update techlibs/lattice/synth_lattice.cc Co-authored-by: Lofty --- techlibs/lattice/synth_lattice.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index 15524608b..15ab686a6 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -512,7 +512,7 @@ struct SynthEcp5Pass : public Pass log("\n"); log("This command runs synthesis for ECP5 FPGAs.\n"); log("\n"); - log("This is wrapper pass, for details take a look at help message for synth_lattice.\n"); + log("This is a wrapper pass, for details take a look at help message for synth_lattice.\n"); log("\n"); } From 58f9531bfbcd7ee643f0ae954fecdaac3f461734 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 14 Nov 2023 12:23:53 +0100 Subject: [PATCH 13/49] enable ABC9 by default except for XO2/3/3D --- techlibs/lattice/synth_lattice.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index 15ab686a6..8edd9096e 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -113,8 +113,8 @@ struct SynthLatticePass : public ScriptPass log(" -abc2\n"); log(" run two passes of 'abc' for slightly improved logic density\n"); log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log(" -noabc9\n"); + log(" disable use of new ABC9 flow\n"); log("\n"); log(" -iopad\n"); log(" insert IO buffers\n"); @@ -158,7 +158,7 @@ struct SynthLatticePass : public ScriptPass dff = false; retime = false; abc2 = false; - abc9 = false; + abc9 = true; iopad = false; nodsp = false; no_rw_check = false; @@ -173,6 +173,7 @@ struct SynthLatticePass : public ScriptPass void execute(std::vector args, RTLIL::Design *design) override { string run_from, run_to; + bool force_abc9 = false; bool force_widelut = false; clear_flags(); @@ -254,7 +255,13 @@ struct SynthLatticePass : public ScriptPass continue; } if (args[argidx] == "-abc9") { - abc9 = true; + // removed, ABC9 is on by default. + force_abc9 = true; + continue; + } + if (args[argidx] == "-noabc9") { + force_abc9 = true; + abc9 = false; continue; } if (args[argidx] == "-iopad") { @@ -295,6 +302,7 @@ struct SynthLatticePass : public ScriptPass brams_map = "_8kc"; have_dsp = false; if (!force_widelut) nowidelut = true; + if (!force_abc9) abc9 = false; /* } else if (family == "xo" || family == "pm") { } else if (family == "xp" || From 714603bf69e68273b005bc868f30d05c1740ccb0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 31 Aug 2023 13:17:21 +0200 Subject: [PATCH 14/49] synth_nexus to synth_lattice --- techlibs/lattice/Makefile.inc | 22 +- .../arith_map.v => lattice/arith_map_nexus.v} | 0 .../brams_map.v => lattice/brams_map_nexus.v} | 0 .../brams.txt => lattice/brams_nexus.txt} | 0 .../cells_xtra.v => lattice/cells_bb_nexus.v} | 0 .../cells_map.v => lattice/cells_map_nexus.v} | 0 .../{cells_map.v => cells_map_trellis.v} | 0 .../cells_sim.v => lattice/cells_sim_nexus.v} | 0 .../cells_xtra_nexus.py} | 4 +- .../dsp_map.v => lattice/dsp_map_nexus.v} | 0 .../lrams_map.v => lattice/lrams_map_nexus.v} | 0 .../lrams.txt => lattice/lrams_nexus.txt} | 0 .../lutrams_map_nexus.v} | 0 .../{lutrams_map.v => lutrams_map_trellis.v} | 0 .../lutrams.txt => lattice/lutrams_nexus.txt} | 0 .../{lutrams.txt => lutrams_trellis.txt} | 0 techlibs/{nexus => lattice}/parse_init.vh | 0 techlibs/lattice/synth_lattice.cc | 163 +++++-- techlibs/nexus/Makefile.inc | 16 - techlibs/nexus/latches_map.v | 11 - techlibs/nexus/synth_nexus.cc | 419 ------------------ 21 files changed, 158 insertions(+), 477 deletions(-) rename techlibs/{nexus/arith_map.v => lattice/arith_map_nexus.v} (100%) rename techlibs/{nexus/brams_map.v => lattice/brams_map_nexus.v} (100%) rename techlibs/{nexus/brams.txt => lattice/brams_nexus.txt} (100%) rename techlibs/{nexus/cells_xtra.v => lattice/cells_bb_nexus.v} (100%) rename techlibs/{nexus/cells_map.v => lattice/cells_map_nexus.v} (100%) rename techlibs/lattice/{cells_map.v => cells_map_trellis.v} (100%) rename techlibs/{nexus/cells_sim.v => lattice/cells_sim_nexus.v} (100%) rename techlibs/{nexus/cells_xtra.py => lattice/cells_xtra_nexus.py} (98%) rename techlibs/{nexus/dsp_map.v => lattice/dsp_map_nexus.v} (100%) rename techlibs/{nexus/lrams_map.v => lattice/lrams_map_nexus.v} (100%) rename techlibs/{nexus/lrams.txt => lattice/lrams_nexus.txt} (100%) rename techlibs/{nexus/lutrams_map.v => lattice/lutrams_map_nexus.v} (100%) rename techlibs/lattice/{lutrams_map.v => lutrams_map_trellis.v} (100%) rename techlibs/{nexus/lutrams.txt => lattice/lutrams_nexus.txt} (100%) rename techlibs/lattice/{lutrams.txt => lutrams_trellis.txt} (100%) rename techlibs/{nexus => lattice}/parse_init.vh (100%) delete mode 100644 techlibs/nexus/Makefile.inc delete mode 100644 techlibs/nexus/latches_map.v delete mode 100644 techlibs/nexus/synth_nexus.cc diff --git a/techlibs/lattice/Makefile.inc b/techlibs/lattice/Makefile.inc index 7cb034f4e..9084472cf 100644 --- a/techlibs/lattice/Makefile.inc +++ b/techlibs/lattice/Makefile.inc @@ -4,28 +4,40 @@ OBJS += techlibs/lattice/lattice_gsr.o $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_ff.vh)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_io.vh)) -$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_map.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_map_trellis.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_map_nexus.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/common_sim.vh)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/parse_init.vh)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/ccu2d_sim.vh)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/ccu2c_sim.vh)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_ecp5.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_xo2.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_xo3.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_xo3d.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_nexus.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_ecp5.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo2.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo3.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo3d.v)) -$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams_map.v)) -$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams.txt)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_nexus.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams_map_trellis.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams_trellis.txt)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams_map_nexus.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams_nexus.txt)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lrams_map_nexus.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lrams_nexus.txt)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_map_16kd.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_16kd.txt)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_map_8kc.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_8kc.txt)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_map_nexus.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_nexus.txt)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/arith_map_ccu2c.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/arith_map_ccu2d.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/arith_map_nexus.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/latches_map.v)) $(eval $(call add_share_file,share/lattice,techlibs/lattice/dsp_map_18x18.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/dsp_map_nexus.v)) $(eval $(call add_share_file,share/ecp5,techlibs/lattice/cells_ff.vh)) @@ -34,3 +46,7 @@ $(eval $(call add_share_file,share/ecp5,techlibs/lattice/common_sim.vh)) $(eval $(call add_share_file,share/ecp5,techlibs/lattice/ccu2c_sim.vh)) $(eval $(call add_share_file_and_rename,share/ecp5,techlibs/lattice/cells_sim_ecp5.v,cells_sim.v)) $(eval $(call add_share_file_and_rename,share/ecp5,techlibs/lattice/cells_bb_ecp5.v,cells_bb.v)) + +$(eval $(call add_share_file,share/nexus,techlibs/lattice/parse_init.vh)) +$(eval $(call add_share_file_and_rename,share/nexus,techlibs/lattice/cells_sim_nexus.v,cells_sim.v)) +$(eval $(call add_share_file_and_rename,share/nexus,techlibs/lattice/cells_bb_nexus.v,cells_xtra.v)) diff --git a/techlibs/nexus/arith_map.v b/techlibs/lattice/arith_map_nexus.v similarity index 100% rename from techlibs/nexus/arith_map.v rename to techlibs/lattice/arith_map_nexus.v diff --git a/techlibs/nexus/brams_map.v b/techlibs/lattice/brams_map_nexus.v similarity index 100% rename from techlibs/nexus/brams_map.v rename to techlibs/lattice/brams_map_nexus.v diff --git a/techlibs/nexus/brams.txt b/techlibs/lattice/brams_nexus.txt similarity index 100% rename from techlibs/nexus/brams.txt rename to techlibs/lattice/brams_nexus.txt diff --git a/techlibs/nexus/cells_xtra.v b/techlibs/lattice/cells_bb_nexus.v similarity index 100% rename from techlibs/nexus/cells_xtra.v rename to techlibs/lattice/cells_bb_nexus.v diff --git a/techlibs/nexus/cells_map.v b/techlibs/lattice/cells_map_nexus.v similarity index 100% rename from techlibs/nexus/cells_map.v rename to techlibs/lattice/cells_map_nexus.v diff --git a/techlibs/lattice/cells_map.v b/techlibs/lattice/cells_map_trellis.v similarity index 100% rename from techlibs/lattice/cells_map.v rename to techlibs/lattice/cells_map_trellis.v diff --git a/techlibs/nexus/cells_sim.v b/techlibs/lattice/cells_sim_nexus.v similarity index 100% rename from techlibs/nexus/cells_sim.v rename to techlibs/lattice/cells_sim_nexus.v diff --git a/techlibs/nexus/cells_xtra.py b/techlibs/lattice/cells_xtra_nexus.py similarity index 98% rename from techlibs/nexus/cells_xtra.py rename to techlibs/lattice/cells_xtra_nexus.py index 6ced76950..c7be64cef 100644 --- a/techlibs/nexus/cells_xtra.py +++ b/techlibs/lattice/cells_xtra_nexus.py @@ -280,7 +280,7 @@ if __name__ == '__main__': for device, cells in devices: xtract_cells_decl(device, cells, dirs, out) - with open('cells_xtra.v', 'w') as f: - f.write('// Created by cells_xtra.py from Lattice models\n') + with open('cells_bb_nexus.v', 'w') as f: + f.write('// Created by cells_xtra_nexus.py from Lattice models\n') f.write('\n') f.write(out.getvalue()) diff --git a/techlibs/nexus/dsp_map.v b/techlibs/lattice/dsp_map_nexus.v similarity index 100% rename from techlibs/nexus/dsp_map.v rename to techlibs/lattice/dsp_map_nexus.v diff --git a/techlibs/nexus/lrams_map.v b/techlibs/lattice/lrams_map_nexus.v similarity index 100% rename from techlibs/nexus/lrams_map.v rename to techlibs/lattice/lrams_map_nexus.v diff --git a/techlibs/nexus/lrams.txt b/techlibs/lattice/lrams_nexus.txt similarity index 100% rename from techlibs/nexus/lrams.txt rename to techlibs/lattice/lrams_nexus.txt diff --git a/techlibs/nexus/lutrams_map.v b/techlibs/lattice/lutrams_map_nexus.v similarity index 100% rename from techlibs/nexus/lutrams_map.v rename to techlibs/lattice/lutrams_map_nexus.v diff --git a/techlibs/lattice/lutrams_map.v b/techlibs/lattice/lutrams_map_trellis.v similarity index 100% rename from techlibs/lattice/lutrams_map.v rename to techlibs/lattice/lutrams_map_trellis.v diff --git a/techlibs/nexus/lutrams.txt b/techlibs/lattice/lutrams_nexus.txt similarity index 100% rename from techlibs/nexus/lutrams.txt rename to techlibs/lattice/lutrams_nexus.txt diff --git a/techlibs/lattice/lutrams.txt b/techlibs/lattice/lutrams_trellis.txt similarity index 100% rename from techlibs/lattice/lutrams.txt rename to techlibs/lattice/lutrams_trellis.txt diff --git a/techlibs/nexus/parse_init.vh b/techlibs/lattice/parse_init.vh similarity index 100% rename from techlibs/nexus/parse_init.vh rename to techlibs/lattice/parse_init.vh diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc index 8edd9096e..744beb650 100644 --- a/techlibs/lattice/synth_lattice.cc +++ b/techlibs/lattice/synth_lattice.cc @@ -35,13 +35,32 @@ struct SynthLatticePass : public ScriptPass RTLIL::constpad["synth_lattice.abc9.W"] = "300"; } + struct DSPRule { + int a_maxwidth; + int b_maxwidth; + int a_minwidth; + int b_minwidth; + std::string prim; + }; + + const std::vector dsp_rules_nexus = { + {36, 36, 22, 22, "$__NX_MUL36X36"}, + {36, 18, 22, 10, "$__NX_MUL36X18"}, + {18, 18, 10, 4, "$__NX_MUL18X18"}, + {18, 18, 4, 10, "$__NX_MUL18X18"}, + { 9, 9, 4, 4, "$__NX_MUL9X9"}, + }; + const std::vector dsp_rules_ecp5 = { + {18, 18, 2, 2, "$__MUL18X18"}, + }; + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" synth_lattice [options]\n"); log("\n"); - log("This command runs synthesis for Lattice FPGAs (excluding iCE40 and Nexus).\n"); + log("This command runs synthesis for Lattice FPGAs (excluding iCE40).\n"); log("\n"); log(" -top \n"); log(" use the specified module as top module\n"); @@ -54,6 +73,8 @@ struct SynthLatticePass : public ScriptPass log(" - xo2: MachXO2\n"); log(" - xo3: MachXO3L/LF\n"); log(" - xo3d: MachXO3D\n"); + log(" - lifcl: CrossLink-NX\n"); + log(" - lfd2nx: Certus-NX\n"); //log(" - xo: MachXO (EXPERIMENTAL)\n"); //log(" - pm: Platform Manager (EXPERIMENTAL)\n"); //log(" - pm2: Platform Manager 2 (EXPERIMENTAL)\n"); @@ -118,9 +139,13 @@ struct SynthLatticePass : public ScriptPass log("\n"); log(" -iopad\n"); log(" insert IO buffers\n"); + log(" (by default enabled on Nexus FPGAs)\n"); + log("\n"); + log(" -noiopad\n"); + log(" do not insert IO buffers\n"); log("\n"); log(" -nodsp\n"); - log(" do not map multipliers to MULT18X18D\n"); + log(" do not infer DSP multipliers\n"); log("\n"); log(" -no-rw-check\n"); log(" marks all recognized read ports as \"return don't-care value on\n"); @@ -140,7 +165,9 @@ struct SynthLatticePass : public ScriptPass string top_opt, edif_file, json_file, family; bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, retime, abc2, abc9, iopad, nodsp, no_rw_check, have_dsp; bool cmp2softlogic; - string postfix, arith_map, brams_map, dsp_map; + string postfix, arith_map, brams_map, dsp_map, cells_map, map_ram_default, widelut_abc; + bool is_nexus; + std::vector dsp_rules; void clear_flags() override { @@ -168,6 +195,10 @@ struct SynthLatticePass : public ScriptPass dsp_map = ""; have_dsp = false; cmp2softlogic = false; + is_nexus = false; + map_ram_default = ""; + cells_map = ""; + widelut_abc = "4:7"; } void execute(std::vector args, RTLIL::Design *design) override @@ -175,6 +206,7 @@ struct SynthLatticePass : public ScriptPass string run_from, run_to; bool force_abc9 = false; bool force_widelut = false; + bool force_iopad = false; clear_flags(); size_t argidx; @@ -266,6 +298,12 @@ struct SynthLatticePass : public ScriptPass } if (args[argidx] == "-iopad") { iopad = true; + force_iopad = true; + continue; + } + if (args[argidx] == "-noiopad") { + iopad = false; + force_iopad = true; continue; } if (args[argidx] == "-nodsp") { @@ -292,7 +330,9 @@ struct SynthLatticePass : public ScriptPass arith_map = "_ccu2c"; brams_map = "_16kd"; dsp_map = "_18x18"; + dsp_rules = dsp_rules_ecp5; have_dsp = true; + cells_map = "_trellis"; } else if (family == "xo2" || family == "xo3" || family == "xo3d" /* || @@ -300,9 +340,24 @@ struct SynthLatticePass : public ScriptPass postfix = "_" + family; arith_map = "_ccu2d"; brams_map = "_8kc"; + cells_map = "_trellis"; have_dsp = false; if (!force_widelut) nowidelut = true; if (!force_abc9) abc9 = false; + } else if (family == "lifcl" || + family == "lfd2nx") { + is_nexus = true; + postfix = "_nexus"; + arith_map = "_nexus"; + brams_map = "_nexus"; + dsp_map = "_nexus"; + dsp_rules = dsp_rules_nexus; + have_dsp = true; + map_ram_default = " -no-auto-huge"; + cells_map = "_nexus"; + widelut_abc = "4:5"; + if (!force_iopad) iopad = true; + if (!force_abc9) abc9 = false; /* } else if (family == "xo" || family == "pm") { } else if (family == "xp" || @@ -366,9 +421,17 @@ struct SynthLatticePass : public ScriptPass run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("opt_expr"); run("opt_clean"); - if (have_dsp && !nodsp) { - run("techmap -map +/mul2dsp.v -map +/lattice/dsp_map" + dsp_map + ".v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=$__MUL18X18", "(unless -nodsp)"); - run("chtype -set $mul t:$__soft_mul", "(unless -nodsp)"); + + if (help_mode) { + run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); + run("techmap -map +/lattice/dsp_map" + dsp_map + ".v", "(unless -nodsp)"); + } else if (have_dsp && !nodsp) { + for (const auto &rule : dsp_rules) { + run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s", + rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim)); + run("chtype -set $mul t:$__soft_mul"); + } + run("techmap -map +/lattice/dsp_map" + dsp_map + ".v"); } if (family == "xo3" || help_mode) run("booth", "(only if '-family xo3')"); @@ -380,7 +443,7 @@ struct SynthLatticePass : public ScriptPass if (check_label("map_ram")) { - std::string args = ""; + std::string args = map_ram_default; if (help_mode) args += " [-no-auto-block] [-no-auto-distributed]"; else { @@ -389,8 +452,13 @@ struct SynthLatticePass : public ScriptPass if (nolutram) args += " -no-auto-distributed"; } - run("memory_libmap -lib +/lattice/lutrams.txt -lib +/lattice/brams" + brams_map + ".txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); - run("techmap -map +/lattice/lutrams_map.v -map +/lattice/brams_map" + brams_map + ".v"); + if (!is_nexus) { + run("memory_libmap -lib +/lattice/lutrams" + cells_map + ".txt -lib +/lattice/brams" + brams_map + ".txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); + run("techmap -map +/lattice/lutrams_map" + cells_map + ".v -map +/lattice/brams_map" + brams_map + ".v"); + } else { + run("memory_libmap -lib +/lattice/lutrams" + cells_map + ".txt -lib +/lattice/brams" + brams_map + ".txt -lib +/lattice/lrams_nexus.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); + run("techmap -map +/lattice/lutrams_map" + cells_map + ".v -map +/lattice/brams_map" + brams_map + ".v -map +/lattice/lrams_map_nexus.v"); + } } if (check_label("map_ffram")) @@ -419,27 +487,37 @@ struct SynthLatticePass : public ScriptPass if (check_label("map_ffs")) { run("opt_clean"); - std::string dfflegalize_args = " -cell $_DFF_?_ 01 -cell $_DFF_?P?_ r -cell $_SDFF_?P?_ r"; - if (help_mode) { - dfflegalize_args += " [-cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r]"; - } else if (!nodffe) { - dfflegalize_args += " -cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r"; - } - if (help_mode) { - dfflegalize_args += " [-cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x] [-cell $_DLATCH_?_ x]"; - } else if (asyncprld) { - dfflegalize_args += " -cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x"; + if (!is_nexus) { + std::string dfflegalize_args = " -cell $_DFF_?_ 01 -cell $_DFF_?P?_ r -cell $_SDFF_?P?_ r"; + if (help_mode) { + dfflegalize_args += " [-cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r]"; + } else if (!nodffe) { + dfflegalize_args += " -cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r"; + } + if (help_mode) { + dfflegalize_args += " [-cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x] [-cell $_DLATCH_?_ x]"; + } else if (asyncprld) { + dfflegalize_args += " -cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x"; + } else { + dfflegalize_args += " -cell $_DLATCH_?_ x"; + } + run("dfflegalize" + dfflegalize_args, "($_ALDFF_*_ only if -asyncprld, $_DLATCH_* only if not -asyncprld, $_*DFFE_* only if not -nodffe)"); } else { - dfflegalize_args += " -cell $_DLATCH_?_ x"; + std::string dfflegalize_args = " -cell $_DFF_P_ 01 -cell $_DFF_PP?_ r -cell $_SDFF_PP?_ r -cell $_DLATCH_?_ x"; + if (help_mode) { + dfflegalize_args += " [-cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r]"; + } else if (!nodffe) { + dfflegalize_args += " -cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r"; + } + run("dfflegalize" + dfflegalize_args, "($_*DFFE_* only if not -nodffe)"); } - run("dfflegalize" + dfflegalize_args, "($_ALDFF_*_ only if -asyncprld, $_DLATCH_* only if not -asyncprld, $_*DFFE_* only if not -nodffe)"); run("opt_merge"); if ((abc9 && dff) || help_mode) run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff)"); - run("techmap -D NO_LUT -map +/lattice/cells_map.v"); + run("techmap -D NO_LUT -map +/lattice/cells_map" + cells_map + ".v"); run("opt_expr -undriven -mux_undef"); run("simplemap"); - run("lattice_gsr"); + if (!is_nexus) run("lattice_gsr"); run("attrmvcp -copy -attr syn_useioff"); run("opt_clean"); } @@ -470,7 +548,7 @@ struct SynthLatticePass : public ScriptPass if (nowidelut) abc_args += " -lut 4"; else - abc_args += " -lut 4:7"; + abc_args += " -lut " + widelut_abc; if (dff) abc_args += " -dff"; run("abc" + abc_args); @@ -480,8 +558,14 @@ struct SynthLatticePass : public ScriptPass if (check_label("map_cells")) { - run("techmap -map +/lattice/cells_map.v"); - run("opt_lut_ins -tech lattice"); + run("techmap -map +/lattice/cells_map" + cells_map + ".v"); + if (is_nexus) { + // This is needed for Radiant, but perhaps not optimal for nextpnr... + run("setundef -zero"); + run("hilomap -singleton -hicell VHI Z -locell VLO Z"); + } else { + run("opt_lut_ins -tech lattice"); + } run("clean"); } @@ -508,6 +592,33 @@ struct SynthLatticePass : public ScriptPass } } SynthLatticePass; +struct SynthNexusPass : public Pass +{ + SynthNexusPass() : Pass("synth_nexus", "synthesis for Nexus FPGAs") { } + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_nexus [options]\n"); + log("\n"); + log("This command runs synthesis for Nexus FPGAs.\n"); + log("\n"); + log("This is a wrapper pass, for details take a look at help message for synth_lattice.\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + args[0] = "synth_lattice"; + args.insert(args.begin()+1, std::string()); + args.insert(args.begin()+1, std::string()); + args[1] = "-family"; + args[2] = "lifcl"; + Pass::call(design, args); + } +} SynthNexusPass; + struct SynthEcp5Pass : public Pass { SynthEcp5Pass() : Pass("synth_ecp5", "synthesis for ECP5 FPGAs") { } diff --git a/techlibs/nexus/Makefile.inc b/techlibs/nexus/Makefile.inc deleted file mode 100644 index 8121d1d8a..000000000 --- a/techlibs/nexus/Makefile.inc +++ /dev/null @@ -1,16 +0,0 @@ -OBJS += techlibs/nexus/synth_nexus.o - -$(eval $(call add_share_file,share/nexus,techlibs/nexus/cells_map.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/cells_sim.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/parse_init.vh)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/cells_xtra.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/lutrams_map.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/lutrams.txt)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/brams_map.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/brams.txt)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/lrams_map.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/lrams.txt)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/arith_map.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/latches_map.v)) -$(eval $(call add_share_file,share/nexus,techlibs/nexus/dsp_map.v)) - diff --git a/techlibs/nexus/latches_map.v b/techlibs/nexus/latches_map.v deleted file mode 100644 index c28f88cf7..000000000 --- a/techlibs/nexus/latches_map.v +++ /dev/null @@ -1,11 +0,0 @@ -module \$_DLATCH_N_ (E, D, Q); - wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; - input E, D; - output Q = !E ? D : Q; -endmodule - -module \$_DLATCH_P_ (E, D, Q); - wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; - input E, D; - output Q = E ? D : Q; -endmodule diff --git a/techlibs/nexus/synth_nexus.cc b/techlibs/nexus/synth_nexus.cc deleted file mode 100644 index c0df06a21..000000000 --- a/techlibs/nexus/synth_nexus.cc +++ /dev/null @@ -1,419 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 gatecat - * - * 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/register.h" -#include "kernel/celltypes.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct SynthNexusPass : public ScriptPass -{ - SynthNexusPass() : ScriptPass("synth_nexus", "synthesis for Lattice Nexus FPGAs") { } - - void on_register() override - { - RTLIL::constpad["synth_nexus.abc9.W"] = "300"; - } - - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" synth_nexus [options]\n"); - log("\n"); - log("This command runs synthesis for Lattice Nexus FPGAs.\n"); - log("\n"); - log(" -top \n"); - log(" use the specified module as top module\n"); - log("\n"); - log(" -family \n"); - log(" run synthesis for the specified Nexus device\n"); - log(" supported values: lifcl, lfd2nx\n"); - log("\n"); - log(" -json \n"); - log(" write the design to the specified JSON file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -vm \n"); - log(" write the design to the specified structural Verilog file. writing of\n"); - log(" an output file is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -run :\n"); - log(" only run the commands between the labels (see below). an empty\n"); - log(" from label is synonymous to 'begin', and empty to label is\n"); - log(" synonymous to the end of the command list.\n"); - log("\n"); - log(" -noflatten\n"); - log(" do not flatten design before synthesis\n"); - log("\n"); - log(" -dff\n"); - log(" run 'abc'/'abc9' with -dff option\n"); - log("\n"); - log(" -retime\n"); - log(" run 'abc' with '-dff -D 1' options\n"); - log("\n"); - log(" -noccu2\n"); - log(" do not use CCU2 cells in output netlist\n"); - log("\n"); - log(" -nodffe\n"); - log(" do not use flipflops with CE in output netlist\n"); - log("\n"); - log(" -nolram\n"); - log(" do not use large RAM cells in output netlist\n"); - log(" note that large RAM must be explicitly requested with a (* lram *)\n"); - log(" attribute on the memory.\n"); - log("\n"); - log(" -nobram\n"); - log(" do not use block RAM cells in output netlist\n"); - log("\n"); - log(" -nolutram\n"); - log(" do not use LUT RAM cells in output netlist\n"); - log("\n"); - log(" -nowidelut\n"); - log(" do not use PFU muxes to implement LUTs larger than LUT4s\n"); - log("\n"); - log(" -noiopad\n"); - log(" do not insert IO buffers\n"); - log("\n"); - log(" -nodsp\n"); - log(" do not infer DSP multipliers\n"); - log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); - log("\n"); - log("The following commands are executed by this synthesis command:\n"); - help_script(); - log("\n"); - } - - string top_opt, json_file, vm_file, family; - bool noccu2, nodffe, nolram, nobram, nolutram, nowidelut, noiopad, nodsp, flatten, dff, retime, abc9; - - void clear_flags() override - { - top_opt = "-auto-top"; - family = "lifcl"; - json_file = ""; - vm_file = ""; - noccu2 = false; - nodffe = false; - nolram = false; - nobram = false; - nolutram = false; - nowidelut = false; - noiopad = false; - nodsp = false; - flatten = true; - dff = false; - retime = false; - } - - void execute(std::vector args, RTLIL::Design *design) override - { - string run_from, run_to; - clear_flags(); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_opt = "-top " + args[++argidx]; - continue; - } - if (args[argidx] == "-json" && argidx+1 < args.size()) { - json_file = args[++argidx]; - continue; - } - if (args[argidx] == "-vm" && argidx+1 < args.size()) { - vm_file = args[++argidx]; - continue; - } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); - if (pos == std::string::npos) - break; - run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); - continue; - } - if ((args[argidx] == "-family") && argidx+1 < args.size()) { - family = args[++argidx]; - continue; - } - if (args[argidx] == "-flatten") { - flatten = true; - continue; - } - if (args[argidx] == "-noflatten") { - flatten = false; - continue; - } - if (args[argidx] == "-dff") { - dff = true; - continue; - } - if (args[argidx] == "-nodsp") { - nodsp = true; - continue; - } - if (args[argidx] == "-retime") { - retime = true; - continue; - } - if (args[argidx] == "-noccu2") { - noccu2 = true; - continue; - } - if (args[argidx] == "-nodffe") { - nodffe = true; - continue; - } - if (args[argidx] == "-nolram") { - nolram = true; - continue; - } - if (args[argidx] == "-nobram") { - nobram = true; - continue; - } - if (args[argidx] == "-nolutram") { - nolutram = true; - continue; - } - if (args[argidx] == "-nowidelut") { - nowidelut = true; - continue; - } - if (args[argidx] == "-noiopad") { - noiopad = true; - continue; - } - if (args[argidx] == "-abc9") { - abc9 = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - if (!design->full_selection()) - log_cmd_error("This command only operates on fully selected designs!\n"); - - if (abc9 && retime) - log_cmd_error("-retime option not currently compatible with -abc9!\n"); - - log_header(design, "Executing SYNTH_NEXUS pass.\n"); - log_push(); - - run_script(design, run_from, run_to); - - log_pop(); - } - - struct DSPRule { - int a_maxwidth; - int b_maxwidth; - int a_minwidth; - int b_minwidth; - std::string prim; - }; - - const std::vector dsp_rules = { - {36, 36, 22, 22, "$__NX_MUL36X36"}, - {36, 18, 22, 10, "$__NX_MUL36X18"}, - {18, 18, 10, 4, "$__NX_MUL18X18"}, - {18, 18, 4, 10, "$__NX_MUL18X18"}, - { 9, 9, 4, 4, "$__NX_MUL9X9"}, - }; - - void script() override - { - - if (family != "lifcl" && family != "lfd2nx") - log_cmd_error("Invalid Nexus -family setting: '%s'.\n", family); - - if (check_label("begin")) - { - run("read_verilog -lib -specify +/nexus/cells_sim.v +/nexus/cells_xtra.v"); - run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt)); - } - - if (check_label("coarse")) - { - run("proc"); - if (flatten || help_mode) - run("flatten"); - run("tribuf -logic"); - run("deminout"); - run("opt_expr"); - run("opt_clean"); - run("check"); - run("opt -nodffe -nosdff"); - run("fsm"); - run("opt"); - run("wreduce"); - run("peepopt"); - run("opt_clean"); - run("share"); - run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); - run("opt_expr"); - run("opt_clean"); - - if (help_mode) { - run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); - run("techmap -map +/nexus/dsp_map.v", "(unless -nodsp)"); - } else if (!nodsp) { - for (const auto &rule : dsp_rules) { - run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s", - rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim.c_str())); - run("chtype -set $mul t:$__soft_mul"); - } - run("techmap -map +/nexus/dsp_map.v"); - } - - run("alumacc"); - run("opt"); - run("memory -nomap"); - run("opt_clean"); - } - - if (check_label("map_ram")) - { - std::string args = ""; - args += " -no-auto-huge"; - if (help_mode) - args += " [-no-auto-block] [-no-auto-distributed]"; - else { - if (nobram) - args += " -no-auto-block"; - if (nolutram) - args += " -no-auto-distributed"; - } - run("memory_libmap -lib +/nexus/lutrams.txt -lib +/nexus/brams.txt -lib +/nexus/lrams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); - run("techmap -map +/nexus/lutrams_map.v -map +/nexus/brams_map.v -map +/nexus/lrams_map.v"); - } - - if (check_label("map_ffram")) - { - run("opt -fast -mux_undef -undriven -fine"); - run("memory_map"); - run("opt -undriven -fine"); - } - - if (check_label("map_gates")) - { - if (noccu2) - run("techmap"); - else - run("techmap -map +/techmap.v -map +/nexus/arith_map.v"); - if (help_mode || !noiopad) - run("iopadmap -bits -outpad OB I:O -inpad IB O:I -toutpad OBZ ~T:I:O -tinoutpad BB ~T:O:I:B A:top", "(skip if '-noiopad')"); - run("opt -fast"); - if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); - } - - if (check_label("map_ffs")) - { - run("opt_clean"); - std::string dfflegalize_args = " -cell $_DFF_P_ 01 -cell $_DFF_PP?_ r -cell $_SDFF_PP?_ r -cell $_DLATCH_?_ x"; - if (help_mode) { - dfflegalize_args += " [-cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r]"; - } else if (!nodffe) { - dfflegalize_args += " -cell $_DFFE_PP_ 01 -cell $_DFFE_PP?P_ r -cell $_SDFFE_PP?P_ r"; - } - run("dfflegalize" + dfflegalize_args, "($_*DFFE_* only if not -nodffe)"); - if ((abc9 && dff) || help_mode) - run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff"); - run("techmap -D NO_LUT -map +/nexus/cells_map.v"); - run("opt_expr -undriven -mux_undef"); - run("simplemap"); - run("attrmvcp -copy -attr syn_useioff"); - run("opt_clean"); - } - - if (check_label("map_luts")) - { - run("techmap -map +/nexus/latches_map.v"); - - if (abc9) { - std::string abc9_opts; - if (nowidelut) - abc9_opts += " -maxlut 4"; - std::string k = "synth_nexus.abc9.W"; - if (active_design && active_design->scratchpad.count(k)) - abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k)); - else - abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k)); - if (nowidelut) - abc9_opts += " -maxlut 4"; - if (dff) - abc9_opts += " -dff"; - run("abc9" + abc9_opts); - } else { - std::string abc_args = " -dress"; - if (nowidelut) - abc_args += " -lut 4"; - else - abc_args += " -lut 4:5"; - if (dff) - abc_args += " -dff"; - run("abc" + abc_args); - } - run("clean"); - } - - if (check_label("map_cells")) - { - run("techmap -map +/nexus/cells_map.v"); - - // This is needed for Radiant, but perhaps not optimal for nextpnr... - run("setundef -zero"); - - run("hilomap -singleton -hicell VHI Z -locell VLO Z"); - run("clean"); - } - - if (check_label("check")) - { - run("autoname"); - run("hierarchy -check"); - run("stat"); - run("check -noinit"); - run("blackbox =A:whitebox"); - } - - if (check_label("json")) - { - if (!json_file.empty() || help_mode) - run(stringf("write_json %s", help_mode ? "" : json_file)); - } - - if (check_label("vm")) - { - if (!vm_file.empty() || help_mode) - run(stringf("write_verilog %s", help_mode ? "" : vm_file)); - } - } -} SynthNexusPass; - -PRIVATE_NAMESPACE_END From 4c17ac5ac2c97943166c788f5f25bd6b47158376 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 29 Sep 2025 23:03:29 +0200 Subject: [PATCH 15/49] .github: suggest Discourse in PR template --- .github/PULL_REQUEST_TEMPLATE.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 82daf609d..7eccdec3b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,9 @@ +_If your work is part of a larger effort, please discuss your general plans on [Discourse](https://yosyshq.discourse.group/) first to align your vision with maintainers._ + _What are the reasons/motivation for this change?_ _Explain how this is achieved._ -_If applicable, please suggest to reviewers how they can test the change._ +_Make sure your change comes with tests. If not possible, share how a reviewer might evaluate it._ + +_These template prompts can be deleted when you're done responding to them_ \ No newline at end of file From b2adaeec6949e7318a269de00337d3fc1c5652d6 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 29 Sep 2025 23:03:54 +0200 Subject: [PATCH 16/49] .github: replace Slack and GitHub Discussions with Discourse in issue templates --- .github/ISSUE_TEMPLATE/bug_report.yml | 5 ++--- .github/ISSUE_TEMPLATE/docs_report.yml | 3 +-- .github/ISSUE_TEMPLATE/feature_request.yml | 9 ++++----- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e4c776ed9..f754d16c7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,15 +6,14 @@ body: attributes: value: > - If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area - or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA). + If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/). If you have a feature request, please fill out the appropriate issue form, this form is for bugs and/or regressions. Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need - commercial support for Yosys. + commercial support or work done for Yosys. - type: input id: yosys_version diff --git a/.github/ISSUE_TEMPLATE/docs_report.yml b/.github/ISSUE_TEMPLATE/docs_report.yml index aa65c63b9..c3ad2f7cc 100644 --- a/.github/ISSUE_TEMPLATE/docs_report.yml +++ b/.github/ISSUE_TEMPLATE/docs_report.yml @@ -6,8 +6,7 @@ body: attributes: value: > - If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area - or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA). + If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/). If you have found a bug in Yosys, or in building the documentation, diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index c521b5296..49d86f341 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,18 +1,17 @@ name: Feature Request -description: "Submit a feature request for Yosys" +description: "Submit a feature request for Yosys" labels: ["feature-request"] body: - type: markdown attributes: value: > - If you have a general question, please ask it in the [Discussions](https://github.com/YosysHQ/yosys/discussions) area - or join our [IRC Channel](https://web.libera.chat/#yosys) or [Community Slack](https://join.slack.com/t/yosyshq/shared_invite/zt-1aopkns2q-EiQ97BeQDt_pwvE41sGSuA). - + If you have a general question, please ask it on the [Discourse forum](https://yosyshq.discourse.group/). + If you have a bug report, please fill out the appropriate issue form, this form is for feature requests. - + Please contact [YosysHQ GmbH](https://www.yosyshq.com/) if you need commercial support or work done for Yosys. From b86cc0d9b3bfbea3afcd98881b20ab3026131437 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 29 Sep 2025 23:20:06 +0200 Subject: [PATCH 17/49] docs: replace Slack with Discourse in extensions writing guide --- docs/source/yosys_internals/extending_yosys/extensions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/yosys_internals/extending_yosys/extensions.rst b/docs/source/yosys_internals/extending_yosys/extensions.rst index d30dd2bae..44b1edabc 100644 --- a/docs/source/yosys_internals/extending_yosys/extensions.rst +++ b/docs/source/yosys_internals/extending_yosys/extensions.rst @@ -9,7 +9,7 @@ Writing extensions .. todo:: update to use :file:`/code_examples/extensions/test*.log` This chapter contains some bits and pieces of information about programming -yosys extensions. Don't be afraid to ask questions on the YosysHQ Slack. +yosys extensions. Don't be afraid to ask questions on the Yosys HQ Discourse. .. todo:: mention coding guide From 5fd2aecd90ff36bffeb5a4cebc7cfb61d862e877 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 00:23:05 +0000 Subject: [PATCH 18/49] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7a2e8419b..317dbeb9b 100644 --- a/Makefile +++ b/Makefile @@ -164,7 +164,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.57+218 +YOSYS_VER := 0.57+244 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From e6fa0223c80d3d4f81d22e582be390c4aafaf971 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 30 Sep 2025 08:44:31 +0200 Subject: [PATCH 19/49] Force linking log_compat when extensions are linked --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 317dbeb9b..91f596258 100644 --- a/Makefile +++ b/Makefile @@ -530,8 +530,12 @@ ifeq ($(ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS),1) VERIFIC_COMPONENTS += extensions CXXFLAGS += -DYOSYSHQ_VERIFIC_EXTENSIONS else +# YosysHQ flavor of Verific always needs extensions linked +# if disabled it will just not be invoked but parts +# are required for it to initialize properly ifneq ($(wildcard $(VERIFIC_DIR)/extensions),) VERIFIC_COMPONENTS += extensions +OBJS += kernel/log_compat.o endif endif CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC From dc7764e2473d5e9c9adcf80052173fc97246ecfe Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 30 Sep 2025 11:03:19 +0200 Subject: [PATCH 20/49] .github: typos --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- docs/source/yosys_internals/extending_yosys/extensions.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7eccdec3b..d8d929f3f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,4 +6,4 @@ _Explain how this is achieved._ _Make sure your change comes with tests. If not possible, share how a reviewer might evaluate it._ -_These template prompts can be deleted when you're done responding to them_ \ No newline at end of file +_These template prompts can be deleted when you're done responding to them._ \ No newline at end of file diff --git a/docs/source/yosys_internals/extending_yosys/extensions.rst b/docs/source/yosys_internals/extending_yosys/extensions.rst index 44b1edabc..74a7d72d6 100644 --- a/docs/source/yosys_internals/extending_yosys/extensions.rst +++ b/docs/source/yosys_internals/extending_yosys/extensions.rst @@ -9,7 +9,7 @@ Writing extensions .. todo:: update to use :file:`/code_examples/extensions/test*.log` This chapter contains some bits and pieces of information about programming -yosys extensions. Don't be afraid to ask questions on the Yosys HQ Discourse. +yosys extensions. Don't be afraid to ask questions on the YosysHQ Discourse. .. todo:: mention coding guide From 6b43fca8df94590f2b75f8ef8c76445517af878d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 12 Sep 2025 04:57:08 +0000 Subject: [PATCH 21/49] Make the Const string constructor take the string by value and move it into the const --- kernel/rtlil.cc | 4 ++-- kernel/rtlil.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 8daf2c821..adcc5f41c 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -264,10 +264,10 @@ std::string& Const::get_str() { return *get_if_str(); } -RTLIL::Const::Const(const std::string &str) +RTLIL::Const::Const(std::string str) { flags = RTLIL::CONST_FLAG_STRING; - new ((void*)&str_) std::string(str); + new ((void*)&str_) std::string(std::move(str)); tag = backing_tag::string; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 5271a3111..74a57e554 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -859,7 +859,7 @@ private: public: Const() : flags(RTLIL::CONST_FLAG_NONE), tag(backing_tag::bits), bits_(std::vector()) {} - Const(const std::string &str); + Const(std::string str); Const(long long val); // default width is 32 Const(long long val, int width); Const(RTLIL::State bit, int width = 1); From 39c6e06e3d6581d12a8d82def2669fa92cedc9a6 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 12 Sep 2025 04:58:39 +0000 Subject: [PATCH 22/49] Add an IdString(std::string_view) constructor for efficiency when we already know the string length --- kernel/rtlil.h | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 74a57e554..a24a82f55 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -209,10 +209,15 @@ struct RTLIL::IdString } static int get_reference(const char *p) + { + return get_reference(std::string_view(p)); + } + + static int get_reference(std::string_view p) { log_assert(destruct_guard_ok); - auto it = global_id_index_.find((char*)p); + auto it = global_id_index_.find(p); if (it != global_id_index_.end()) { #ifndef YOSYS_NO_IDS_REFCNT global_refcount_storage_.at(it->second)++; @@ -226,14 +231,13 @@ struct RTLIL::IdString ensure_prepopulated(); - if (!p[0]) + if (p.empty()) return 0; log_assert(p[0] == '$' || p[0] == '\\'); - log_assert(p[1] != 0); - for (const char *c = p; *c; c++) - if ((unsigned)*c <= (unsigned)' ') - log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", *c, p); + for (char ch : p) + if ((unsigned)ch <= (unsigned)' ') + log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", ch, std::string(p).c_str()); #ifndef YOSYS_NO_IDS_REFCNT if (global_free_idx_list_.empty()) { @@ -245,8 +249,11 @@ struct RTLIL::IdString int idx = global_free_idx_list_.back(); global_free_idx_list_.pop_back(); - global_id_storage_.at(idx) = strdup(p); - global_id_index_[global_id_storage_.at(idx)] = idx; + char* buf = static_cast(malloc(p.size() + 1)); + memcpy(buf, p.data(), p.size()); + buf[p.size()] = 0; + global_id_storage_.at(idx) = buf; + global_id_index_.insert(it, {std::string_view(buf, p.size()), idx}); global_refcount_storage_.at(idx)++; #else int idx = global_id_storage_.size(); @@ -255,7 +262,7 @@ struct RTLIL::IdString #endif if (yosys_xtrace) { - log("#X# New IdString '%s' with index %d.\n", p, idx); + log("#X# New IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); log_backtrace("-X- ", yosys_xtrace-1); } @@ -322,7 +329,8 @@ struct RTLIL::IdString inline IdString(const char *str) : index_(get_reference(str)) { } inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } - inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } + inline IdString(const std::string &str) : index_(get_reference(std::string_view(str))) { } + inline IdString(std::string_view str) : index_(get_reference(str)) { } inline IdString(StaticId id) : index_(static_cast(id)) {} inline ~IdString() { put_reference(index_); } From 86d8dd6224628609b703f811e41dd0d282d8a6d0 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 12 Sep 2025 04:59:20 +0000 Subject: [PATCH 23/49] Add a moving assignment operator for IdString to avoid refcount churn --- kernel/rtlil.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a24a82f55..794cabd70 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -339,6 +339,12 @@ struct RTLIL::IdString index_ = get_reference(rhs.index_); } + inline void operator=(IdString &&rhs) { + put_reference(index_); + index_ = rhs.index_; + rhs.index_ = 0; + } + inline void operator=(const char *rhs) { IdString id(rhs); *this = id; From db3d9a1baf567b6e005265ad97aff4b34ad6f89e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 12 Sep 2025 05:01:50 +0000 Subject: [PATCH 24/49] When adding named elements to an RTLIL::Module, std::move the name to avoid refcount churn --- kernel/rtlil.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index adcc5f41c..40c23f163 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3050,7 +3050,7 @@ void RTLIL::Module::fixup_ports() RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) { RTLIL::Wire *wire = new RTLIL::Wire; - wire->name = name; + wire->name = std::move(name); wire->width = width; add(wire); return wire; @@ -3058,7 +3058,7 @@ RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, int width) RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *other) { - RTLIL::Wire *wire = addWire(name); + RTLIL::Wire *wire = addWire(std::move(name)); wire->width = other->width; wire->start_offset = other->start_offset; wire->port_id = other->port_id; @@ -3073,7 +3073,7 @@ RTLIL::Wire *RTLIL::Module::addWire(RTLIL::IdString name, const RTLIL::Wire *oth RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type) { RTLIL::Cell *cell = new RTLIL::Cell; - cell->name = name; + cell->name = std::move(name); cell->type = type; add(cell); return cell; @@ -3081,7 +3081,7 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, RTLIL::IdString type) RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *other) { - RTLIL::Cell *cell = addCell(name, other->type); + RTLIL::Cell *cell = addCell(std::move(name), other->type); cell->connections_ = other->connections_; cell->parameters = other->parameters; cell->attributes = other->attributes; @@ -3091,7 +3091,7 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memory *other) { RTLIL::Memory *mem = new RTLIL::Memory; - mem->name = name; + mem->name = std::move(name); mem->width = other->width; mem->start_offset = other->start_offset; mem->size = other->size; @@ -3103,7 +3103,7 @@ RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memor RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name) { RTLIL::Process *proc = new RTLIL::Process; - proc->name = name; + proc->name = std::move(name); add(proc); return proc; } @@ -3111,7 +3111,7 @@ RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name) RTLIL::Process *RTLIL::Module::addProcess(RTLIL::IdString name, const RTLIL::Process *other) { RTLIL::Process *proc = other->clone(); - proc->name = name; + proc->name = std::move(name); add(proc); return proc; } From 7f550468ead3a3b097a339ffb23fce9a73435fe2 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 12 Sep 2025 05:02:52 +0000 Subject: [PATCH 25/49] Update RTLIL text representation docs --- docs/source/appendix/rtlil_text.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/source/appendix/rtlil_text.rst b/docs/source/appendix/rtlil_text.rst index b1bc9c582..352b1af2e 100644 --- a/docs/source/appendix/rtlil_text.rst +++ b/docs/source/appendix/rtlil_text.rst @@ -63,6 +63,10 @@ significant bit first. Bits may be any of: - ``m``: A marked bit (internal use only) - ``-``: A don't care value +When the bit representation has fewer bits than the width, it is padded to the width with +the most significant explicit bit, or ``0`` if the most significant explicit bit is ``1``, +or ``x`` if there are no explicit bits. + An *integer* is simply a signed integer value in decimal format. **Warning:** Integer constants are limited to 32 bits. That is, they may only be in the range :math:`[-2147483648, 2147483648)`. Integers outside this range will result in an @@ -133,6 +137,7 @@ wires, memories, cells, processes, and connections. ::= * ::= module ::= ( + | | | | @@ -170,6 +175,11 @@ See :ref:`sec:rtlil_sigspec` for an overview of signal specifications. | [ (:)? ] | { * } +When a ```` is specified, the wire must have been previously declared. + +When a signal slice is specified, the left-hand integer must be greather than or +equal to the right-hand integer. + Connections ^^^^^^^^^^^ @@ -268,7 +278,7 @@ may have zero or more attributes. .. code:: BNF ::= * - := * switch + ::= * switch ::= * ::= case ? ::= (, )* @@ -295,3 +305,4 @@ be: | sync always ::= low | high | posedge | negedge | edge ::= update + | * memwr From 01eaaa4b902117f5819f076f7daaa0be0d48093d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 00:26:18 +0000 Subject: [PATCH 26/49] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 91f596258..54ad13d7c 100644 --- a/Makefile +++ b/Makefile @@ -164,7 +164,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.57+244 +YOSYS_VER := 0.57+254 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From ac4cb5e460f200c71f2bf7dd826404f87b9db340 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 12 Sep 2025 05:04:06 +0000 Subject: [PATCH 27/49] Implement a handwritten recursive-descent RTLIL parser with minimal copying --- frontends/rtlil/Makefile.inc | 18 - frontends/rtlil/rtlil_frontend.cc | 783 ++++++++++++++++++++++++++++-- frontends/rtlil/rtlil_frontend.h | 52 -- frontends/rtlil/rtlil_lexer.l | 150 ------ frontends/rtlil/rtlil_parser.y | 525 -------------------- 5 files changed, 755 insertions(+), 773 deletions(-) delete mode 100644 frontends/rtlil/rtlil_frontend.h delete mode 100644 frontends/rtlil/rtlil_lexer.l delete mode 100644 frontends/rtlil/rtlil_parser.y diff --git a/frontends/rtlil/Makefile.inc b/frontends/rtlil/Makefile.inc index d0c0cfcf8..4649507f7 100644 --- a/frontends/rtlil/Makefile.inc +++ b/frontends/rtlil/Makefile.inc @@ -1,19 +1 @@ - -GENFILES += frontends/rtlil/rtlil_parser.tab.cc -GENFILES += frontends/rtlil/rtlil_parser.tab.hh -GENFILES += frontends/rtlil/rtlil_parser.output -GENFILES += frontends/rtlil/rtlil_lexer.cc - -frontends/rtlil/rtlil_parser.tab.cc: frontends/rtlil/rtlil_parser.y - $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -o $@ -d -r all -b frontends/rtlil/rtlil_parser $< - -frontends/rtlil/rtlil_parser.tab.hh: frontends/rtlil/rtlil_parser.tab.cc - -frontends/rtlil/rtlil_lexer.cc: frontends/rtlil/rtlil_lexer.l - $(Q) mkdir -p $(dir $@) - $(P) flex -o frontends/rtlil/rtlil_lexer.cc $< - -OBJS += frontends/rtlil/rtlil_parser.tab.o frontends/rtlil/rtlil_lexer.o OBJS += frontends/rtlil/rtlil_frontend.o - diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index e8d6ac9c9..d7511055b 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -17,27 +17,762 @@ * * --- * - * A very simple and straightforward frontend for the RTLIL text - * representation. + * A handwritten recursive-descent parser for the RTLIL text representation. * */ -#include "rtlil_frontend.h" #include "kernel/register.h" #include "kernel/log.h" - -void rtlil_frontend_yyerror(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s); -} - -void rtlil_frontend_yywarning(char const *s) -{ - YOSYS_NAMESPACE_PREFIX log_warning("In line %d: %s\n", rtlil_frontend_yyget_lineno(), s); -} +#include "kernel/utils.h" +#include +#include +#include YOSYS_NAMESPACE_BEGIN +struct RTLILFrontendWorker { + std::istream *f = nullptr; + RTLIL::Design *design; + bool flag_nooverwrite = false; + bool flag_overwrite = false; + bool flag_lib = false; + + int line_num; + std::string line_buf; + // Substring of line_buf. Always newline-terminated, thus never empty. + std::string_view line; + + RTLIL::Module *current_module; + dict attrbuf; + std::vector*> switch_stack; + std::vector case_stack; + + template + [[noreturn]] + void error(FmtString...> fmt, const Args &... args) + { + log_error("Parser error in line %d: %s\n", line_num, fmt.format(args...)); + } + + template + void warning(FmtString...> fmt, const Args &... args) + { + log_warning("In line %d: %s\n", line_num, fmt.format(args...)); + } + + // May return an empty line if the stream is not good(). + void advance_to_next_nonempty_line() + { + if (!f->good()) { + line = "\n"; + return; + } + while (true) { + std::getline(*f, line_buf); + line_num++; + if (line_buf.empty() || line_buf[line_buf.size() - 1] != '\n') + line_buf += '\n'; + line = line_buf; + consume_whitespace_and_comments(); + if (line[0] != '\n' || !f->good()) + break; + } + } + + void consume_whitespace_and_comments() + { + while (true) { + switch (line[0]) { + case ' ': + case '\t': + line = line.substr(1); + break; + case '#': + line = "\n"; + return; + default: + return; + } + } + } + + bool try_parse_keyword(std::string_view keyword) + { + int keyword_size = keyword.size(); + if (keyword != line.substr(0, keyword_size)) + return false; + // This index is safe because `line` is always newline-terminated + // and `keyword` never contains a newline. + char ch = line[keyword_size]; + if (ch >= 'a' && ch <= 'z') + return false; + line = line.substr(keyword_size); + consume_whitespace_and_comments(); + return true; + } + + std::string error_token() + { + std::string result; + for (char ch : line) { + if (ch == '\n' || ch == ' ' || ch == '\t') + break; + result += ch; + } + return result; + } + + void expect_keyword(std::string_view keyword) + { + if (!try_parse_keyword(keyword)) + error("Expected token `%s', got `%s'.", keyword, error_token()); + } + + bool try_parse_char(char ch) + { + if (line[0] != ch) + return false; + line = line.substr(1); + consume_whitespace_and_comments(); + return true; + } + + void expect_char(char ch) + { + if (!try_parse_char(ch)) + error("Expected `%c', got `%s'.", ch, error_token()); + } + + bool try_parse_eol() + { + if (line[0] != '\n') + return false; + advance_to_next_nonempty_line(); + return true; + } + + void expect_eol() + { + if (!try_parse_eol()) + error("Expected EOL, got `%s'.", error_token()); + } + + std::optional try_parse_id() + { + char ch = line[0]; + if (ch != '\\' && ch != '$') + return std::nullopt; + int idx = 1; + while (true) { + ch = line[idx]; + if (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) + break; + ++idx; + } + IdString result(line.substr(0, idx)); + line = line.substr(idx); + consume_whitespace_and_comments(); + return result; + } + + RTLIL::IdString parse_id() + { + std::optional id = try_parse_id(); + if (!id.has_value()) + error("Expected ID, got `%s'.", error_token()); + return std::move(*id); + } + + long long parse_integer() + { + long long result = parse_integer_alone(); + consume_whitespace_and_comments(); + return result; + } + + long long parse_integer_alone() + { + int idx = 0; + if (line[idx] == '-') + ++idx; + while (true) { + char ch = line[idx]; + if (ch < '0' || ch > '9') + break; + ++idx; + } + long long result; + if (std::from_chars(line.data(), line.data() + idx, result, 10).ec != std::errc{}) + error("Invalid integer `%s'.", error_token()); + line = line.substr(idx); + return result; + } + + std::string parse_string() + { + if (line[0] != '\"') + error("Expected string, got `%s'.", error_token()); + std::string str; + int idx = 1; + while (true) { + int start_idx = idx; + char ch; + while (true) { + ch = line[idx]; + if (ch == '"' || ch == '\n' || ch == '\\' || ch == 0) + break; + ++idx; + } + str.append(line.data() + start_idx, line.data() + idx); + ++idx; + if (ch == '"') + break; + if (ch == 0) + error("Null byte in string literal: `%s'.", line); + if (ch == '\n') + error("Unterminated string literal: `%s'.", line); + ch = line[idx++]; + if (ch == 'n') { + ch = '\n'; + } else if (ch == 't') { + ch = '\t'; + } else if (ch >= '0' && ch <= '7') { + int v = ch - '0'; + char next_ch = line[idx + 1]; + if (next_ch >= '0' && next_ch <= '7') { + ++idx; + v = v*8 + (next_ch - '0'); + next_ch = line[idx + 1]; + if (next_ch >= '0' && next_ch <= '7') { + ++idx; + v = v*8 + (next_ch - '0'); + } + } + ch = v; + } + str += ch; + } + line = line.substr(idx); + consume_whitespace_and_comments(); + return str; + } + + RTLIL::Const parse_const() + { + if (line[0] == '"') + return RTLIL::Const(parse_string()); + + bool negative_value = line[0] == '-'; + long long width = parse_integer_alone(); + // Can't test value<0 here because we need to stop parsing after '-0' + if (negative_value || line[0] != '\'') { + if (width < INT_MIN || width > INT_MAX) + error("Integer %lld out of range in `%s'.", width, error_token()); + consume_whitespace_and_comments(); + return RTLIL::Const(width); + } + + int idx = 1; + bool is_signed = line[1] == 's'; + if (is_signed) + ++idx; + + std::vector bits; + bits.reserve(width); + while (true) { + RTLIL::State bit; + switch (line[idx]) { + case '0': bit = RTLIL::S0; break; + case '1': bit = RTLIL::S1; break; + case 'x': bit = RTLIL::Sx; break; + case 'z': bit = RTLIL::Sz; break; + case 'm': bit = RTLIL::Sm; break; + case '-': bit = RTLIL::Sa; break; + default: goto done; + } + bits.push_back(bit); + ++idx; + } + done: + std::reverse(bits.begin(), bits.end()); + + if (GetSize(bits) > width) + bits.resize(width); + else if (GetSize(bits) < width) { + RTLIL::State extbit = RTLIL::Sx; + if (!bits.empty()) { + extbit = bits.back(); + if (extbit == RTLIL::S1) + extbit = RTLIL::S0; + } + bits.resize(width, extbit); + } + + RTLIL::Const val(std::move(bits)); + if (is_signed) + val.flags |= RTLIL::CONST_FLAG_SIGNED; + line = line.substr(idx); + consume_whitespace_and_comments(); + return val; + } + + RTLIL::SigSpec parse_sigspec() + { + if (try_parse_char('{')) { + std::vector parts; + while (!try_parse_char('}')) + parts.push_back(parse_sigspec()); + RTLIL::SigSpec sig; + for (auto it = parts.rbegin(); it != parts.rend(); ++it) + sig.append(std::move(*it)); + return sig; + } + + RTLIL::SigSpec sig; + + // We could add a special path for parsing IdStrings that must already exist, + // as here. + // We don't need to addref/release in this case. + std::optional id = try_parse_id(); + if (id.has_value()) { + RTLIL::Wire *wire = current_module->wire(*id); + if (wire == nullptr) + error("Wire `%s' not found.", *id); + sig = RTLIL::SigSpec(wire); + } else { + sig = RTLIL::SigSpec(parse_const()); + } + + while (try_parse_char('[')) { + int left = parse_integer(); + if (left >= sig.size() || left < 0) + error("bit index %d out of range", left); + if (try_parse_char(':')) { + int right = parse_integer(); + if (right < 0) + error("bit index %d out of range", right); + if (left < right) + error("invalid slice [%d:%d]", left, right); + sig = sig.extract(right, left-right+1); + } else { + sig = sig.extract(left); + } + expect_char(']'); + } + + return sig; + } + + void parse_module() + { + RTLIL::IdString module_name = parse_id(); + expect_eol(); + + bool delete_current_module = false; + if (design->has(module_name)) { + RTLIL::Module *existing_mod = design->module(module_name); + if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { + log("Ignoring blackbox re-definition of module %s.\n", module_name); + delete_current_module = true; + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { + error("RTLIL error: redefinition of module %s.", module_name); + } else if (flag_nooverwrite) { + log("Ignoring re-definition of module %s.\n", module_name); + delete_current_module = true; + } else { + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", module_name); + design->remove(existing_mod); + } + } + + current_module = new RTLIL::Module; + current_module->name = std::move(module_name); + current_module->attributes = std::move(attrbuf); + if (!delete_current_module) + design->add(current_module); + + while (true) + { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + if (try_parse_keyword("parameter")) { + parse_parameter(); + continue; + } + if (try_parse_keyword("connect")) { + parse_connect(); + continue; + } + if (try_parse_keyword("wire")) { + parse_wire(); + continue; + } + if (try_parse_keyword("cell")) { + parse_cell(); + continue; + } + if (try_parse_keyword("memory")) { + parse_memory(); + continue; + } + if (try_parse_keyword("process")) { + parse_process(); + continue; + } + if (try_parse_keyword("end")) { + expect_eol(); + break; + } + error("Unexpected token in module body: %s", error_token()); + } + + if (attrbuf.size() != 0) + error("dangling attribute"); + current_module->fixup_ports(); + if (delete_current_module) + delete current_module; + else if (flag_lib) + current_module->makeblackbox(); + current_module = nullptr; + } + + void parse_attribute() + { + RTLIL::IdString id = parse_id(); + RTLIL::Const c = parse_const(); + attrbuf.insert({std::move(id), std::move(c)}); + expect_eol(); + } + + void parse_parameter() + { + RTLIL::IdString id = parse_id(); + current_module->avail_parameters(id); + if (try_parse_eol()) + return; + RTLIL::Const c = parse_const(); + current_module->parameter_default_values.insert({std::move(id), std::move(c)}); + expect_eol(); + } + + void parse_wire() + { + RTLIL::Wire *wire; + int width = 1; + int start_offset = 0; + int port_id = 0; + bool port_input = false; + bool port_output = false; + bool upto = false; + bool is_signed = false; + + while (true) + { + std::optional id = try_parse_id(); + if (id.has_value()) { + if (current_module->wire(*id) != nullptr) + error("RTLIL error: redefinition of wire %s.", *id); + wire = current_module->addWire(std::move(*id)); + break; + } + if (try_parse_keyword("width")) + width = parse_integer(); + else if (try_parse_keyword("upto")) + upto = true; + else if (try_parse_keyword("signed")) + is_signed = true; + else if (try_parse_keyword("offset")) + start_offset = parse_integer(); + else if (try_parse_keyword("input")) { + port_id = parse_integer(); + port_input = true; + } else if (try_parse_keyword("output")) { + port_id = parse_integer(); + port_output = true; + } else if (try_parse_keyword("inout")) { + port_id = parse_integer(); + port_input = true; + port_output = true; + } else if (try_parse_eol()) + error("Missing wire ID"); + else + error("Unexpected wire option: %s", error_token()); + } + + wire->attributes = std::move(attrbuf); + wire->width = width; + wire->upto = upto; + wire->start_offset = start_offset; + wire->is_signed = is_signed; + wire->port_id = port_id; + wire->port_input = port_input; + wire->port_output = port_output; + expect_eol(); + } + + void parse_memory() + { + RTLIL::Memory *memory = new RTLIL::Memory; + memory->attributes = std::move(attrbuf); + + int width = 1; + int start_offset = 0; + int size = 0; + while (true) + { + std::optional id = try_parse_id(); + if (id.has_value()) { + if (current_module->memories.count(*id) != 0) + error("RTLIL error: redefinition of memory %s.", *id); + memory->name = std::move(*id); + break; + } + if (try_parse_keyword("width")) + width = parse_integer(); + else if (try_parse_keyword("size")) + size = parse_integer(); + else if (try_parse_keyword("offset")) + start_offset = parse_integer(); + else if (try_parse_eol()) + error("Missing memory ID"); + else + error("Unexpected memory option: %s", error_token()); + } + memory->width = width; + memory->start_offset = start_offset; + memory->size = size; + current_module->memories.insert({memory->name, memory}); + expect_eol(); + } + + void parse_cell() + { + RTLIL::IdString cell_type = parse_id(); + RTLIL::IdString cell_name = parse_id(); + expect_eol(); + + if (current_module->cell(cell_name) != nullptr) + error("RTLIL error: redefinition of cell %s.", cell_name); + RTLIL::Cell *cell = current_module->addCell(cell_name, cell_type); + cell->attributes = std::move(attrbuf); + + while (true) + { + if (try_parse_keyword("parameter")) { + bool is_signed = false; + bool is_real = false; + if (try_parse_keyword("signed")) { + is_signed = true; + } else if (try_parse_keyword("real")) { + is_real = true; + } + RTLIL::IdString param_name = parse_id(); + RTLIL::Const val = parse_const(); + if (is_signed) + val.flags |= RTLIL::CONST_FLAG_SIGNED; + if (is_real) + val.flags |= RTLIL::CONST_FLAG_REAL; + cell->parameters.insert({std::move(param_name), std::move(val)}); + expect_eol(); + } else if (try_parse_keyword("connect")) { + RTLIL::IdString port_name = parse_id(); + if (cell->hasPort(port_name)) + error("RTLIL error: redefinition of cell port %s.", port_name); + cell->setPort(std::move(port_name), parse_sigspec()); + expect_eol(); + } else if (try_parse_keyword("end")) { + expect_eol(); + break; + } else { + error("Unexpected token in cell body: %s", error_token()); + } + } + } + + void parse_connect() + { + if (attrbuf.size() != 0) + error("dangling attribute"); + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + current_module->connect(std::move(s1), std::move(s2)); + expect_eol(); + } + + void parse_case_body(RTLIL::CaseRule *current_case) + { + while (true) + { + if (try_parse_keyword("attribute")) + parse_attribute(); + else if (try_parse_keyword("switch")) + parse_switch(); + else if (try_parse_keyword("assign")) { + if (attrbuf.size() != 0) + error("dangling attribute"); + // See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this + // warning + if (!switch_stack.back()->empty()) + warning("case rule assign statements after switch statements may cause unexpected behaviour. " + "The assign statement is reordered to come before all switch statements."); + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + current_case->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2))); + expect_eol(); + } else + return; + } + } + + void parse_switch() + { + RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; + rule->signal = parse_sigspec(); + rule->attributes = std::move(attrbuf); + switch_stack.back()->push_back(rule); + expect_eol(); + + while (true) { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + + if (try_parse_keyword("end")) { + expect_eol(); + break; + } + + expect_keyword("case"); + RTLIL::CaseRule *case_rule = new RTLIL::CaseRule; + case_rule->attributes = std::move(attrbuf); + rule->cases.push_back(case_rule); + switch_stack.push_back(&case_rule->switches); + case_stack.push_back(case_rule); + + if (!try_parse_eol()) { + while (true) { + case_rule->compare.push_back(parse_sigspec()); + if (try_parse_eol()) + break; + expect_char(','); + } + } + + parse_case_body(case_rule); + + switch_stack.pop_back(); + case_stack.pop_back(); + } + } + + void parse_process() + { + RTLIL::IdString proc_name = parse_id(); + expect_eol(); + + if (current_module->processes.count(proc_name) != 0) + error("RTLIL error: redefinition of process %s.", proc_name); + RTLIL::Process *proc = current_module->addProcess(std::move(proc_name)); + proc->attributes = std::move(attrbuf); + + switch_stack.clear(); + switch_stack.push_back(&proc->root_case.switches); + case_stack.clear(); + case_stack.push_back(&proc->root_case); + + parse_case_body(&proc->root_case); + + while (try_parse_keyword("sync")) + { + RTLIL::SyncRule *rule = new RTLIL::SyncRule; + + if (try_parse_keyword("low")) rule->type = RTLIL::ST0; + else if (try_parse_keyword("high")) rule->type = RTLIL::ST1; + else if (try_parse_keyword("posedge")) rule->type = RTLIL::STp; + else if (try_parse_keyword("negedge")) rule->type = RTLIL::STn; + else if (try_parse_keyword("edge")) rule->type = RTLIL::STe; + else if (try_parse_keyword("always")) rule->type = RTLIL::STa; + else if (try_parse_keyword("global")) rule->type = RTLIL::STg; + else if (try_parse_keyword("init")) rule->type = RTLIL::STi; + else error("Unexpected sync type: %s", error_token()); + + if (rule->type != RTLIL::STa && rule->type != RTLIL::STg && rule->type != RTLIL::STi) + rule->signal = parse_sigspec(); + proc->syncs.push_back(rule); + expect_eol(); + + bool attributes_in_update_list = false; + while (true) + { + if (try_parse_keyword("update")) { + RTLIL::SigSpec s1 = parse_sigspec(); + RTLIL::SigSpec s2 = parse_sigspec(); + rule->actions.push_back(RTLIL::SigSig(std::move(s1), std::move(s2))); + expect_eol(); + continue; + } + + if (try_parse_keyword("attribute")) { + attributes_in_update_list = true; + parse_attribute(); + continue; + } + + if (!try_parse_keyword("memwr")) + break; + + RTLIL::MemWriteAction act; + act.attributes = std::move(attrbuf); + act.memid = parse_id(); + act.address = parse_sigspec(); + act.data = parse_sigspec(); + act.enable = parse_sigspec(); + act.priority_mask = parse_const(); + rule->mem_write_actions.push_back(std::move(act)); + expect_eol(); + } + // The old parser allowed dangling attributes before a "sync" to carry through + // the "sync", so we will too, for now. + if (attributes_in_update_list && attrbuf.size() > 0) + error("dangling attribute"); + } + + expect_keyword("end"); + expect_eol(); + } + + RTLILFrontendWorker(RTLIL::Design *design) : design(design) {} + + void parse(std::istream *f) + { + this->f = f; + line_num = 0; + advance_to_next_nonempty_line(); + while (f->good()) + { + if (try_parse_keyword("attribute")) { + parse_attribute(); + continue; + } + if (try_parse_keyword("module")) { + parse_module(); + continue; + } + if (try_parse_keyword("autoidx")) { + autoidx = std::max(autoidx, parse_integer()); + expect_eol(); + continue; + } + error("Unexpected token: %s", error_token()); + } + if (attrbuf.size() != 0) + error("dangling attribute"); + } +}; + struct RTLILFrontend : public Frontend { RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { } void help() override @@ -63,9 +798,7 @@ struct RTLILFrontend : public Frontend { } void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = false; - RTLIL_FRONTEND::flag_lib = false; + RTLILFrontendWorker worker(design); log_header(design, "Executing RTLIL frontend.\n"); @@ -73,17 +806,17 @@ struct RTLILFrontend : public Frontend { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-nooverwrite") { - RTLIL_FRONTEND::flag_nooverwrite = true; - RTLIL_FRONTEND::flag_overwrite = false; + worker.flag_nooverwrite = true; + worker.flag_overwrite = false; continue; } if (arg == "-overwrite") { - RTLIL_FRONTEND::flag_nooverwrite = false; - RTLIL_FRONTEND::flag_overwrite = true; + worker.flag_nooverwrite = false; + worker.flag_overwrite = true; continue; } if (arg == "-lib") { - RTLIL_FRONTEND::flag_lib = true; + worker.flag_lib = true; continue; } break; @@ -92,14 +825,8 @@ struct RTLILFrontend : public Frontend { log("Input filename: %s\n", filename); - RTLIL_FRONTEND::lexin = f; - RTLIL_FRONTEND::current_design = design; - rtlil_frontend_yydebug = false; - rtlil_frontend_yyrestart(NULL); - rtlil_frontend_yyparse(); - rtlil_frontend_yylex_destroy(); + worker.parse(f); } } RTLILFrontend; YOSYS_NAMESPACE_END - diff --git a/frontends/rtlil/rtlil_frontend.h b/frontends/rtlil/rtlil_frontend.h deleted file mode 100644 index 31cfb80b4..000000000 --- a/frontends/rtlil/rtlil_frontend.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * 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. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -#ifndef RTLIL_FRONTEND_H -#define RTLIL_FRONTEND_H - -#include "kernel/yosys.h" - -YOSYS_NAMESPACE_BEGIN - -namespace RTLIL_FRONTEND { - extern std::istream *lexin; - extern RTLIL::Design *current_design; - extern bool flag_nooverwrite; - extern bool flag_overwrite; - extern bool flag_lib; -} - -YOSYS_NAMESPACE_END - -extern int rtlil_frontend_yydebug; -int rtlil_frontend_yylex(void); -void rtlil_frontend_yyerror(char const *s); -void rtlil_frontend_yywarning(char const *s); -void rtlil_frontend_yyrestart(FILE *f); -int rtlil_frontend_yyparse(void); -int rtlil_frontend_yylex_destroy(void); -int rtlil_frontend_yyget_lineno(void); - -#endif - diff --git a/frontends/rtlil/rtlil_lexer.l b/frontends/rtlil/rtlil_lexer.l deleted file mode 100644 index c374dd395..000000000 --- a/frontends/rtlil/rtlil_lexer.l +++ /dev/null @@ -1,150 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * 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. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -%{ - -#ifdef __clang__ -// bison generates code using the 'register' storage class specifier -#pragma clang diagnostic ignored "-Wdeprecated-register" -#endif - -#include -#include "frontends/rtlil/rtlil_frontend.h" -#include "rtlil_parser.tab.hh" - -USING_YOSYS_NAMESPACE - -#define YY_INPUT(buf,result,max_size) \ - result = readsome(*RTLIL_FRONTEND::lexin, buf, max_size) - -%} - -%option yylineno -%option noyywrap -%option nounput -%option prefix="rtlil_frontend_yy" - -%x STRING - -%% - -"autoidx" { return TOK_AUTOIDX; } -"module" { return TOK_MODULE; } -"attribute" { return TOK_ATTRIBUTE; } -"parameter" { return TOK_PARAMETER; } -"signed" { return TOK_SIGNED; } -"real" { return TOK_REAL; } -"wire" { return TOK_WIRE; } -"memory" { return TOK_MEMORY; } -"width" { return TOK_WIDTH; } -"upto" { return TOK_UPTO; } -"offset" { return TOK_OFFSET; } -"size" { return TOK_SIZE; } -"input" { return TOK_INPUT; } -"output" { return TOK_OUTPUT; } -"inout" { return TOK_INOUT; } -"cell" { return TOK_CELL; } -"connect" { return TOK_CONNECT; } -"switch" { return TOK_SWITCH; } -"case" { return TOK_CASE; } -"assign" { return TOK_ASSIGN; } -"sync" { return TOK_SYNC; } -"low" { return TOK_LOW; } -"high" { return TOK_HIGH; } -"posedge" { return TOK_POSEDGE; } -"negedge" { return TOK_NEGEDGE; } -"edge" { return TOK_EDGE; } -"always" { return TOK_ALWAYS; } -"global" { return TOK_GLOBAL; } -"init" { return TOK_INIT; } -"update" { return TOK_UPDATE; } -"memwr" { return TOK_MEMWR; } -"process" { return TOK_PROCESS; } -"end" { return TOK_END; } - -[a-z]+ { return TOK_INVALID; } - -"\\"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } -"$"[^ \t\r\n]+ { rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } - -[0-9]+'s?[01xzm-]* { rtlil_frontend_yylval.string = strdup(yytext); return TOK_VALUE; } --?[0-9]+ { - char *end = nullptr; - errno = 0; - long value = strtol(yytext, &end, 10); - log_assert(end == yytext + strlen(yytext)); - if (errno == ERANGE) - return TOK_INVALID; // literal out of range of long - if (value < INT_MIN || value > INT_MAX) - return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms) - rtlil_frontend_yylval.integer = value; - return TOK_INT; -} - -\" { BEGIN(STRING); } -\\. { yymore(); } -\" { - BEGIN(0); - char *yystr = strdup(yytext); - yystr[strlen(yytext) - 1] = 0; - int i = 0, j = 0; - while (yystr[i]) { - if (yystr[i] == '\\' && yystr[i + 1]) { - i++; - if (yystr[i] == 'n') - yystr[i] = '\n'; - else if (yystr[i] == 't') - yystr[i] = '\t'; - else if ('0' <= yystr[i] && yystr[i] <= '7') { - yystr[i] = yystr[i] - '0'; - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { - yystr[i + 1] = yystr[i] * 8 + yystr[i + 1] - '0'; - i++; - } - } - } - yystr[j++] = yystr[i++]; - } - yystr[j] = 0; - rtlil_frontend_yylval.string = yystr; - return TOK_STRING; -} -. { yymore(); } - -"#"[^\n]* /* ignore comments */ -[ \t] /* ignore non-newline whitespaces */ -[\r\n]+ { return TOK_EOL; } - -. { return *yytext; } - -%% - -// this is a hack to avoid the 'yyinput defined but not used' error msgs -void *rtlil_frontend_avoid_input_warnings() { - return (void*)&yyinput; -} diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y deleted file mode 100644 index 2b8d7b7ab..000000000 --- a/frontends/rtlil/rtlil_parser.y +++ /dev/null @@ -1,525 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * 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. - * - * --- - * - * A very simple and straightforward frontend for the RTLIL text - * representation. - * - */ - -%require "3.0" - -%{ -#include -#include "frontends/rtlil/rtlil_frontend.h" -YOSYS_NAMESPACE_BEGIN -namespace RTLIL_FRONTEND { - std::istream *lexin; - RTLIL::Design *current_design; - RTLIL::Module *current_module; - RTLIL::Wire *current_wire; - RTLIL::Memory *current_memory; - RTLIL::Cell *current_cell; - RTLIL::Process *current_process; - std::vector*> switch_stack; - std::vector case_stack; - dict attrbuf; - bool flag_nooverwrite, flag_overwrite, flag_lib; - bool delete_current_module; -} -using namespace RTLIL_FRONTEND; -YOSYS_NAMESPACE_END -USING_YOSYS_NAMESPACE -%} - -%define api.prefix {rtlil_frontend_yy} - -/* The union is defined in the header, so we need to provide all the - * includes it requires - */ -%code requires { -#include -#include -#include "frontends/rtlil/rtlil_frontend.h" -} - -%union { - char *string; - int integer; - YOSYS_NAMESPACE_PREFIX RTLIL::Const *data; - YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec; - std::vector *rsigspec; -} - -%token TOK_ID TOK_VALUE TOK_STRING -%token TOK_INT -%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT -%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC -%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT -%token TOK_UPDATE TOK_MEMWR TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET -%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO - -%type sigspec_list_reversed -%type sigspec sigspec_list -%type sync_type -%type constant - -%expect 0 -%debug - -%% - -input: - optional_eol { - attrbuf.clear(); - } design { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - }; - -EOL: - optional_eol TOK_EOL; - -optional_eol: - optional_eol TOK_EOL | /* empty */; - -design: - design module | - design attr_stmt | - design autoidx_stmt | - /* empty */; - -module: - TOK_MODULE TOK_ID EOL { - delete_current_module = false; - if (current_design->has($2)) { - RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { - log("Ignoring blackbox re-definition of module %s.\n", $2); - delete_current_module = true; - } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of module %s.", $2).c_str()); - } else if (flag_nooverwrite) { - log("Ignoring re-definition of module %s.\n", $2); - delete_current_module = true; - } else { - log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2); - current_design->remove(existing_mod); - } - } - current_module = new RTLIL::Module; - current_module->name = $2; - current_module->attributes = attrbuf; - if (!delete_current_module) - current_design->add(current_module); - attrbuf.clear(); - free($2); - } module_body TOK_END { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - current_module->fixup_ports(); - if (delete_current_module) - delete current_module; - else if (flag_lib) - current_module->makeblackbox(); - current_module = nullptr; - } EOL; - -module_body: - module_body module_stmt | - /* empty */; - -module_stmt: - param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; - -param_stmt: - TOK_PARAMETER TOK_ID EOL { - current_module->avail_parameters($2); - free($2); - }; - -param_defval_stmt: - TOK_PARAMETER TOK_ID constant EOL { - current_module->avail_parameters($2); - current_module->parameter_default_values[$2] = *$3; - delete $3; - free($2); - }; - -attr_stmt: - TOK_ATTRIBUTE TOK_ID constant EOL { - attrbuf[$2] = *$3; - delete $3; - free($2); - }; - -autoidx_stmt: - TOK_AUTOIDX TOK_INT EOL { - autoidx = max(autoidx, $2); - }; - -wire_stmt: - TOK_WIRE { - current_wire = current_module->addWire("$__rtlil_frontend_tmp__"); - current_wire->attributes = attrbuf; - attrbuf.clear(); - } wire_options TOK_ID EOL { - if (current_module->wire($4) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of wire %s.", $4).c_str()); - current_module->rename(current_wire, $4); - free($4); - }; - -wire_options: - wire_options TOK_WIDTH TOK_INT { - current_wire->width = $3; - } | - wire_options TOK_WIDTH TOK_INVALID { - rtlil_frontend_yyerror("RTLIL error: invalid wire width"); - } | - wire_options TOK_UPTO { - current_wire->upto = true; - } | - wire_options TOK_SIGNED { - current_wire->is_signed = true; - } | - wire_options TOK_OFFSET TOK_INT { - current_wire->start_offset = $3; - } | - wire_options TOK_INPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = false; - } | - wire_options TOK_OUTPUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = false; - current_wire->port_output = true; - } | - wire_options TOK_INOUT TOK_INT { - current_wire->port_id = $3; - current_wire->port_input = true; - current_wire->port_output = true; - } | - /* empty */; - -memory_stmt: - TOK_MEMORY { - current_memory = new RTLIL::Memory; - current_memory->attributes = attrbuf; - attrbuf.clear(); - } memory_options TOK_ID EOL { - if (current_module->memories.count($4) != 0) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of memory %s.", $4).c_str()); - current_memory->name = $4; - current_module->memories[$4] = current_memory; - free($4); - }; - -memory_options: - memory_options TOK_WIDTH TOK_INT { - current_memory->width = $3; - } | - memory_options TOK_SIZE TOK_INT { - current_memory->size = $3; - } | - memory_options TOK_OFFSET TOK_INT { - current_memory->start_offset = $3; - } | - /* empty */; - -cell_stmt: - TOK_CELL TOK_ID TOK_ID EOL { - if (current_module->cell($3) != nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell %s.", $3).c_str()); - current_cell = current_module->addCell($3, $2); - current_cell->attributes = attrbuf; - attrbuf.clear(); - free($2); - free($3); - } cell_body TOK_END EOL; - -cell_body: - cell_body TOK_PARAMETER TOK_ID constant EOL { - current_cell->parameters[$3] = *$4; - free($3); - delete $4; - } | - cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL { - current_cell->parameters[$4] = *$5; - current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED; - free($4); - delete $5; - } | - cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL { - current_cell->parameters[$4] = *$5; - current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL; - free($4); - delete $5; - } | - cell_body TOK_CONNECT TOK_ID sigspec EOL { - if (current_cell->hasPort($3)) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell port %s.", $3).c_str()); - current_cell->setPort($3, *$4); - delete $4; - free($3); - } | - /* empty */; - -proc_stmt: - TOK_PROCESS TOK_ID EOL { - if (current_module->processes.count($2) != 0) - rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str()); - current_process = current_module->addProcess($2); - current_process->attributes = attrbuf; - switch_stack.clear(); - switch_stack.push_back(¤t_process->root_case.switches); - case_stack.clear(); - case_stack.push_back(¤t_process->root_case); - attrbuf.clear(); - free($2); - } case_body sync_list TOK_END EOL; - -switch_stmt: - TOK_SWITCH sigspec EOL { - RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; - rule->signal = *$2; - rule->attributes = attrbuf; - switch_stack.back()->push_back(rule); - attrbuf.clear(); - delete $2; - } attr_list switch_body TOK_END EOL; - -attr_list: - /* empty */ | - attr_list attr_stmt; - -switch_body: - switch_body TOK_CASE { - RTLIL::CaseRule *rule = new RTLIL::CaseRule; - rule->attributes = attrbuf; - switch_stack.back()->back()->cases.push_back(rule); - switch_stack.push_back(&rule->switches); - case_stack.push_back(rule); - attrbuf.clear(); - } compare_list EOL case_body { - switch_stack.pop_back(); - case_stack.pop_back(); - } | - /* empty */; - -compare_list: - sigspec { - case_stack.back()->compare.push_back(*$1); - delete $1; - } | - compare_list ',' sigspec { - case_stack.back()->compare.push_back(*$3); - delete $3; - } | - /* empty */; - -case_body: - case_body attr_stmt | - case_body switch_stmt | - case_body assign_stmt | - /* empty */; - -assign_stmt: - TOK_ASSIGN sigspec sigspec EOL { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - - // See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this - // warning - if (!switch_stack.back()->empty()) { - rtlil_frontend_yywarning( - "case rule assign statements after switch statements may cause unexpected behaviour. " - "The assign statement is reordered to come before all switch statements." - ); - } - - case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); - delete $2; - delete $3; - }; - -sync_list: - sync_list TOK_SYNC sync_type sigspec EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType($3); - rule->signal = *$4; - current_process->syncs.push_back(rule); - delete $4; - } update_list | - sync_list TOK_SYNC TOK_ALWAYS EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STa; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_GLOBAL EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STg; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - sync_list TOK_SYNC TOK_INIT EOL { - RTLIL::SyncRule *rule = new RTLIL::SyncRule; - rule->type = RTLIL::SyncType::STi; - rule->signal = RTLIL::SigSpec(); - current_process->syncs.push_back(rule); - } update_list | - /* empty */; - -sync_type: - TOK_LOW { $$ = RTLIL::ST0; } | - TOK_HIGH { $$ = RTLIL::ST1; } | - TOK_POSEDGE { $$ = RTLIL::STp; } | - TOK_NEGEDGE { $$ = RTLIL::STn; } | - TOK_EDGE { $$ = RTLIL::STe; }; - -update_list: - update_list TOK_UPDATE sigspec sigspec EOL { - current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4)); - delete $3; - delete $4; - } | - update_list attr_list TOK_MEMWR TOK_ID sigspec sigspec sigspec constant EOL { - RTLIL::MemWriteAction act; - act.attributes = attrbuf; - act.memid = $4; - act.address = *$5; - act.data = *$6; - act.enable = *$7; - act.priority_mask = *$8; - current_process->syncs.back()->mem_write_actions.push_back(std::move(act)); - attrbuf.clear(); - free($4); - delete $5; - delete $6; - delete $7; - delete $8; - } | - /* empty */; - -constant: - TOK_VALUE { - char *ep; - int width = strtol($1, &ep, 10); - bool is_signed = false; - if (*ep == '\'') { - ep++; - } - if (*ep == 's') { - is_signed = true; - ep++; - } - std::list bits; - while (*ep != 0) { - RTLIL::State bit = RTLIL::Sx; - switch (*ep) { - case '0': bit = RTLIL::S0; break; - case '1': bit = RTLIL::S1; break; - case 'x': bit = RTLIL::Sx; break; - case 'z': bit = RTLIL::Sz; break; - case '-': bit = RTLIL::Sa; break; - case 'm': bit = RTLIL::Sm; break; - } - bits.push_front(bit); - ep++; - } - - if (bits.size() == 0) - bits.push_back(RTLIL::Sx); - while ((int)bits.size() < width) { - RTLIL::State bit = bits.back(); - if (bit == RTLIL::S1) - bit = RTLIL::S0; - bits.push_back(bit); - } - while ((int)bits.size() > width) - bits.pop_back(); - RTLIL::Const::Builder builder(bits.size()); - for (RTLIL::State bit : bits) - builder.push_back(bit); - $$ = new RTLIL::Const(builder.build()); - if (is_signed) { - $$->flags |= RTLIL::CONST_FLAG_SIGNED; - } - free($1); - } | - TOK_INT { - $$ = new RTLIL::Const($1); - } | - TOK_STRING { - $$ = new RTLIL::Const($1); - free($1); - }; - -sigspec: - constant { - $$ = new RTLIL::SigSpec(*$1); - delete $1; - } | - TOK_ID { - if (current_module->wire($1) == nullptr) - rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str()); - $$ = new RTLIL::SigSpec(current_module->wire($1)); - free($1); - } | - sigspec '[' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0) - rtlil_frontend_yyerror("bit index out of range"); - $$ = new RTLIL::SigSpec($1->extract($3)); - delete $1; - } | - sigspec '[' TOK_INT ':' TOK_INT ']' { - if ($3 >= $1->size() || $3 < 0 || $3 < $5) - rtlil_frontend_yyerror("invalid slice"); - $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1)); - delete $1; - } | - '{' sigspec_list '}' { - $$ = $2; - }; - -sigspec_list_reversed: - sigspec_list_reversed sigspec { - $$->push_back(*$2); - delete $2; - } | - /* empty */ { - $$ = new std::vector; - }; - -sigspec_list: sigspec_list_reversed { - $$ = new RTLIL::SigSpec; - for (auto it = $1->rbegin(); it != $1->rend(); it++) - $$->append(*it); - delete $1; - }; - -conn_stmt: - TOK_CONNECT sigspec sigspec EOL { - if (attrbuf.size() != 0) - rtlil_frontend_yyerror("dangling attribute"); - current_module->connect(*$2, *$3); - delete $2; - delete $3; - }; From 915ad949f9fb0dd9286da8e052c9cbb5233348e3 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 16 Sep 2025 01:17:45 +0000 Subject: [PATCH 28/49] Limit the maximum size of parsed RTLIL constants to 1 Gb. Without this check it's trivially easy to crash Yosys with a tiny RTLIL input by specifying a constant with very large width. Fuzz testers love hitting this over and over again. --- frontends/rtlil/rtlil_frontend.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index d7511055b..b54cd8f14 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -31,6 +31,10 @@ YOSYS_NAMESPACE_BEGIN struct RTLILFrontendWorker { + // Forbid constants of more than 1 Gb. + // This will help us not explode on malicious RTLIL. + static constexpr int MAX_CONST_WIDTH = 1024 * 1024 * 1024; + std::istream *f = nullptr; RTLIL::Design *design; bool flag_nooverwrite = false; @@ -267,7 +271,7 @@ struct RTLILFrontendWorker { // Can't test value<0 here because we need to stop parsing after '-0' if (negative_value || line[0] != '\'') { if (width < INT_MIN || width > INT_MAX) - error("Integer %lld out of range in `%s'.", width, error_token()); + error("Integer %lld out of range before `%s'.", width, error_token()); consume_whitespace_and_comments(); return RTLIL::Const(width); } @@ -278,6 +282,8 @@ struct RTLILFrontendWorker { ++idx; std::vector bits; + if (width > MAX_CONST_WIDTH) + error("Constant width %lld out of range before `%s`.", width, error_token()); bits.reserve(width); while (true) { RTLIL::State bit; From d45223976ab4e9ed4b7d3d1973d3379d89d54e6c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Wed, 1 Oct 2025 02:47:47 +0000 Subject: [PATCH 29/49] Optimize `IdString::empty()` I actually saw this take 0.6% of the time in an `opt_clean` pass (under Module::check()). Trivial issue, but the fix is also trivial and simple. --- kernel/rtlil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 5271a3111..9f636c5a2 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -411,7 +411,7 @@ struct RTLIL::IdString } bool empty() const { - return c_str()[0] == 0; + return index_ == 0; } void clear() { From d5beb65d306116147f104f750089c660255c1eb5 Mon Sep 17 00:00:00 2001 From: Ethan Sifferman Date: Wed, 1 Oct 2025 10:19:25 -0700 Subject: [PATCH 30/49] added SIMLIB_VERILATOR_COMPAT --- techlibs/common/simlib.v | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 977b8bbf9..e0fb9fbfa 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -31,6 +31,14 @@ * */ +// If using Verilator, define SIMLIB_VERILATOR_COMPAT +`ifdef SIMLIB_VERILATOR_COMPAT + /* verilator lint_save */ + /* verilator lint_off DEFOVERRIDE */ + `define SIMLIB_NOCONNECT + /* verilator lint_restore */ +`endif + // -------------------------------------------------------- //* ver 2 //* title Bit-wise inverter From f7120e9c2a922ef5e4520abd681816aa00c91bca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 00:22:09 +0000 Subject: [PATCH 31/49] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 54ad13d7c..ca589ff91 100644 --- a/Makefile +++ b/Makefile @@ -164,7 +164,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.57+254 +YOSYS_VER := 0.57+260 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) From 88be7283532237b71c1777a9953bb1aab260321a Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Sun, 21 Sep 2025 22:36:27 +0300 Subject: [PATCH 32/49] pyosys: rewrite using pybind11 - Rewrite all Python features to use the pybind11 library instead of boost::python. Unlike boost::python, pybind11 is a header-only library that is just included by Pyosys code, saving a lot of compile time on wheels. - Factor out as much "translation" code from the generator into proper C++ files - Fix running the embedded interpreter not supporting "from pyosys import libyosys as ys" like wheels - Move Python-related elements to `pyosys` directory at the root of the repo - Slight shift in bridging semantics: - Containers are declared as "opaque types" and are passed by reference to Python - many methods have been implemented to make them feel right at home without the overhead/ambiguity of copying to Python and then copying back after mutation - Monitor/Pass use "trampoline" pattern to support virual methods overridable in Python: virtual methods no longer require `py_` prefix - Create really short test set for pyosys that just exercises basic functionality --- .github/workflows/wheels.yml | 14 +- .github/workflows/wheels/cibw_before_build.sh | 21 - CODEOWNERS | 3 +- Makefile | 30 +- docs/source/yosys_internals/hashing.rst | 2 +- examples/python-api/pass.py | 22 +- kernel/driver.cc | 29 +- kernel/yosys.cc | 25 +- kernel/yosys_common.h | 3 + misc/py_wrap_generator.py | 2549 ----------------- passes/cmds/plugin.cc | 34 +- pyosys/.gitignore | 1 + {misc => pyosys}/__init__.py | 1 + pyosys/generator.py | 2039 +++++++++++++ pyosys/hashlib.h | 275 ++ pyosys/wrappers_tpl.cc | 248 ++ pyproject.toml | 6 + setup.py | 43 +- tests/pyosys/run_tests.py | 39 + tests/pyosys/spm.cut.v.gz | Bin 0 -> 5294 bytes tests/pyosys/test_data_read.py | 45 + tests/pyosys/test_dict.py | 13 + tests/pyosys/test_idict.py | 31 + tests/pyosys/test_import.py | 3 + tests/pyosys/test_monitor.py | 22 + tests/pyosys/test_pass.py | 34 + tests/pyosys/test_script.py | 21 + 27 files changed, 2879 insertions(+), 2674 deletions(-) delete mode 100644 misc/py_wrap_generator.py create mode 100644 pyosys/.gitignore rename {misc => pyosys}/__init__.py (99%) create mode 100644 pyosys/generator.py create mode 100644 pyosys/hashlib.h create mode 100644 pyosys/wrappers_tpl.cc create mode 100644 pyproject.toml create mode 100644 tests/pyosys/run_tests.py create mode 100644 tests/pyosys/spm.cut.v.gz create mode 100644 tests/pyosys/test_data_read.py create mode 100644 tests/pyosys/test_dict.py create mode 100644 tests/pyosys/test_idict.py create mode 100644 tests/pyosys/test_import.py create mode 100644 tests/pyosys/test_monitor.py create mode 100644 tests/pyosys/test_pass.py create mode 100644 tests/pyosys/test_script.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 2a5b7e024..b561b5d32 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -55,11 +55,6 @@ jobs: submodules: true persist-credentials: false - uses: actions/setup-python@v5 - - name: Get Boost Source - shell: bash - run: | - mkdir -p boost - curl -L https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-b2-nodocs.tar.gz | tar --strip-components=1 -xzC boost - name: Get FFI shell: bash run: | @@ -103,21 +98,16 @@ jobs: CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh CIBW_ENVIRONMENT: > OPTFLAGS=-O3 - CXXFLAGS=-I./boost/pfx/include - LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig - makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a' PATH="$PWD/bison/src:$PATH" CIBW_ENVIRONMENT_MACOS: > OPTFLAGS=-O3 - CXXFLAGS=-I./boost/pfx/include - LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 - makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' + makeFlags='CONFIG=clang' PATH="$PWD/bison/src:$PATH" CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh - CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py + CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py python3 - uses: actions/upload-artifact@v4 with: name: python-wheels-${{ matrix.os.runner }} diff --git a/.github/workflows/wheels/cibw_before_build.sh b/.github/workflows/wheels/cibw_before_build.sh index 018b0e0df..4e81688d0 100644 --- a/.github/workflows/wheels/cibw_before_build.sh +++ b/.github/workflows/wheels/cibw_before_build.sh @@ -11,24 +11,3 @@ if [ "$(uname)" != "Linux" ]; then fi python3 --version python3-config --includes - -# Build boost -cd ./boost -## Delete the artefacts from previous builds (if any) -rm -rf ./pfx -## Bootstrap bjam -./bootstrap.sh --prefix=./pfx -## Build Boost against current version of Python, only for -## static linkage (Boost is statically linked because system boost packages -## wildly vary in versions, including the libboost_python3 version) -./b2\ - -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu)\ - --prefix=./pfx\ - --with-filesystem\ - --with-system\ - --with-python\ - cxxflags="$(python3-config --includes) -std=c++17 -fPIC"\ - cflags="$(python3-config --includes) -fPIC"\ - link=static\ - variant=release\ - install diff --git a/CODEOWNERS b/CODEOWNERS index 46d37ad2f..4617c39bb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -38,7 +38,8 @@ techlibs/gowin/ @pepijndevos techlibs/gatemate/ @pu-cc # pyosys -misc/*.py @btut +pyosys/* @donn +setup.py @donn backends/firrtl @ucbjrl @azidar diff --git a/Makefile b/Makefile index ca589ff91..c9cbd0810 100644 --- a/Makefile +++ b/Makefile @@ -133,10 +133,6 @@ LINKFLAGS += -rdynamic ifneq ($(shell :; command -v brew),) BREW_PREFIX := $(shell brew --prefix)/opt $(info $$BREW_PREFIX is [${BREW_PREFIX}]) -ifeq ($(ENABLE_PYOSYS),1) -CXXFLAGS += -I$(BREW_PREFIX)/boost/include -LINKFLAGS += -L$(BREW_PREFIX)/boost/lib -L$(BREW_PREFIX)/boost-python3/lib -endif CXXFLAGS += -I$(BREW_PREFIX)/readline/include -I$(BREW_PREFIX)/flex/include LINKFLAGS += -L$(BREW_PREFIX)/readline/lib -L$(BREW_PREFIX)/flex/lib PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) @@ -353,26 +349,14 @@ ifeq ($(ENABLE_PYOSYS),1) LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags)) LIBS += $(shell $(PYTHON_CONFIG) --libs) EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) +PYBIND11_INCLUDE ?= $(shell $(PYTHON_EXECUTABLE) -m pybind11 --includes) +CXXFLAGS += -I$(PYBIND11_INCLUDE) -DWITH_PYTHON CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON -# Detect name of boost_python library. Some distros use boost_python-py, other boost_python, some only use the major version number, some a concatenation of major and minor version numbers -CHECK_BOOST_PYTHON = (echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(LINKFLAGS) $(EXE_LIBS) $(LIBS) -l$(1) - > /dev/null 2>&1 && echo "-l$(1)") -BOOST_PYTHON_LIB ?= $(shell \ - $(call CHECK_BOOST_PYTHON,boost_python-py$(subst .,,$(PYTHON_VERSION))) || \ - $(call CHECK_BOOST_PYTHON,boost_python-py$(PYTHON_MAJOR_VERSION)) || \ - $(call CHECK_BOOST_PYTHON,boost_python$(subst .,,$(PYTHON_VERSION))) || \ - $(call CHECK_BOOST_PYTHON,boost_python$(PYTHON_MAJOR_VERSION)) \ -) - -ifeq ($(BOOST_PYTHON_LIB),) -$(error BOOST_PYTHON_LIB could not be detected. Please define manually) -endif - -LIBS += $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem -PY_WRAPPER_FILE = kernel/python_wrappers +PY_WRAPPER_FILE = pyosys/wrappers OBJS += $(PY_WRAPPER_FILE).o -PY_GEN_SCRIPT= py_wrap_generator -PY_WRAP_INCLUDES := $(shell $(PYTHON_EXECUTABLE) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()") +PY_GEN_SCRIPT = pyosys/generator.py +PY_WRAP_INCLUDES := $(shell $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) endif # ENABLE_PYOSYS ifeq ($(ENABLE_READLINE),1) @@ -779,9 +763,9 @@ endif $(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(CXX) $(CXXFLAGS) -x c++ -o $@ -E -P - ifeq ($(ENABLE_PYOSYS),1) -$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES) +$(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT) pyosys/wrappers_tpl.cc $(PY_WRAP_INCLUDES) pyosys/hashlib.h $(Q) mkdir -p $(dir $@) - $(P) $(PYTHON_EXECUTABLE) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")" + $(P) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) $(PY_WRAPPER_FILE).cc endif %.o: %.cpp diff --git a/docs/source/yosys_internals/hashing.rst b/docs/source/yosys_internals/hashing.rst index 1993e617a..1255f6f7c 100644 --- a/docs/source/yosys_internals/hashing.rst +++ b/docs/source/yosys_internals/hashing.rst @@ -36,7 +36,7 @@ The main characteristics are: all compilers, standard libraries and architectures. In addition to ``dict`` and ``pool`` there is also an ``idict`` that -creates a bijective map from ``K`` to the integers. For example: +creates a bijective map from ``K`` to incrementing integers. For example: :: diff --git a/examples/python-api/pass.py b/examples/python-api/pass.py index dbef0a13f..d87e09078 100755 --- a/examples/python-api/pass.py +++ b/examples/python-api/pass.py @@ -1,22 +1,25 @@ #!/usr/bin/python3 -import libyosys as ys +from pyosys import libyosys as ys + +from pathlib import Path import matplotlib.pyplot as plt -import numpy as np + +__file_dir__ = Path(__file__).absolute().parent class CellStatsPass(ys.Pass): def __init__(self): super().__init__("cell_stats", "Shows cell stats as plot") - def py_help(self): + def help(self): ys.log("This pass uses the matplotlib library to display cell stats\n") - def py_execute(self, args, design): + def execute(self, args, design): ys.log_header(design, "Plotting cell stats\n") cell_stats = {} - for module in design.selected_whole_modules_warn(): + for module in design.all_selected_whole_modules(): for cell in module.selected_cells(): if cell.type.str() in cell_stats: cell_stats[cell.type.str()] += 1 @@ -29,4 +32,11 @@ class CellStatsPass(ys.Pass): def py_clear_flags(self): ys.log("Clear Flags - CellStatsPass\n") -p = CellStatsPass() +p = CellStatsPass() # register + +if __name__ == "__main__": + design = ys.Design() + ys.run_pass(f"read_verilog {__file_dir__.parents[1] / 'tests' / 'simple' / 'fiedler-cooley.v'}", design) + ys.run_pass("prep", design) + ys.run_pass("opt -full", design) + ys.run_pass("cell_stats", design) diff --git a/kernel/driver.cc b/kernel/driver.cc index bbe4e46f3..a27c0a00f 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -92,8 +92,9 @@ int main(int argc, char **argv) yosys_banner(); yosys_setup(); #ifdef WITH_PYTHON - PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); - PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); + py::object sys = py::module_::import("sys"); + sys.attr("path").attr("append")(proc_self_dirname()); + sys.attr("path").attr("append")(proc_share_dirname()); #endif if (argc == 2) @@ -516,8 +517,9 @@ int main(int argc, char **argv) yosys_setup(); #ifdef WITH_PYTHON - PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); - PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); + py::object sys = py::module_::import("sys"); + sys.attr("path").attr("append")(proc_self_dirname()); + sys.attr("path").attr("append")(proc_share_dirname()); #endif log_error_atexit = yosys_atexit; @@ -567,21 +569,18 @@ int main(int argc, char **argv) #endif } else if (scriptfile_python) { #ifdef WITH_PYTHON - PyObject *sys = PyImport_ImportModule("sys"); + py::list new_argv; int py_argc = special_args.size() + 1; - PyObject *new_argv = PyList_New(py_argc); - PyList_SetItem(new_argv, 0, PyUnicode_FromString(scriptfile.c_str())); + new_argv.append(scriptfile); for (int i = 1; i < py_argc; ++i) - PyList_SetItem(new_argv, i, PyUnicode_FromString(special_args[i - 1].c_str())); + new_argv.append(special_args[i - 1]); - PyObject *old_argv = PyObject_GetAttrString(sys, "argv"); - PyObject_SetAttrString(sys, "argv", new_argv); - Py_DECREF(old_argv); + py::setattr(sys, "argv", new_argv); - PyObject *py_path = PyUnicode_FromString(scriptfile.c_str()); - PyObject_SetAttrString(sys, "_yosys_script_path", py_path); - Py_DECREF(py_path); - PyRun_SimpleString("import os, sys; sys.path.insert(0, os.path.dirname(os.path.abspath(sys._yosys_script_path)))"); + py::object Path = py::module_::import("pathlib").attr("Path"); + py::object scriptfile_python_path = Path(scriptfile).attr("parent"); + + sys.attr("path").attr("insert")(0, py::str(scriptfile_python_path)); FILE *scriptfp = fopen(scriptfile.c_str(), "r"); if (scriptfp == nullptr) { diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 95beca75c..9cab12bf6 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -64,13 +64,8 @@ #endif #ifdef WITH_PYTHON -#if PY_MAJOR_VERSION >= 3 -# define INIT_MODULE PyInit_libyosys - extern "C" PyObject* INIT_MODULE(); -#else -# define INIT_MODULE initlibyosys - extern "C" void INIT_MODULE(); -#endif +extern "C" PyObject* PyInit_libyosys(); +extern "C" PyObject* PyInit_pyosys(); #include #endif @@ -189,6 +184,17 @@ int run_command(const std::string &command, std::function +#include + +namespace py = pybind11; #endif #ifndef _YOSYS_ diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py deleted file mode 100644 index aa1406f9b..000000000 --- a/misc/py_wrap_generator.py +++ /dev/null @@ -1,2549 +0,0 @@ -# -# yosys -- Yosys Open SYnthesis Suite -# -# Copyright (C) 2012 Claire Xenia Wolf -# -# 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. -# -# Author Benedikt Tutzer -# - -import copy - -#Map c++ operator Syntax to Python functions -wrappable_operators = { - "<" : "__lt__", - "==": "__eq__", - "!=": "__ne__", - "+" : "__add__", - "-" : "__sub__", - "*" : "__mul__", - "/" : "__div__", - "()": "__call__" - } - -#Restrict certain strings from being function names in Python -keyword_aliases = { - "in" : "in_", - "False" : "False_", - "None" : "None_", - "True" : "True_", - "and" : "and_", - "as" : "as_", - "assert" : "assert_", - "break" : "break_", - "class" : "class_", - "continue" : "continue_", - "def" : "def_", - "del" : "del_", - "elif" : "elif_", - "else" : "else_", - "except" : "except_", - "for" : "for_", - "from" : "from_", - "global" : "global_", - "if" : "if_", - "import" : "import_", - "in" : "in_", - "is" : "is_", - "lambda" : "lambda_", - "nonlocal" : "nonlocal_", - "not" : "not_", - "or" : "or_", - "pass" : "pass_", - "raise" : "raise_", - "return" : "return_", - "try" : "try_", - "while" : "while_", - "with" : "with_", - "yield" : "yield_" - } - -#These can be used without any explicit conversion -primitive_types = ["void", "bool", "int", "double", "size_t", "std::string", - "string", "string_view", "std::string_view", "State", "char_p", "std::source_location", "source_location"] - -from enum import Enum - -#Ways to link between Python- and C++ Objects -class link_types(Enum): - global_list = 1 #Manage a global list of objects in C++, the Python - #object contains a key to find the corresponding C++ - #object and a Pointer to the object to verify it is - #still the same, making collisions unlikely to happen - ref_copy = 2 #The Python object contains a copy of the C++ object. - #The C++ object is deleted when the Python object gets - #deleted - pointer = 3 #The Python Object contains a pointer to it's C++ - #counterpart - derive = 4 #The Python-Wrapper is derived from the C++ object. - -class attr_types(Enum): - star = "*" - amp = "&" - ampamp = "&&" - default = "" - -#For source-files -class Source: - name = "" - classes = [] - - def __init__(self, name, classes): - self.name = name - self.classes = classes - -#Splits a list by the given delimiter, without splitting strings inside -#pointy-brackets (< and >) -def split_list(str_def, delim): - str_def = str_def.strip() - if len(str_def) == 0: - return [] - if str_def.count(delim) == 0: - return [str_def] - if str_def.count("<") == 0: - return str_def.split(delim) - if str_def.find("<") < str_def.find(" "): - closing = find_closing(str_def[str_def.find("<")+1:], "<", ">") + str_def.find("<") - comma = str_def[closing:].find(delim) - if comma == -1: - return [str_def] - comma = closing + comma - else: - comma = str_def.find(delim) - rest = split_list(str_def[comma+1:], delim) - ret = [str_def[:comma]] - if rest != None and len(rest) != 0: - ret.extend(rest) - return ret - -#Represents a Type -class WType: - name = "" - cont = None - attr_type = attr_types.default - - def __init__(self, name = "", cont = None, attr_type = attr_types.default): - self.name = name - self.cont = cont - self.attr_type = attr_type - - #Python type-string - def gen_text(self): - text = self.name - if self.name in enum_names: - text = enum_by_name(self.name).namespace + "::" + self.name - if self.cont != None: - return known_containers[self.name].typename - return text - - #C++ type-string - def gen_text_cpp(self): - postfix = "" - if self.attr_type == attr_types.star: - postfix = "*" - if self.name in primitive_types: - return self.name + postfix - if self.name in enum_names: - return enum_by_name(self.name).namespace + "::" + self.name + postfix - if self.name in classnames: - return class_by_name(self.name).namespace + "::" + self.name + postfix - text = self.name - if self.cont != None: - text += "<" - for a in self.cont.args: - text += a.gen_text_cpp() + ", " - text = text[:-2] - text += ">" - return text - - @staticmethod - def from_string(str_def, containing_file, line_number): - str_def = str_def.strip() - if len(str_def) == 0: - return None - str_def = str_def.replace("RTLIL::SigSig", "std::pair").replace("SigSig", "std::pair") - t = WType() - t.name = "" - t.cont = None - t.attr_type = attr_types.default - if str_def.find("<") != -1:# and str_def.find("<") < str_def.find(" "): - str_def = str_def.replace("const ", "") - - candidate = WContainer.from_string(str_def, containing_file, line_number) - if candidate == None: - return None - t.name = str_def[:str_def.find("<")] - - if t.name.count("*") + t.name.count("&") > 1: - return None - - if t.name.count("*") == 1 or str_def[0] == '*' or str_def[-1] == '*': - t.attr_type = attr_types.star - t.name = t.name.replace("*","") - elif t.name.count("&&") == 1: - t.attr_type = attr_types.ampamp - t.name = t.name.replace("&&","") - elif t.name.count("&") == 1 or str_def[0] == '&' or str_def[-1] == '&': - t.attr_type = attr_types.amp - t.name = t.name.replace("&","") - - t.cont = candidate - if(t.name not in known_containers): - return None - return t - - prefix = "" - - if str.startswith(str_def, "const "): - if "char_p" in str_def: - prefix = "const " - str_def = str_def[6:] - if str.startswith(str_def, "unsigned "): - prefix = "unsigned " + prefix - str_def = str_def[9:] - while str.startswith(str_def, "long "): - prefix= "long " + prefix - str_def = str_def[5:] - while str.startswith(str_def, "short "): - prefix = "short " + prefix - str_def = str_def[6:] - - str_def = str_def.split("::")[-1] - - if str_def.count("*") + str_def.count("&") >= 2: - return None - - if str_def.count("*") == 1: - t.attr_type = attr_types.star - str_def = str_def.replace("*","") - elif str_def.count("&&") == 1: - t.attr_type = attr_types.ampamp - str_def = str_def.replace("&&","") - elif str_def.count("&") == 1: - t.attr_type = attr_types.amp - str_def = str_def.replace("&","") - - if len(str_def) > 0 and str_def.split("::")[-1] not in primitive_types and str_def.split("::")[-1] not in classnames and str_def.split("::")[-1] not in enum_names: - return None - - if str_def.count(" ") == 0: - t.name = (prefix + str_def).replace("char_p", "char *") - t.cont = None - return t - return None - -#Represents a container-type -class WContainer: - name = "" - args = [] - - def from_string(str_def, containing_file, line_number): - if str_def == None or len(str_def) < 4: - return None - cont = WContainer() - cont.name = str_def[:str_def.find("<")] - str_def = str_def[str_def.find("<")+1:find_closing(str_def, "<", ">")] - cont.args = [] - for arg in split_list(str_def, ","): - candidate = WType.from_string(arg.strip(), containing_file, line_number) - if candidate == None: - return None - if candidate.name == "void": - return None - cont.args.append(candidate) - return cont - -#Translators between Python and C++ containers -#Base Type -class Translator: - tmp_cntr = 0 - typename = "DefaultType" - orig_name = "DefaultCpp" - - @classmethod - def gen_type(c, types): - return "\nImplement a function that outputs the c++ type of this container here\n" - - @classmethod - def translate(c, varname, types, prefix): - return "\nImplement a function translating a python container to a c++ container here\n" - - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - return "\nImplement a function translating a c++ container to a python container here\n" - -#Translates list-types (vector, pool, set), that only differ in their name and -#the name of the insertion function -class PythonListTranslator(Translator): - typename = "boost::python::list" - insert_name = "Default" - - #generate the c++ type string - @classmethod - def gen_type(c, types): - text = c.orig_name + "<" - if types[0].name in primitive_types: - text += types[0].name - elif types[0].name in known_containers: - text += known_containers[types[0].name].gen_type(types[0].cont.args) - else: - text += class_by_name(types[0].name).namespace + "::" + types[0].name - if types[0].attr_type == attr_types.star: - text += "*" - text += ">" - return text - - #Generate C++ code to translate from a boost::python::list - @classmethod - def translate(c, varname, types, prefix): - text = prefix + c.gen_type(types) + " " + varname + "___tmp;" - cntr_name = "cntr_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "); " + cntr_name + "++)" - text += prefix + "{" - tmp_name = "tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - if types[0].name in known_containers: - text += prefix + "\t" + known_containers[types[0].name].typename + " " + tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "[" + cntr_name + "]);" - text += known_containers[types[0].name].translate(tmp_name, types[0].cont.args, prefix+"\t") - tmp_name = tmp_name + "___tmp" - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + ");" - elif types[0].name in classnames: - text += prefix + "\t" + types[0].name + "* " + tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "[" + cntr_name + "]);" - if types[0].attr_type == attr_types.star: - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + "->get_cpp_obj());" - else: - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(*" + tmp_name + "->get_cpp_obj());" - else: - text += prefix + "\t" + types[0].name + " " + tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "[" + cntr_name + "]);" - text += prefix + "\t" + varname + "___tmp" + c.insert_name + "(" + tmp_name + ");" - text += prefix + "}" - return text - - #Generate C++ code to translate to a boost::python::list - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - text = prefix + c.typename + " " + varname + "___tmp;" - tmp_name = "tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - if ref: - text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" - else: - text += prefix + "for(auto " + tmp_name + " : " + varname + ")" - text += prefix + "{" - if types[0].name in classnames: - if types[0].attr_type == attr_types.star: - text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));" - else: - text += prefix + "\t" + varname + "___tmp.append(*" + types[0].name + "::get_py_obj(&" + tmp_name + "));" - elif types[0].name in known_containers: - text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[0].attr_type == attr_types.star) - text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + "___tmp);" - else: - text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");" - text += prefix + "}" - return text - -class IDictTranslator(PythonListTranslator): - typename = "boost::python::list" - orig_name = "idict" - insert_name = "" - -#Sub-type for std::set -class SetTranslator(PythonListTranslator): - insert_name = ".insert" - orig_name = "std::set" - -#Sub-type for std::vector -class VectorTranslator(PythonListTranslator): - insert_name = ".push_back" - orig_name = "std::vector" - -#Sub-type for pool -class PoolTranslator(PythonListTranslator): - insert_name = ".insert" - orig_name = "pool" - -#Sub-type for ObjRange -class ObjRangeTranslator(PythonListTranslator): - orig_name = "RTLIL::ObjRange" - -#Translates dict-types (dict, std::map), that only differ in their name and -#the name of the insertion function -class PythonDictTranslator(Translator): - typename = "boost::python::dict" - insert_name = "Default" - - @classmethod - def gen_type(c, types): - text = c.orig_name + "<" - if types[0].name in primitive_types: - text += types[0].name - elif types[0].name in known_containers: - text += known_containers[types[0].name].gen_type(types[0].cont.args) - else: - text += class_by_name(types[0].name).namespace + "::" + types[0].name - if types[0].attr_type == attr_types.star: - text += "*" - text += ", " - if types[1].name in primitive_types: - text += types[1].name - elif types[1].name in known_containers: - text += known_containers[types[1].name].gen_type(types[1].cont.args) - else: - text += class_by_name(types[1].name).namespace + "::" + types[1].name - if types[1].attr_type == attr_types.star: - text += "*" - text += ">" - return text - - #Generate c++ code to translate from a boost::python::dict - @classmethod - def translate(c, varname, types, prefix): - text = prefix + c.gen_type(types) + " " + varname + "___tmp;" - text += prefix + "boost::python::list " + varname + "_keylist = " + varname + ".keys();" - cntr_name = "cntr_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "_keylist); " + cntr_name + "++)" - text += prefix + "{" - key_tmp_name = "key_tmp_" + str(Translator.tmp_cntr) - val_tmp_name = "val_tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - - if types[0].name in known_containers: - text += prefix + "\t" + known_containers[types[0].name].typename + " " + key_tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "_keylist[ " + cntr_name + " ]);" - text += known_containers[types[0].name].translate(key_tmp_name, types[0].cont.args, prefix+"\t") - key_tmp_name = key_tmp_name + "___tmp" - elif types[0].name in classnames: - text += prefix + "\t" + types[0].name + "* " + key_tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "_keylist[ " + cntr_name + " ]);" - else: - text += prefix + "\t" + types[0].name + " " + key_tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "_keylist[ " + cntr_name + " ]);" - - if types[1].name in known_containers: - text += prefix + "\t" + known_containers[types[1].name].typename + " " + val_tmp_name + " = boost::python::extract<" + known_containers[types[1].name].typename + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" - text += known_containers[types[1].name].translate(val_tmp_name, types[1].cont.args, prefix+"\t") - val_tmp_name = val_tmp_name + "___tmp" - elif types[1].name in classnames: - text += prefix + "\t" + types[1].name + "* " + val_tmp_name + " = boost::python::extract<" + types[1].name + "*>(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" - else: - text += prefix + "\t" + types[1].name + " " + val_tmp_name + " = boost::python::extract<" + types[1].name + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" - - text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(std::pair<" + types[0].gen_text_cpp() + ", " + types[1].gen_text_cpp() + ">(" - - if types[0].name not in classnames: - text += key_tmp_name - else: - if types[0].attr_type != attr_types.star: - text += "*" - text += key_tmp_name + "->get_cpp_obj()" - - text += ", " - if types[1].name not in classnames: - text += val_tmp_name - else: - if types[1].attr_type != attr_types.star: - text += "*" - text += val_tmp_name + "->get_cpp_obj()" - text += "));\n" + prefix + "}" - return text - - #Generate c++ code to translate to a boost::python::dict - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - text = prefix + c.typename + " " + varname + "___tmp;" - tmp_name = "tmp_" + str(Translator.tmp_cntr) - Translator.tmp_cntr = Translator.tmp_cntr + 1 - if ref: - text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" - else: - text += prefix + "for(auto " + tmp_name + " : " + varname + ")" - text += prefix + "{" - if types[1].name in known_containers: - text += prefix + "\tauto " + tmp_name + "_second = " + tmp_name + ".second;" - text += known_containers[types[1].name].translate_cpp(tmp_name + "_second", types[1].cont.args, prefix + "\t", types[1].attr_type == attr_types.star) - - if types[0].name in classnames: - text += prefix + "\t" + varname + "___tmp[" + types[0].name + "::get_py_obj(" + tmp_name + ".first)] = " - elif types[0].name not in known_containers: - text += prefix + "\t" + varname + "___tmp[" + tmp_name + ".first] = " - - if types[1].name in classnames: - if types[1].attr_type == attr_types.star: - text += types[1].name + "::get_py_obj(" + tmp_name + ".second);" - else: - text += "*" + types[1].name + "::get_py_obj(&" + tmp_name + ".second);" - elif types[1].name in known_containers: - text += tmp_name + "_second___tmp;" - else: - text += tmp_name + ".second;" - text += prefix + "}" - return text - -#Sub-type for dict -class DictTranslator(PythonDictTranslator): - insert_name = "insert" - orig_name = "dict" - -#Sub_type for std::map -class MapTranslator(PythonDictTranslator): - insert_name = "insert" - orig_name = "std::map" - -#Translator for std::pair. Derived from PythonDictTranslator because the -#gen_type function is the same (because both have two template parameters) -class TupleTranslator(PythonDictTranslator): - typename = "boost::python::tuple" - orig_name = "std::pair" - - #Generate c++ code to translate from a boost::python::tuple - @classmethod - def translate(c, varname, types, prefix): - text = prefix + types[0].name + " " + varname + "___tmp_0 = boost::python::extract<" + types[0].name + ">(" + varname + "[0]);" - text += prefix + types[1].name + " " + varname + "___tmp_1 = boost::python::extract<" + types[1].name + ">(" + varname + "[1]);" - text += prefix + TupleTranslator.gen_type(types) + " " + varname + "___tmp(" - if types[0].name.split(" ")[-1] in primitive_types: - text += varname + "___tmp_0, " - else: - text += "*" + varname + "___tmp_0.get_cpp_obj(), " - if types[1].name.split(" ")[-1] in primitive_types: - text += varname + "___tmp_1);" - else: - text += "*" + varname + "___tmp_1.get_cpp_obj());" - return text - - #Generate c++ code to translate to a boost::python::tuple - @classmethod - def translate_cpp(c, varname, types, prefix, ref): - # if the tuple is a pair of SigSpecs (aka SigSig), then we need - # to call get_py_obj() on each item in the tuple - if types[0].name in classnames: - first_var = types[0].name + "::get_py_obj(" + varname + ".first)" - else: - first_var = varname + ".first" - if types[1].name in classnames: - second_var = types[1].name + "::get_py_obj(" + varname + ".second)" - else: - second_var = varname + ".second" - text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");" - return text - -#Associate the Translators with their c++ type -known_containers = { - "std::set" : SetTranslator, - "std::vector" : VectorTranslator, - "pool" : PoolTranslator, - "idict" : IDictTranslator, - "dict" : DictTranslator, - "std::pair" : TupleTranslator, - "std::map" : MapTranslator, - "RTLIL::ObjRange" : ObjRangeTranslator -} - -class Attribute: - wtype = None - varname = None - is_const = False - default_value = None - pos = None - pos_counter = 0 - coerce_arg = None - - def __init__(self, wtype, varname, is_const = False, default_value = None): - self.wtype = wtype - self.varname = varname - self.is_const = is_const - self.default_value = None - self.container = None - - @staticmethod - def from_string(str_def, containing_file, line_number, *, owner_fn_name=""): - if len(str_def) < 3: - return None - orig = str_def - arg = Attribute(None, None) - prefix = "" - arg.wtype = None - arg.varname = None - arg.is_const = False - arg.default_value = None - arg.container = None - if str.startswith(str_def, "const "): - arg.is_const = True - str_def = str_def[6:] - if str.startswith(str_def, "unsigned "): - prefix = "unsigned " - str_def = str_def[9:] - while str.startswith(str_def, "long "): - prefix= "long " + prefix - str_def = str_def[5:] - while str.startswith(str_def, "short "): - prefix = "short " + prefix - str_def = str_def[6:] - - if str_def.find("<") != -1 and str_def.find("<") < str_def.find(" "): - closing = find_closing(str_def[str_def.find("<"):], "<", ">") + str_def.find("<") + 1 - arg.wtype = WType.from_string(str_def[:closing].strip(), containing_file, line_number) - str_def = str_def[closing+1:] - else: - if str_def.count(" ") > 0: - arg.wtype = WType.from_string(prefix + str_def[:str_def.find(" ")].strip(), containing_file, line_number) - str_def = str_def[str_def.find(" ")+1:] - else: - arg.wtype = WType.from_string(prefix + str_def.strip(), containing_file, line_number) - str_def = "" - arg.varname = "" - - if arg.wtype == None: - return None - if str_def.count("=") == 0: - arg.varname = str_def.strip() - if arg.varname.find(" ") > 0: - return None - else: - arg.varname = str_def[:str_def.find("=")].strip() - if arg.varname.find(" ") > 0: - return None - str_def = str_def[str_def.find("=")+1:].strip() - arg.default_value = str_def[arg.varname.find("=")+1:].strip() - if len(arg.varname) == 0: - arg.varname = None - return arg - if arg.varname[0] == '*': - arg.wtype.attr_type = attr_types.star - arg.varname = arg.varname[1:] - elif arg.varname[0] == '&': - if arg.wtype.attr_type != attr_types.default: - return None - if arg.varname[1] == '&': - arg.wtype.attr_type = attr_types.ampamp - arg.varname = arg.varname[2:] - else: - arg.wtype.attr_type = attr_types.amp - arg.varname = arg.varname[1:] - - # handle string views - if arg.wtype.name in ["std::string_view", "string_view"]: - if arg.varname == "format" and owner_fn_name.startswith("log_"): - # coerce format strings to "%s" (not bridgable) - arg.coerce_arg = '"%s"' - elif arg.varname == "prefix" and "warning" in owner_fn_name: - # coerce warning prefix to "warning:" - arg.coerce_arg = '"Warning: "' - else: - # boost::python can't bridge string views, so just copy them - arg.wtype.name = "string" - - return arg - - #Generates the varname. If the attribute has no name in the header file, - #a name is generated - def gen_varname(self): - if self.varname != None: - return self.varname - if self.wtype.name == "void": - return "" - if self.pos == None: - self.pos = Attribute.pos_counter - Attribute.pos_counter = Attribute.pos_counter + 1 - return "gen_varname_" + str(self.pos) - - #Generates the text for the function headers with wrapper types - def gen_listitem(self): - prefix = "" - if self.is_const: - prefix = "const " - if self.wtype.name in classnames: - return prefix + self.wtype.name + "* " + self.gen_varname() - if self.wtype.name in known_containers: - return prefix + known_containers[self.wtype.name].typename + " " + self.gen_varname() - return prefix + self.wtype.name + " " + self.gen_varname() - - #Generates the test for the function headers with c++ types - def gen_listitem_cpp(self): - prefix = "" - if self.is_const: - prefix = "const " - infix = "" - if self.wtype.attr_type == attr_types.star: - infix = "*" - elif self.wtype.attr_type == attr_types.amp: - infix = "&" - elif self.wtype.attr_type == attr_types.ampamp: - infix = "&&" - if self.wtype.name in known_containers: - return prefix + known_containers[self.wtype.name].gen_type(self.wtype.cont.args) + " " + infix + self.gen_varname() - if self.wtype.name in classnames: - return prefix + class_by_name(self.wtype.name).namespace + "::" + self.wtype.name + " " + infix + self.gen_varname() - return prefix + self.wtype.name + " " + infix + self.gen_varname() - - #Generates the listitem withtout the varname, so the signature can be - #compared - def gen_listitem_hash(self): - prefix = "" - if self.is_const: - prefix = "const " - if self.wtype.name in classnames: - return prefix + self.wtype.name + "* " - if self.wtype.name in known_containers: - return known_containers[self.wtype.name].typename - return prefix + self.wtype.name - - #Generate Translation code for the attribute - def gen_translation(self): - if self.wtype.name in known_containers: - return known_containers[self.wtype.name].translate(self.gen_varname(), self.wtype.cont.args, "\n\t\t") - return "" - - #Generate Translation code from c++ for the attribute - def gen_translation_cpp(self): - if self.wtype.name in known_containers: - return known_containers[self.wtype.name].translate_cpp(self.gen_varname(), self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) - return "" - - #Generate Text for the call - def gen_call(self): - ret = self.gen_varname() - if self.wtype.name in known_containers: - if self.wtype.attr_type == attr_types.star: - return "&" + ret + "___tmp" - return ret + "___tmp" - if self.wtype.name in classnames: - if self.wtype.attr_type != attr_types.star: - ret = "*" + ret - return ret + "->get_cpp_obj()" - if self.wtype.name == "char *" and self.gen_varname() in ["format", "fmt"]: - return "\"%s\", " + self.gen_varname() - if self.wtype.attr_type == attr_types.star: - return "&" + ret - return ret - - def gen_call_cpp(self): - ret = self.gen_varname() - if self.wtype.name.split(" ")[-1] in primitive_types or self.wtype.name in enum_names: - if self.wtype.attr_type == attr_types.star: - return "&" + ret - return ret - if self.wtype.name not in classnames: - if self.wtype.attr_type == attr_types.star: - return "&" + ret + "___tmp" - return ret + "___tmp" - if self.wtype.attr_type != attr_types.star: - ret = "*" + ret - return self.wtype.name + "::get_py_obj(" + self.gen_varname() + ")" - - #Generate cleanup code - def gen_cleanup(self): - if self.wtype.name in primitive_types or self.wtype.name in classnames or self.wtype.name in enum_names or not self.wtype.attr_type == attr_types.star or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): - return "" - return "\n\t\tdelete " + self.gen_varname() + "___tmp;" - -class WClass: - name = None - namespace = None - link_type = None - base_class = None - id_ = None - string_id = None - hash_id = None - needs_clone = False - found_funs = [] - found_vars = [] - found_constrs = [] - - def __init__(self, name, link_type, id_, string_id = None, hash_id = None, needs_clone = False): - self.name = name - self.namespace = None - self.base_class = None - self.link_type = link_type - self.id_ = id_ - self.string_id = string_id - self.hash_id = hash_id - self.needs_clone = needs_clone - self.found_funs = [] - self.found_vars = [] - self.found_constrs = [] - - def printable_constrs(self): - ret = 0 - for con in self.found_constrs: - if not con.protected: - ret += 1 - return ret - - def gen_decl(self, filename): - long_name = self.namespace + "::" + self.name - - text = "\n\t// WRAPPED from " + filename - text += "\n\tstruct " + self.name - if self.link_type == link_types.derive: - text += " : public " + self.namespace + "::" + self.name - text += "\n\t{\n" - - if self.link_type != link_types.derive: - - text += "\t\t" + long_name + "* ref_obj;\n" - - if self.link_type == link_types.ref_copy or self.link_type == link_types.pointer: - text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn ref_obj;\n\t\t}\n" - elif self.link_type == link_types.global_list: - text += "\t\t" + self.id_.wtype.name + " " + self.id_.varname + ";\n" - text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{" - text += "\n\t\t\t" + long_name + "* ret = " + long_name + "::get_all_" + self.name.lower() + "s()->at(this->" + self.id_.varname + ");" - text += "\n\t\t\tif(ret != NULL && ret == this->ref_obj)" - text += "\n\t\t\t\treturn ret;" - text += "\n\t\t\tthrow std::runtime_error(\"" + self.name + "'s c++ object does not exist anymore.\");" - text += "\n\t\t\treturn NULL;" - text += "\n\t\t}\n" - - #if self.link_type != link_types.pointer: - text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" - text += "\n\t\t\tif(ref == nullptr){" - text += "\n\t\t\t\tthrow std::runtime_error(\"" + self.name + " does not exist.\");" - text += "\n\t\t\t}" - text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" - if self.link_type == link_types.pointer: - text += "\n\t\t\tret->ref_obj = ref;" - if self.link_type == link_types.ref_copy: - if self.needs_clone: - text += "\n\t\t\tret->ref_obj = ref->clone();" - else: - text += "\n\t\t\tret->ref_obj = new "+long_name+"(*ref);" - if self.link_type == link_types.global_list: - text += "\n\t\t\tret->ref_obj = ref;" - text += "\n\t\t\tret->" + self.id_.varname + " = ret->ref_obj->" + self.id_.varname + ";" - text += "\n\t\t\treturn ret;" - text += "\n\t\t}\n" - - if self.link_type == link_types.ref_copy: - text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + " ref)\n\t\t{" - text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" - if self.needs_clone: - text += "\n\t\t\tret->ref_obj = ref.clone();" - else: - text += "\n\t\t\tret->ref_obj = new "+long_name+"(ref);" - text += "\n\t\t\treturn ret;" - text += "\n\t\t}\n" - - for con in self.found_constrs: - text += con.gen_decl() - if self.base_class is not None: - text += "\n\t\tvirtual ~" + self.name + "() { };" - for var in self.found_vars: - text += var.gen_decl() - for fun in self.found_funs: - text += fun.gen_decl() - - - if self.link_type == link_types.derive: - duplicates = {} - for fun in self.found_funs: - if fun.name in duplicates: - fun.gen_alias() - duplicates[fun.name].gen_alias() - else: - duplicates[fun.name] = fun - - text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn (" + self.namespace + "::" + self.name +"*)this;\n\t\t}\n" - text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" - text += "\n\t\t\treturn (" + self.name + "*)ref;" - text += "\n\t\t}\n" - - for con in self.found_constrs: - text += con.gen_decl_derive() - for var in self.found_vars: - text += var.gen_decl() - for fun in self.found_funs: - text += fun.gen_decl_virtual() - - if self.hash_id != None: - text += "\n\t\tunsigned int get_hash_py()" - text += "\n\t\t{" - suffix = f"->{self.hash_id}" if self.hash_id else f"->{self.hash_id}" - if self.hash_id == "": - text += f"\n\t\t\treturn run_hash(*(get_cpp_obj()));" - else: - text += f"\n\t\t\treturn run_hash(get_cpp_obj()->{self.hash_id});" - text += "\n\t\t}" - - text += "\n\t};\n" - - if self.link_type == link_types.derive: - text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">" - text += "\n\t{" - - for con in self.found_constrs: - text += con.gen_decl_wrapperclass() - for fun in self.found_funs: - text += fun.gen_default_impl() - - text += "\n\t};" - - text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)" - text += "\n\t{" - text += "\n\t\tostr << \"" + self.name - if self.string_id != None: - text +=" \\\"\"" - text += " << ref.get_cpp_obj()->" + self.string_id - text += " << \"\\\"\"" - else: - text += " at \" << ref.get_cpp_obj()" - text += ";" - text += "\n\t\treturn ostr;" - text += "\n\t}" - text += "\n" - - return text - - def gen_funs(self, filename): - text = "" - if self.link_type != link_types.derive: - for con in self.found_constrs: - text += con.gen_def() - for var in self.found_vars: - text += var.gen_def() - for fun in self.found_funs: - text += fun.gen_def() - else: - for var in self.found_vars: - text += var.gen_def() - for fun in self.found_funs: - text += fun.gen_def_virtual() - return text - - def gen_boost_py_body(self): - text = "" - if self.printable_constrs() == 0 or not self.contains_default_constr(): - text += ", no_init" - text += ")" - text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))" - text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))" - for con in self.found_constrs: - text += con.gen_boost_py() - for var in self.found_vars: - text += var.gen_boost_py() - static_funs = [] - for fun in self.found_funs: - text += fun.gen_boost_py() - if fun.is_static and fun.alias not in static_funs: - static_funs.append(fun.alias) - for fun in static_funs: - text += "\n\t\t\t.staticmethod(\"" + fun + "\")" - - if self.hash_id != None: - text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)" - text += "\n\t\t\t;\n" - return text - - def gen_boost_py(self): - body = self.gen_boost_py_body() - base_info = "" - if self.base_class is not None: - base_info = ", bases<" + (self.base_class.name) + ">" - - if self.link_type == link_types.derive: - text = "\n\t\tclass_<" + self.name + base_info + ">(\"Cpp" + self.name + "\"" - text += body - text += "\n\t\tclass_<" + self.name - text += "Wrap, boost::noncopyable" - text += ">(\"" + self.name + "\"" - text += body - else: - text = "\n\t\tclass_<" + self.name + base_info + ">(\"" + self.name + "\"" - text += body - return text - - - def contains_default_constr(self): - for c in self.found_constrs: - if len(c.args) == 0: - return True - return False - -#CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE - -sources = [ - Source("kernel/celltypes",[ - WClass("CellType", link_types.pointer, None, None, "type", True), - WClass("CellTypes", link_types.pointer, None, None, None, True) - ] - ), - Source("kernel/consteval",[ - WClass("ConstEval", link_types.pointer, None, None, None, True) - ] - ), - Source("kernel/log",[]), - Source("kernel/register",[ - WClass("Pass", link_types.derive, None, None, None, True), - ] - ), - Source("kernel/rtlil",[ - WClass("IdString", link_types.ref_copy, None, "str()", ""), - WClass("Const", link_types.ref_copy, None, "as_string()", ""), - WClass("AttrObject", link_types.ref_copy, None, None, None), - WClass("NamedObject", link_types.ref_copy, None, None, None), - WClass("Selection", link_types.ref_copy, None, None, None), - WClass("Monitor", link_types.derive, None, None, None), - WClass("CaseRule",link_types.ref_copy, None, None, None, True), - WClass("SwitchRule",link_types.ref_copy, None, None, None, True), - WClass("SyncRule", link_types.ref_copy, None, None, None, True), - WClass("Process", link_types.ref_copy, None, "name.c_str()", "name"), - WClass("SigChunk", link_types.ref_copy, None, None, None), - WClass("SigBit", link_types.ref_copy, None, None, ""), - WClass("SigSpec", link_types.ref_copy, None, None, ""), - WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), - WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), - WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), - WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", ""), - WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "") - ] - ), - #Source("kernel/satgen",[ - # ] - # ), - #Source("libs/ezsat/ezsat",[ - # ] - # ), - #Source("libs/ezsat/ezminisat",[ - # ] - # ), - Source("kernel/sigtools",[ - WClass("SigMap", link_types.pointer, None, None, None, True) - ] - ), - Source("kernel/yosys",[ - ] - ), - Source("kernel/cost",[]) - ] - -blacklist_methods = ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow"] - -enum_names = ["State","SyncType","ConstFlags"] - -enums = [] #Do not edit -glbls = [] - -unowned_functions = [] - -classnames = [] -for source in sources: - for wclass in source.classes: - classnames.append(wclass.name) - -def class_by_name(name): - for source in sources: - for wclass in source.classes: - if wclass.name == name: - return wclass - return None - -def enum_by_name(name): - for e in enums: - if e.name == name: - return e - return None - -def find_closing(text, open_tok, close_tok): - if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok): - return text.find(close_tok) - return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1 - -def unpretty_string(s): - s = s.strip() - while s.find(" ") != -1: - s = s.replace(" "," ") - while s.find("\t") != -1: - s = s.replace("\t"," ") - s = s.replace(" (","(") - return s - -class WEnum: - name = None - namespace = None - values = [] - - def from_string(str_def, namespace, line_number): - str_def = str_def.strip() - if not str.startswith(str_def, "enum "): - return None - if str_def.count(";") != 1: - return None - str_def = str_def[5:] - enum = WEnum() - split = str_def.split(":") - if(len(split) != 2): - return None - enum.name = split[0].strip() - if enum.name not in enum_names: - return None - str_def = split[1] - if str_def.count("{") != str_def.count("}") != 1: - return None - if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';': - return None - str_def = str_def.split("{")[-1].split("}")[0] - enum.values = [] - for val in str_def.split(','): - enum.values.append(val.strip().split('=')[0].strip()) - enum.namespace = namespace - return enum - - def gen_boost_py(self): - text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n" - for value in self.values: - text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n" - text += "\t\t\t;\n" - return text - - def __str__(self): - ret = "Enum " + self.namespace + "::" + self.name + "(\n" - for val in self.values: - ret = ret + "\t" + val + "\n" - return ret + ")" - - def __repr__(self): - return __str__(self) - -class WConstructor: - orig_text = None - args = [] - containing_file = None - member_of = None - duplicate = False - protected = False - - def __init__(self, containing_file, class_): - self.orig_text = "Auto generated default constructor" - self.args = [] - self.containing_file = containing_file - self.member_of = class_ - self.protected = False - - def from_string(str_def, containing_file, class_, line_number, protected = False): - if class_ == None: - return None - if str_def.count("delete;") > 0: - return None - con = WConstructor(containing_file, class_) - con.orig_text = str_def - con.args = [] - con.duplicate = False - con.protected = protected - if str.startswith(str_def, "inline "): - str_def = str_def[7:] - if not str.startswith(str_def, class_.name + "("): - return None - str_def = str_def[len(class_.name)+1:] - found = find_closing(str_def, "(", ")") - if found == -1: - return None - str_def = str_def[0:found].strip() - if len(str_def) == 0: - return con - args = split_list(str_def, ",") - for i, arg in enumerate(args): - parsed = Attribute.from_string(arg.strip(), containing_file, line_number) - if parsed == None: - return None - # Only allow std::source_location as defaulted last argument, and - # don't append so it takes default value - if parsed.wtype.name in ["std::source_location", "source_location"]: - if parsed.default_value is None or i != len(args) - 1: - debug("std::source_location not defaulted last arg of " + class_.name + " is unsupported", 2) - return None - continue - con.args.append(parsed) - return con - - def gen_decl(self): - if self.duplicate or self.protected: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");\n" - return text - - def gen_decl_derive(self): - if self.duplicate or self.protected: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ")" - if len(self.args) == 0: - return text + "{}" - text += " : " - text += self.member_of.namespace + "::" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_call() + ", " - if len(self.args) > 0: - text = text[:-2] - text += "){}\n" - return text - - def gen_decl_wrapperclass(self): - if self.duplicate or self.protected: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" + self.member_of.name + "Wrap(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ")" - if len(self.args) == 0: - return text + "{}" - text += " : " - text += self.member_of.name + "(" - for arg in self.args: - text += arg.gen_call() + ", " - if len(self.args) > 0: - text = text[:-2] - text += "){}\n" - return text - - def gen_decl_hash_py(self): - text = self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");" - return text - - def gen_def(self): - if self.duplicate or self.protected: - return "" - text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t" + self.member_of.name + "::" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text +=")\n\t{" - for arg in self.args: - text += arg.gen_translation() - if self.member_of.link_type != link_types.derive: - text += "\n\t\tthis->ref_obj = new " + self.member_of.namespace + "::" + self.member_of.name + "(" - for arg in self.args: - text += arg.gen_call() + ", " - if len(self.args) > 0: - text = text[:-2] - if self.member_of.link_type != link_types.derive: - text += ");" - if self.member_of.link_type == link_types.global_list: - text += "\n\t\tthis->" + self.member_of.id_.varname + " = this->ref_obj->" + self.member_of.id_.varname + ";" - for arg in self.args: - text += arg.gen_cleanup() - text += "\n\t}\n" - return text - - def gen_boost_py(self): - if self.duplicate or self.protected or len(self.args) == 0: - return "" - text = "\n\t\t\t.def(init" - text += "<" - for a in self.args: - text += a.gen_listitem_hash() + ", " - text = text[0:-2] + ">())" - return text - -class WFunction: - orig_text = None - is_static = False - is_inline = False - is_virtual = False - ret_attr_type = attr_types.default - is_operator = False - ret_type = None - name = None - alias = None - args = [] - containing_file = None - member_of = None - duplicate = False - namespace = "" - - def from_string(str_def, containing_file, class_, line_number, namespace): - if str_def.count("delete;") > 0: - return None - func = WFunction() - func.is_static = False - func.is_inline = False - func.is_virtual = False - func.is_const = False - func.ret_attr_type = attr_types.default - func.is_operator = False - func.member_of = None - func.orig_text = str_def - func.args = [] - func.containing_file = containing_file - func.member_of = class_ - func.duplicate = False - func.namespace = namespace - str_def = str_def.replace("operator ","operator") - - # remove attributes from the start - if str.startswith(str_def, "[[") and "]]" in str_def: - str_def = str_def[str_def.find("]]")+2:] - - if str.startswith(str_def, "static "): - func.is_static = True - str_def = str_def[7:] - else: - func.is_static = False - if str.startswith(str_def, "inline "): - func.is_inline = True - str_def = str_def[7:] - else: - func.is_inline = False - if str.startswith(str_def, "virtual "): - func.is_virtual = True - str_def = str_def[8:] - else: - func.is_virtual = False - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short", "const"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - func.ret_type = WType.from_string(prefix + parts[0], containing_file, line_number) - - if func.ret_type == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - found = str_def.find("(") - if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")): - return None - func.name = str_def[:found] - str_def = str_def[found:] - if func.name.find("operator") != -1 and str.startswith(str_def, "()("): - func.name += "()" - str_def = str_def[2:] - str_def = str_def[1:] - if func.name.find("operator") != -1: - func.is_operator = True - if func.name.find("*") == 0: - func.name = func.name.replace("*", "") - func.ret_type.attr_type = attr_types.star - if func.name.find("&&") == 0: - func.name = func.name.replace("&&", "") - func.ret_type.attr_type = attr_types.ampamp - if func.name.find("&") == 0: - func.name = func.name.replace("&", "") - func.ret_type.attr_type = attr_types.amp - - found = find_closing(str_def, "(", ")") - if found == -1: - return None - - post_qualifiers = str_def[found + 1:].lstrip().replace("{", " {") + " " - if post_qualifiers.startswith("const "): - func.is_const = True - - str_def = str_def[0:found] - if func.name in blacklist_methods: - return None - if func.namespace != None and func.namespace != "": - if (func.namespace + "::" + func.name) in blacklist_methods: - return None - if func.member_of != None: - if (func.namespace + "::" + func.member_of.name + "::" + func.name) in blacklist_methods: - return None - if func.is_operator and func.name.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators: - return None - - testname = func.name - if func.is_operator: - testname = testname[:testname.find("operator")] - if testname.count(")") != 0 or testname.count("(") != 0 or testname.count("~") != 0 or testname.count(";") != 0 or testname.count(">") != 0 or testname.count("<") != 0 or testname.count("throw") != 0: - return None - - func.alias = func.name - if func.name in keyword_aliases: - func.alias = keyword_aliases[func.name] - str_def = str_def[:found].strip() - if(len(str_def) == 0): - return func - args = split_list(str_def, ",") - for i, arg in enumerate(args): - if arg.strip() == "...": - continue - parsed = Attribute.from_string(arg.strip(), containing_file, line_number, owner_fn_name=func.name) - if parsed == None: - return None - # Only allow std::source_location as defaulted last argument, and - # don't append so it takes default value - if parsed.wtype.name in ["std::source_location", "source_location"]: - if parsed.default_value is None or i != len(args) - 1: - debug("std::source_location not defaulted last arg of " + func.name + " is unsupported", 2) - return None - continue - func.args.append(parsed) - return func - - @property - def mangled_name(self): - mangled_typename = lambda code: code.replace("::", "_").replace("<","_").replace(">","_") \ - .replace(" ","").replace("*","").replace(",","") - - return self.name + "".join( - f"__{mangled_typename(arg.wtype.gen_text_cpp())}" for arg in self.args - ) - - def gen_alias(self): - self.alias = self.mangled_name - - def gen_post_qualifiers(self, derived=False): - if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual and derived: - # we drop the qualifiers when deriving callbacks to be implemented in Python - return '' - return ' const' if self.is_const else '' - - def gen_decl(self): - if self.duplicate: - return "" - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\t" - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " " + self.alias + "(" - for arg in self.args: - if arg.coerce_arg: - continue - text += arg.gen_listitem() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += f"){self.gen_post_qualifiers()};\n" - return text - - def gen_decl_virtual(self): - if self.duplicate: - return "" - if not self.is_virtual: - return self.gen_decl() - text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t\tvirtual " - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += ")" - if len(self.args) == 0 and self.ret_type.name == "void": - text += "{}" - else: - text += "\n\t\t{" - for arg in self.args: - text += "\n\t\t\t(void)" + arg.gen_varname() + ";" - if self.ret_type.name == "void": - pass - elif self.ret_type.name == "bool": - text += "\n\t\t\treturn false;" - else: - raise NotImplementedError(self.ret_type.name) - text += "\n\t\t}\n" - text += "\n\t\tvirtual " - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " " + self.name + "(" - for arg in self.args: - text += arg.gen_listitem_cpp() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += f"){self.gen_post_qualifiers()} override;\n" - return text - - def gen_decl_hash_py(self): - text = self.ret_type.gen_text() + " " + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");" - return text - - def gen_def(self): - if self.duplicate: - return "" - text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t" + self.ret_type.gen_text() + " " - if self.member_of != None: - text += self.member_of.name + "::" - text += self.alias + "(" - for arg in self.args: - if arg.coerce_arg: - continue - text += arg.gen_listitem() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += f"){self.gen_post_qualifiers()}\n\t{{" - for arg in self.args: - text += arg.gen_translation() - text += "\n\t\t" - if self.ret_type.name != "void": - if self.ret_type.name in known_containers: - text += self.ret_type.gen_text_cpp() - else: - text += self.ret_type.gen_text() - if self.ret_type.name in classnames or (self.ret_type.name in known_containers and self.ret_type.attr_type == attr_types.star): - text += "*" - text += " ret_ = " - if self.ret_type.name in classnames: - text += self.ret_type.name + "::get_py_obj(" - if self.member_of == None: - text += "::" + self.namespace + "::" + self.name + "(" - elif self.is_static: - text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" - else: - text += "this->get_cpp_obj()->" + self.name + "(" - for arg in self.args: - text += arg.coerce_arg or arg.gen_call() - text += ", " - if len(self.args) > 0: - text = text[:-2] - if self.ret_type.name in classnames: - text += ")" - text += ");" - for arg in self.args: - text += arg.gen_cleanup() - if self.ret_type.name != "void": - if self.ret_type.name in classnames: - text += "\n\t\treturn *ret_;" - elif self.ret_type.name in known_containers: - text += known_containers[self.ret_type.name].translate_cpp("ret_", self.ret_type.cont.args, "\n\t\t", self.ret_type.attr_type == attr_types.star) - text += "\n\t\treturn ret____tmp;" - else: - text += "\n\t\treturn ret_;" - text += "\n\t}\n" - return text - - def gen_def_virtual(self): - if self.duplicate: - return "" - if not self.is_virtual: - return self.gen_def() - text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file - text += "\n\t" - if self.is_static: - text += "static " - text += self.ret_type.gen_text() + " " + self.member_of.name + "::" + self.name + "(" - for arg in self.args: - text += arg.gen_listitem_cpp() - text += ", " - if len(self.args) > 0: - text = text[:-2] - text += f"){self.gen_post_qualifiers()}\n\t{{" - for arg in self.args: - text += arg.gen_translation_cpp() - return_stmt = "return " if self.ret_type.name != "void" else "" - text += f"\n\t\t{return_stmt}" - if self.member_of == None: - text += "::" + self.namespace + "::" + self.alias + "(" - elif self.is_static: - text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" - else: - text += f"const_cast<{self.member_of.name}*>(this)->py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_call_cpp() + ", " - if len(self.args) > 0: - text = text[:-2] - if self.ret_type.name in classnames: - text += ")" - text += ");" - for arg in self.args: - text += arg.gen_cleanup() - text += "\n\t}\n" - return text - - def gen_default_impl(self): - if self.duplicate: - return "" - if not self.is_virtual: - return "" - text = "\n\n\t\t" + self.ret_type.gen_text() + " py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - - call_string = "py_" + self.alias + "(" - for arg in self.args: - call_string += arg.gen_varname() + ", " - if len(self.args) > 0: - call_string = call_string[0:-2] - call_string += ");" - - return_stmt = "return " if self.ret_type.name != "void" else "" - - text += ")\n\t\t{" - text += "\n\t\t\tif (boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\")) {" - text += "\n\t\t\t\ttry {" - text += f"\n\t\t\t\t\t{return_stmt}" + call_string - text += "\n\t\t\t\t} catch (boost::python::error_already_set &) {" - text += "\n\t\t\t\t\tlog_python_exception_as_error();" - text += "\n\t\t\t\t}" - text += "\n\t\t\t} else {" - text += f"\n\t\t\t\t{return_stmt}" + self.member_of.name + "::" + call_string - text += "\n\t\t\t}" - text += "\n\t\t}" - - text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem() + ", " - if len(self.args) > 0: - text = text[:-2] - text += f")\n\t\t{{" - text += f"\n\t\t\t{return_stmt}this->" + self.member_of.name + "::" + call_string - text += "\n\t\t}" - return text - - - def gen_boost_py(self): - if self.duplicate: - return "" - if self.member_of == None: - text = "\n\t\tdef" - else: - text = "\n\t\t\t.def" - if len(self.args) > -1: - if self.ret_type.name in known_containers: - text += "<" + known_containers[self.ret_type.name].typename + " " - else: - text += "<" + self.ret_type.name + " " - if self.member_of == None or self.is_static: - text += "(*)(" - else: - text += "(" + self.member_of.name + "::*)(" - for a in self.args: - if a.coerce_arg: - continue - text += a.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[0:-2] + f"){self.gen_post_qualifiers(True)}>" - else: - text += f"void){self.gen_post_qualifiers(True)}>" - - if self.is_operator: - text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\"" - else: - if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual: - text += "(\"py_" + self.alias + "\"" - else: - text += "(\"" + self.alias + "\"" - if self.member_of != None: - text += ", &" + self.member_of.name + "::" - if self.member_of.link_type == link_types.derive and self.is_virtual: - text += "py_" + self.alias - text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias - else: - text += self.alias - - text += ")" - else: - text += ", " + "YOSYS_PYTHON::" + self.alias + ");" - return text - -class WMember: - orig_text = None - wtype = attr_types.default - name = None - containing_file = None - member_of = None - namespace = "" - is_const = False - - def from_string(str_def, containing_file, class_, line_number, namespace): - member = WMember() - member.orig_text = str_def - member.wtype = None - member.name = "" - member.containing_file = containing_file - member.member_of = class_ - member.namespace = namespace - member.is_const = False - - if str.startswith(str_def, "const "): - member.is_const = True - str_def = str_def[6:] - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) - - if member.wtype == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1: - return None - - found = str_def.find(";") - if found == -1: - return None - - found_eq = str_def.find("=") - if found_eq != -1: - found = found_eq - - member.name = str_def[:found] - str_def = str_def[found+1:] - if member.name.find("*") == 0: - member.name = member.name.replace("*", "") - member.wtype.attr_type = attr_types.star - if member.name.find("&&") == 0: - member.name = member.name.replace("&&", "") - member.wtype.attr_type = attr_types.ampamp - if member.name.find("&") == 0: - member.name = member.name.replace("&", "") - member.wtype.attr_type = attr_types.amp - - if(len(str_def.strip()) != 0): - return None - - if len(member.name.split(",")) > 1: - member_list = [] - for name in member.name.split(","): - name = name.strip(); - member_list.append(WMember()) - member_list[-1].orig_text = member.orig_text - member_list[-1].wtype = member.wtype - member_list[-1].name = name - member_list[-1].containing_file = member.containing_file - member_list[-1].member_of = member.member_of - member_list[-1].namespace = member.namespace - member_list[-1].is_const = member.is_const - return member_list - - return member - - def gen_decl(self): - text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n" - if self.is_const: - return text - if self.wtype.name in classnames: - text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n" - else: - text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n" - return text - - def gen_def(self): - text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()" - text += "\n\t{\n\t\t" - if self.wtype.attr_type == attr_types.star: - text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t" - text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t" - if self.wtype.name in known_containers: - text += self.wtype.gen_text_cpp() - else: - text += self.wtype.gen_text() - - if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): - text += "*" - text += " ret_ = " - if self.wtype.name in classnames: - text += self.wtype.name + "::get_py_obj(" - if self.wtype.attr_type != attr_types.star: - text += "&" - text += "this->get_cpp_obj()->" + self.name - if self.wtype.name in classnames: - text += ")" - text += ";" - - if self.wtype.name in classnames: - text += "\n\t\treturn *ret_;" - elif self.wtype.name in known_containers: - text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) - text += "\n\t\treturn ret____tmp;" - else: - text += "\n\t\treturn ret_;" - text += "\n\t}\n" - - if self.is_const: - return text - - ret = Attribute(self.wtype, "rhs"); - - if self.wtype.name in classnames: - text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)" - else: - text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)" - text += "\n\t{" - text += ret.gen_translation() - text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";" - text += "\n\t}\n" - - return text; - - def gen_boost_py(self): - text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name - if not self.is_const: - text += ", &" + self.member_of.name + "::set_var_py_" + self.name - text += ")" - return text - -class WGlobal: - orig_text = None - wtype = attr_types.default - name = None - containing_file = None - namespace = "" - is_const = False - - def from_string(str_def, containing_file, line_number, namespace): - glbl = WGlobal() - glbl.orig_text = str_def - glbl.wtype = None - glbl.name = "" - glbl.containing_file = containing_file - glbl.namespace = namespace - glbl.is_const = False - - if not str.startswith(str_def, "extern"): - return None - str_def = str_def[7:] - - if str.startswith(str_def, "const "): - glbl.is_const = True - str_def = str_def[6:] - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - glbl.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) - - if glbl.wtype == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1: - return None - - found = str_def.find(";") - if found == -1: - return None - - found_eq = str_def.find("=") - if found_eq != -1: - found = found_eq - - glbl.name = str_def[:found] - str_def = str_def[found+1:] - if glbl.name.find("*") == 0: - glbl.name = glbl.name.replace("*", "") - glbl.wtype.attr_type = attr_types.star - if glbl.name.find("&&") == 0: - glbl.name = glbl.name.replace("&&", "") - glbl.wtype.attr_type = attr_types.ampamp - if glbl.name.find("&") == 0: - glbl.name = glbl.name.replace("&", "") - glbl.wtype.attr_type = attr_types.amp - - if(len(str_def.strip()) != 0): - return None - - if len(glbl.name.split(",")) > 1: - glbl_list = [] - for name in glbl.name.split(","): - name = name.strip(); - glbl_list.append(WGlobal()) - glbl_list[-1].orig_text = glbl.orig_text - glbl_list[-1].wtype = glbl.wtype - glbl_list[-1].name = name - glbl_list[-1].containing_file = glbl.containing_file - glbl_list[-1].namespace = glbl.namespace - glbl_list[-1].is_const = glbl.is_const - return glbl_list - - return glbl - - def gen_def(self): - text = "\n\t" - if self.is_const: - text += "const " - text += self.wtype.gen_text() + " get_var_py_" + self.name + "()" - text += "\n\t{\n\t\t" - if self.wtype.attr_type == attr_types.star: - text += "if(" + self.namespace + "::" + self.name + " == NULL)\n\t\t\t" - text += "throw std::runtime_error(\"" + self.namespace + "::" + self.name + " is NULL\");\n\t\t" - if self.wtype.name in known_containers: - text += self.wtype.gen_text_cpp() - else: - if self.is_const: - text += "const " - text += self.wtype.gen_text() - - if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): - text += "*" - text += " ret_ = " - if self.wtype.name in classnames: - text += self.wtype.name + "::get_py_obj(" - if self.wtype.attr_type != attr_types.star: - text += "&" - text += self.namespace + "::" + self.name - if self.wtype.name in classnames: - text += ")" - text += ";" - - if self.wtype.name in classnames: - text += "\n\t\treturn *ret_;" - elif self.wtype.name in known_containers: - text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) - text += "\n\t\treturn ret____tmp;" - else: - text += "\n\t\treturn ret_;" - text += "\n\t}\n" - - if self.is_const: - return text - - ret = Attribute(self.wtype, "rhs"); - - if self.wtype.name in classnames: - text += "\n\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)" - else: - text += "\n\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)" - text += "\n\t{" - text += ret.gen_translation() - text += "\n\t\t" + self.namespace + "::" + self.name + " = " + ret.gen_call() + ";" - text += "\n\t}\n" - - return text; - - def gen_boost_py(self): - text = "\n\t\t\t.add_static_property(\"" + self.name + "\", &" + "YOSYS_PYTHON::get_var_py_" + self.name - if not self.is_const: - text += ", &YOSYS_PYTHON::set_var_py_" + self.name - text += ")" - return text - -def concat_namespace(tuple_list): - if len(tuple_list) == 0: - return "" - ret = "" - for namespace in tuple_list: - ret += "::" + namespace[0] - return ret[2:] - -def calc_ident(text): - if len(text) == 0 or text[0] != ' ': - return 0 - return calc_ident(text[1:]) + 1 - -def assure_length(text, length, left = False): - if len(text) > length: - return text[:length] - if left: - return text + " "*(length - len(text)) - return " "*(length - len(text)) + text - -def nesting_delta(s): - return s.count("{") - s.count("}") - -def parse_header(source): - debug("Parsing " + source.name + ".pyh",1) - source_file = open(source.name + ".pyh", "r") - - source_text = [] - in_line = source_file.readline() - - namespaces = [] - - while(in_line): - if(len(in_line)>1): - source_text.append(in_line.replace("char *", "char_p ").replace("char* ", "char_p ")) - in_line = source_file.readline() - - i = 0 - - namespaces = [] - classes = [] - private_segment = False - - while i < len(source_text): - line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") - ugly_line = unpretty_string(line) - debug(f"READ:>> {line}", 2) - - # for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line - if 'union {' in line: - j = i+1 - while j < len(source_text): - union_line = source_text[j] - if '};' in union_line: - source_text[j] = '\n' - break - j += 1 - if j != len(source_text): - i += 1 - continue - - if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: - namespace_name = ugly_line[10:].replace("{","").strip() - namespaces.append((namespace_name, ugly_line.count("{"))) - debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----",3) - i += 1 - continue - - if len(namespaces) != 0: - namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + nesting_delta(ugly_line)) - if namespaces[-1][1] == 0: - debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) - namespaces.pop() - i += 1 - continue - - if (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0: - # Opening a record declaration which isn't a forward declaration - struct_name = ugly_line.split(" ")[1].split("::")[-1] - impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1] - complete_namespace = concat_namespace(namespaces) - for namespace in impl_namespaces: - complete_namespace += "::" + namespace - debug("\tFound " + struct_name + " in " + complete_namespace,2) - - base_class_name = None - if len(ugly_line.split(" : ")) > 1: # class is derived - deriv_str = ugly_line.split(" : ")[1] - if len(deriv_str.split("::")) > 1: # namespace of base class is given - base_class_name = deriv_str.split("::", 1)[1] - else: - base_class_name = deriv_str.split(" ")[0] - debug("\t " + struct_name + " is derived from " + base_class_name,2) - base_class = class_by_name(base_class_name) - - c = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line)) - debug(f"switch to {struct_name} in namespace {namespaces}", 2) - if struct_name in classnames: - c[0].namespace = complete_namespace - c[0].base_class = base_class - classes.append(c) - i += 1 - continue - - if len(classes): - c = (classes[-1][0], classes[-1][1] + nesting_delta(ugly_line)) - classes[-1] = c - if c[1] == 0: - if c[0] == None: - debug("\tExiting unknown class", 3) - else: - debug("\tExiting class " + c[0].name, 3) - classes.pop() - private_segment = False - i += 1 - continue - - class_ = classes[-1] if classes else None - - if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1): - private_segment = True - i += 1 - continue - if class_ != None and line.find("public:") != -1: - private_segment = False - i += 1 - continue - - candidate = None - - if private_segment and class_ != None and class_[0] != None: - candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i, True) - if candidate != None: - debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_constrs.append(candidate) - i += 1 - continue - - if not private_segment and (class_ == None or class_[0] != None): - if class_ != None: - candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) - else: - candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) - if candidate != None and candidate.name.find("::") == -1: - if class_ == None: - debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - unowned_functions.append(candidate) - - # generate log aliases - if candidate.name.startswith("log_formatted"): - alias = candidate.name.replace("log_formatted", "log") - if alias == "log_string": - alias = "log" - copied_candidate = copy.copy(candidate) - copied_candidate.alias = alias - unowned_functions.append(copied_candidate) - - else: - debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_funs.append(candidate) - else: - candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i) - if candidate != None: - enums.append(candidate) - debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - elif class_ != None and class_[1] == 1: - candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i) - if candidate != None: - debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_constrs.append(candidate) - else: - candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) - if candidate != None: - if type(candidate) == list: - for c in candidate: - debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2) - class_[0].found_vars.extend(candidate) - else: - debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2) - class_[0].found_vars.append(candidate) - if candidate == None and class_ == None: - candidate = WGlobal.from_string(ugly_line, source.name, i, concat_namespace(namespaces)) - if candidate != None: - if type(candidate) == list: - for c in candidate: - glbls.append(c) - debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2) - else: - glbls.append(candidate) - debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2) - - j = i - line = unpretty_string(line) - while candidate == None and j+1 < len(source_text) and line.count(';') <= 1 and line.count("(") >= line.count(")"): - j += 1 - line = line + "\n" + unpretty_string(source_text[j]) - if class_ != None: - candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) - else: - candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) - if candidate != None and candidate.name.find("::") == -1: - if class_ == None: - debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - unowned_functions.append(candidate) - else: - debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_funs.append(candidate) - continue - candidate = WEnum.from_string(line, concat_namespace(namespaces), i) - if candidate != None: - enums.append(candidate) - debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) - continue - if class_ != None: - candidate = WConstructor.from_string(line, source.name, class_[0], i) - if candidate != None: - debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) - class_[0].found_constrs.append(candidate) - continue - if class_ == None: - candidate = WGlobal.from_string(line, source.name, i, concat_namespace(namespaces)) - if candidate != None: - if type(candidate) == list: - for c in candidate: - glbls.append(c) - debug("\tFound global \"" + c.name + "\" in namespace " + concat_namespace(namespaces), 2) - else: - glbls.append(candidate) - debug("\tFound global \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces), 2) - continue - if candidate != None: - while i < j: - i += 1 - line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") - ugly_line = unpretty_string(line) - if len(namespaces) != 0: - namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + nesting_delta(ugly_line)) - if namespaces[-1][1] == 0: - debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) - namespaces.pop() - if len(classes): - c = (classes[-1][0] , classes[-1][1] + nesting_delta(ugly_line)) - classes[-1] = c - if c[1] == 0: - if c[0] == None: - debug("\tExiting unknown class", 3) - else: - debug("\tExiting class " + c[0].name, 3) - classes.pop() - private_segment = False - i += 1 - else: - i += 1 - -def debug(message, level): - if level <= debug.debug_level: - print(message) - -def expand_function(f): - fun_list = [] - arg_list = [] - for arg in f.args: - if arg.default_value != None and (arg.wtype.name.split(" ")[-1] in primitive_types or arg.wtype.name in enum_names or (arg.wtype.name in classnames and arg.default_value == "nullptr")): - fi = copy.deepcopy(f) - fi.args = copy.deepcopy(arg_list) - fun_list.append(fi) - arg_list.append(arg) - fun_list.append(f) - return fun_list - -def expand_functions(): - global unowned_functions - new_funs = [] - for fun in unowned_functions: - new_funs.extend(expand_function(fun)) - unowned_functions = new_funs - for source in sources: - for class_ in source.classes: - new_funs = [] - for fun in class_.found_funs: - new_funs.extend(expand_function(fun)) - class_.found_funs = new_funs - -def inherit_members(): - for source in sources: - for class_ in source.classes: - if class_.base_class: - base_funs = copy.deepcopy(class_.base_class.found_funs) - for fun in base_funs: - fun.member_of = class_ - fun.namespace = class_.namespace - base_vars = copy.deepcopy(class_.base_class.found_vars) - for var in base_vars: - var.member_of = class_ - var.namespace = class_.namespace - class_.found_funs.extend(base_funs) - class_.found_vars.extend(base_vars) - -def clean_duplicates(): - for source in sources: - for class_ in source.classes: - known_decls = {} - for fun in class_.found_funs: - if fun.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) - - other = known_decls[fun.gen_decl_hash_py()] - if fun.mangled_name == other.mangled_name: - fun.duplicate = True - debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3) - continue - - other.gen_alias() - fun.gen_alias() - else: - known_decls[fun.gen_decl_hash_py()] = fun - known_decls = [] - for con in class_.found_constrs: - if con.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + con.gen_decl_hash_py(),3) - con.duplicate = True - else: - known_decls.append(con.gen_decl_hash_py()) - known_decls = [] - for fun in unowned_functions: - if fun.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) - fun.duplicate = True - else: - known_decls.append(fun.gen_decl_hash_py()) - -def gen_wrappers(filename, debug_level_ = 0): - debug.debug_level = debug_level_ - for source in sources: - parse_header(source) - - expand_functions() - inherit_members() - clean_duplicates() - - import shutil - import math - col = shutil.get_terminal_size((80,20)).columns - debug("-"*col, 1) - debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1) - debug("-"*col, 1) - for source in sources: - for class_ in source.classes: - debug("Class " + assure_length(class_.name, len(max(classnames, key=len)), True) + " contains " + assure_length(str(len(class_.found_vars)), 3, False) + " member variables, "+ assure_length(str(len(class_.found_funs)), 3, False) + " methods and " + assure_length(str(len(class_.found_constrs)), 2, False) + " constructors", 1) - if len(class_.found_constrs) == 0: - class_.found_constrs.append(WConstructor(source.name, class_)) - debug(str(len(unowned_functions)) + " functions are unowned", 1) - debug(str(len(unowned_functions)) + " global variables", 1) - for enum in enums: - debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1) - debug("-"*col, 1) - wrapper_file = open(filename, "w+") - wrapper_file.write( -"""/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Claire Xenia Wolf - * - * 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. - * - * This is a generated file and can be overwritten by make - */ - -#ifdef WITH_PYTHON -""") - for source in sources: - wrapper_file.write("#include \""+source.name+".h\"\n") - wrapper_file.write(""" -#include -#include -#include -#include -#include -#include // std::streamsize -#include -#include // boost::iostreams::sink -#include -USING_YOSYS_NAMESPACE - -using std::string_view; - -namespace YOSYS_PYTHON { - - [[noreturn]] static void log_python_exception_as_error() { - PyErr_Print(); - log_error("Python interpreter encountered an exception.\\n"); - } - - struct YosysStatics{}; -""") - - for source in sources: - for wclass in source.classes: - wrapper_file.write("\n\tstruct " + wclass.name + ";") - - wrapper_file.write("\n") - - for source in sources: - for wclass in source.classes: - wrapper_file.write(wclass.gen_decl(source.name)) - - wrapper_file.write("\n") - - for source in sources: - for wclass in source.classes: - wrapper_file.write(wclass.gen_funs(source.name)) - - for fun in unowned_functions: - wrapper_file.write(fun.gen_def()) - - for glbl in glbls: - wrapper_file.write(glbl.gen_def()) - - wrapper_file.write(""" struct Initializer - { - Initializer() { - if(!Yosys::yosys_already_setup()) - { - Yosys::log_streams.push_back(&std::cout); - Yosys::log_error_stderr = true; - Yosys::yosys_setup(); - } - } - - Initializer(Initializer const &) {} - - ~Initializer() { - Yosys::yosys_shutdown(); - } - }; - - - /// source: https://stackoverflow.com/questions/26033781/converting-python-io-object-to-stdostream-when-using-boostpython?noredirect=1&lq=1 - /// @brief Type that implements the Boost.IOStream's Sink and Flushable - /// concept for writing data to Python object that support: - /// n = object.write(str) # n = None or bytes written - /// object.flush() # if flush exists, then it is callable - class PythonOutputDevice - { - public: - - // This class models both the Sink and Flushable concepts. - struct category - : boost::iostreams::sink_tag, - boost::iostreams::flushable_tag - {}; - - explicit - PythonOutputDevice(boost::python::object object) - : object_(object) - {} - - // Sink concept. - public: - - typedef char char_type; - - std::streamsize write(const char* buffer, std::streamsize buffer_size) - { - namespace python = boost::python; - // Copy the buffer to a python string. - python::str data(buffer, buffer_size); - - // Invoke write on the python object, passing in the data. The following - // is equivalent to: - // n = object_.write(data) - python::extract bytes_written( - object_.attr("write")(data)); - - // Per the Sink concept, return the number of bytes written. If the - // Python return value provides a numeric result, then use it. Otherwise, - // such as the case of a File object, use the buffer_size. - return bytes_written.check() - ? bytes_written - : buffer_size; - } - - // Flushable concept. - public: - - bool flush() - { - // If flush exists, then call it. - boost::python::object flush = object_.attr("flush"); - if (!flush.is_none()) - { - flush(); - } - - // Always return true. If an error occurs, an exception should be thrown. - return true; - } - - private: - boost::python::object object_; - }; - - /// @brief Use an auxiliary function to adapt the legacy function. - void log_to_stream(boost::python::object object) - { - // Create an ostream that delegates to the python object. - boost::iostreams::stream* output = new boost::iostreams::stream(object); - Yosys::log_streams.insert(Yosys::log_streams.begin(), output); - }; - - - BOOST_PYTHON_MODULE(libyosys) - { - using namespace boost::python; - - class_("Initializer"); - scope().attr("_hidden") = new Initializer(); - - def("log_to_stream", &log_to_stream); -""") - - for enum in enums: - wrapper_file.write(enum.gen_boost_py()) - - for source in sources: - for wclass in source.classes: - wrapper_file.write(wclass.gen_boost_py()) - - for fun in unowned_functions: - wrapper_file.write(fun.gen_boost_py()) - - wrapper_file.write("\n\n\t\tclass_(\"Yosys\")\n") - for glbl in glbls: - wrapper_file.write(glbl.gen_boost_py()) - wrapper_file.write("\t\t;\n") - - wrapper_file.write("\n\t}\n}\n#endif") - -def print_includes(): - for source in sources: - print(source.name + ".pyh") diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc index afa830552..e1e888a85 100644 --- a/passes/cmds/plugin.cc +++ b/passes/cmds/plugin.cc @@ -24,12 +24,6 @@ # include #endif -#ifdef WITH_PYTHON -# include -# include -# include -#endif - YOSYS_NAMESPACE_BEGIN std::map loaded_plugins; @@ -57,23 +51,23 @@ void load_plugin(std::string filename, std::vector aliases) if (!is_loaded) { // Check if we're loading a python script - if(filename.find(".py") != std::string::npos) - { + if (filename.rfind(".py") != std::string::npos) { #ifdef WITH_PYTHON - boost::filesystem::path full_path(filename); - std::string path(full_path.parent_path().c_str()); - filename = full_path.filename().c_str(); - filename = filename.substr(0,filename.size()-3); - PyRun_SimpleString(("sys.path.insert(0,\""+path+"\")").c_str()); - PyErr_Print(); - PyObject *module_p = PyImport_ImportModule(filename.c_str()); - if(module_p == NULL) - { - PyErr_Print(); - log_cmd_error("Can't load python module `%s'\n", full_path.filename()); + py::object Path = py::module_::import("pathlib").attr("Path"); + py::object full_path = Path(py::cast(filename)); + py::object plugin_python_path = full_path.attr("parent"); + auto basename = py::cast(full_path.attr("stem")); + + py::object sys = py::module_::import("sys"); + sys.attr("path").attr("insert")(0, py::str(plugin_python_path)); + + try { + auto module_container = py::module_::import(basename.c_str()); + loaded_python_plugins[orig_filename] = module_container.ptr(); + } catch (py::error_already_set &e) { + log_cmd_error("Can't load python module `%s': %s\n", basename, e.what()); return; } - loaded_python_plugins[orig_filename] = module_p; Pass::init_register(); #else log_error( diff --git a/pyosys/.gitignore b/pyosys/.gitignore new file mode 100644 index 000000000..f9fbdf4f6 --- /dev/null +++ b/pyosys/.gitignore @@ -0,0 +1 @@ +wrappers.cc diff --git a/misc/__init__.py b/pyosys/__init__.py similarity index 99% rename from misc/__init__.py rename to pyosys/__init__.py index d74e3f5bd..4622464da 100644 --- a/misc/__init__.py +++ b/pyosys/__init__.py @@ -1,3 +1,4 @@ + import os import sys diff --git a/pyosys/generator.py b/pyosys/generator.py new file mode 100644 index 000000000..ebe89737e --- /dev/null +++ b/pyosys/generator.py @@ -0,0 +1,2039 @@ +#!/usr/bin/env python3 +# yosys -- Yosys Open SYnthesis Suite +# +# Copyright (C) 2012 Claire Xenia Wolf +# +# 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. +# +# Author: Benedikt Tutzer +# Modified for pybind11 by: Mohamed Gaber + +import argparse +import copy +from enum import Enum +from io import StringIO +from pathlib import Path +from functools import wraps +from typing import ClassVar, Optional + +__file_dir__ = Path(__file__).absolute().parent + + +def autostring(fn): + @wraps(fn) + def wrapper(*args, **kwargs): + if "stream" not in kwargs: + stream = StringIO() + fn(*args, stream=stream, **kwargs) + return stream.getvalue() + else: + fn(*args, **kwargs) + + return wrapper + + +# Map c++ operator Syntax to Python functions +wrappable_operators = { + "<": "__lt__", + "==": "__eq__", + "!=": "__ne__", + "+": "__add__", + "-": "__sub__", + "*": "__mul__", + "/": "__div__", + "()": "__call__", +} + +# Restrict certain strings from being function names in Python +keyword_aliases = { + "in": "in_", + "False": "False_", + "None": "None_", + "True": "True_", + "and": "and_", + "as": "as_", + "assert": "assert_", + "break": "break_", + "class": "class_", + "continue": "continue_", + "def": "def_", + "del": "del_", + "elif": "elif_", + "else": "else_", + "except": "except_", + "for": "for_", + "from": "from_", + "global": "global_", + "if": "if_", + "import": "import_", + "in": "in_", + "is": "is_", + "lambda": "lambda_", + "nonlocal": "nonlocal_", + "not": "not_", + "or": "or_", + "pass": "pass_", + "raise": "raise_", + "return": "return_", + "try": "try_", + "while": "while_", + "with": "with_", + "yield": "yield_", +} + +# These can be used without any explicit conversion +autocast_types = { + "void": "void", + "bool": "bool", + "int": "int", + "double": "double", + "size_t": "size_t", + "std::string": "std::string", + "string": "string", + "char_p": "char_p", + "std::source_location": "std::source_location", + "source_location": "source_location", + "State": "RTLIL::State", + # trampoline types + "Pass": "RTLIL::Pass", + "Monitor": "RTLIL::Monitor", +} + +def strip_std_prefix(str_in): + # removesuffix is python 3.9+ + std_namespace = "std::" + if str_in.startswith(std_namespace): + return str_in[len(std_namespace):] + return str_in + + +# Ways to link between Python- and C++ Objects +class link_types(Enum): + global_list = 1 # Identical to pointer, kept for historical reasons + ref_copy = 2 # Copy + pointer = 3 # The Python Object contains a pointer to its C++ + # counterpart + derive = 4 # Identical to ref_copy, kept for historical reasons + + +class attr_types(Enum): + star = "*" + amp = "&" + ampamp = "&&" + default = "" + + +# For source-files +class Source: + name = "" + classes = [] + + def __init__(self, name, classes): + self.name = name + self.classes = classes + + +# Splits a list by the given delimiter, without splitting strings inside +# pointy-brackets (< and >) +def split_list(str_def, delim): + str_def = str_def.strip() + if len(str_def) == 0: + return [] + if str_def.count(delim) == 0: + return [str_def] + if str_def.count("<") == 0: + return str_def.split(delim) + if str_def.find("<") < str_def.find(" "): + closing = find_closing( + str_def[str_def.find("<") + 1 :], "<", ">" + ) + str_def.find("<") + comma = str_def[closing:].find(delim) + if comma == -1: + return [str_def] + comma = closing + comma + else: + comma = str_def.find(delim) + rest = split_list(str_def[comma + 1 :], delim) + ret = [str_def[:comma]] + if rest != None and len(rest) != 0: + ret.extend(rest) + return ret + + +# Represents a Type +class WType: + name = "" + cont = None + attr_type = attr_types.default + + def __init__(self, name="", cont=None, attr_type=attr_types.default): + self.name = name + self.cont = cont + self.attr_type = attr_type + + # Python type-string + def gen_text(self): + text = self.name + if self.name in enum_names: + text = enum_by_name(self.name).namespace + "::" + self.name + if self.cont != None: + return self.cont.gen_identifier() + return text + + # C++ type-string + def gen_text_cpp(self): + postfix = "" + if self.attr_type == attr_types.star: + postfix = " *" + elif self.attr_type == attr_types.amp: + postfix = " &" + elif self.attr_type == attr_types.ampamp: + postfix = " &&" + if self.name in classnames: + return class_by_name(self.name).namespace + "::" + self.name + postfix + if self.name in enum_names: + return enum_by_name(self.name).namespace + "::" + self.name + postfix + if self.name in autocast_types: + return autocast_types[self.name] + postfix + text = self.name + if self.cont != None: + text += "<" + for a in self.cont.args: + text += a.gen_text_cpp() + ", " + text = text[:-2] + text += ">" + return text + + @staticmethod + def from_string(str_def, containing_file, line_number): + str_def = str_def.strip() + if len(str_def) == 0: + return None + str_def = str_def.replace( + "RTLIL::SigSig", "std::pair" + ).replace("SigSig", "std::pair") + t = WType() + t.name = "" + t.cont = None + t.attr_type = attr_types.default + if str_def.find("<") != -1: # and str_def.find("<") < str_def.find(" "): + str_def = str_def.replace("const ", "") + + candidate = WContainer.from_string(str_def, containing_file, line_number) + if candidate == None: + return None + t.name = str_def[: str_def.find("<")] + + if t.name.count("*") + t.name.count("&") > 1: + return None + + if t.name.count("*") == 1 or str_def[0] == "*" or str_def[-1] == "*": + t.attr_type = attr_types.star + t.name = t.name.replace("*", "") + elif t.name.count("&&") == 1: + t.attr_type = attr_types.ampamp + t.name = t.name.replace("&&", "") + elif t.name.count("&") == 1 or str_def[0] == "&" or str_def[-1] == "&": + t.attr_type = attr_types.amp + t.name = t.name.replace("&", "") + + t.cont = candidate + if t.name not in known_containers: + return None + return t + + prefix = "" + + if str.startswith(str_def, "const "): + if "char_p" in str_def: + prefix = "const " + str_def = str_def[6:] + if str.startswith(str_def, "unsigned "): + prefix = "unsigned " + prefix + str_def = str_def[9:] + while str.startswith(str_def, "long "): + prefix = "long " + prefix + str_def = str_def[5:] + while str.startswith(str_def, "short "): + prefix = "short " + prefix + str_def = str_def[6:] + + str_def = str_def.split("::")[-1] + + if str_def.count("*") + str_def.count("&") >= 2: + return None + + if str_def.count("*") == 1: + t.attr_type = attr_types.star + str_def = str_def.replace("*", "") + elif str_def.count("&&") == 1: + t.attr_type = attr_types.ampamp + str_def = str_def.replace("&&", "") + elif str_def.count("&") == 1: + t.attr_type = attr_types.amp + str_def = str_def.replace("&", "") + + if ( + len(str_def) > 0 + and str_def.split("::")[-1] not in autocast_types + and str_def.split("::")[-1] not in classnames + and str_def.split("::")[-1] not in enum_names + ): + return None + + if str_def.count(" ") == 0: + t.name = (prefix + str_def).replace("char_p", "char *") + t.cont = None + return t + return None + + def gen_identifier(self): + if self.cont: + return self.cont.gen_identifier() + return self.name.title() + + def as_wclass(self) -> Optional["WClass"]: + return class_by_name(self.name) + + def __repr__(self): + return f"{self.__class__.__qualname__}(**{repr(self.__dict__)})" + + +# Associate the "Translators" with their c++ type +known_containers = { + "std::set", + "std::vector", + "std::map", + "std::pair", + "pool", + "idict", + "dict", + "RTLIL::ObjRange" +} + +# Represents a container-type +class WContainer: + name = "" + args = [] + + def from_string(str_def, containing_file, line_number): + if str_def == None or len(str_def) < 4: + return None + cont = WContainer() + cont.name = str_def[: str_def.find("<")] + str_def = str_def[str_def.find("<") + 1 : find_closing(str_def, "<", ">")] + cont.args = [] + for arg in split_list(str_def, ","): + candidate = WType.from_string(arg.strip(), containing_file, line_number) + if candidate == None: + return None + if candidate.name == "void": + return None + cont.args.append(candidate) + return cont + + # generate the c++ type string + def gen_type_cpp(self): + tpl_args = [] + for arg in self.args: + postfix = (arg.attr_type == attr_types.star) * " *" + if arg.name in autocast_types: + tpl_args.append(autocast_types[arg.name] + postfix) + elif arg.name in known_containers: + tpl_args.append(arg.cont.gen_type_cpp()) + else: + tpl_args.append(arg.as_wclass().fully_qualified_name() + postfix) + return f'{self.name}<{ ", ".join(tpl_args) }>' + + def gen_identifier(self): + container = strip_std_prefix(self.name).title() + + if container == "Dict": + assert len(self.args) == 2 + return f"{self.args[0].gen_identifier()}To{self.args[1].gen_identifier()}{container}" + + args = [] + for arg in self.args: + arg_name = arg.name.title() + if arg.cont: + arg_name = arg.cont.gen_identifier() + args.append(arg_name) + args.append(container) + result = "".join(args) + if result == "SigspecSigspecPair": + return "SigSig" + return result + + @autostring + def gen_boost_py(self, *, stream): + bind_fn = "py::bind_" + strip_std_prefix(self.name) + tpl_args = [self.gen_type_cpp()] + if bind_fn != "py::bind_vector": + # using custom bind function, can't use ::value so need more + # template arguments + for arg in self.args: + postfix = (arg.attr_type == attr_types.star) * " *" + if arg.name in autocast_types: + tpl_args.append(autocast_types[arg.name] + postfix) + elif arg.name in known_containers: + tpl_args.append(arg.cont.gen_type_cpp()) + else: + tpl_args.append(arg.as_wclass().fully_qualified_name() + postfix) + if bind_fn == "py::bind_set": + bind_fn = "py::bind_pool" + stream.write(f'\t\t{bind_fn}<{",".join(tpl_args)}>(m, "{self.gen_identifier()}");\n') + + def __repr__(self): + return f"{self.__class__.__qualname__}(**{repr(self.__dict__)})" + + +class Attribute: + wtype = None + varname = None + is_const = False + default_value = None + pos = None + pos_counter = 0 + + def __init__(self, wtype, varname, is_const=False, default_value=None): + self.wtype = wtype + self.varname = varname + self.is_const = is_const + self.default_value = None + self.container = None + + @staticmethod + def from_string(str_def, containing_file, line_number): + if len(str_def) < 3: + return None + orig = str_def + arg = Attribute(None, None) + prefix = "" + arg.wtype = None + arg.varname = None + arg.is_const = False + arg.default_value = None + arg.container = None + if str.startswith(str_def, "const "): + arg.is_const = True + str_def = str_def[6:] + if str.startswith(str_def, "unsigned "): + prefix = "unsigned " + str_def = str_def[9:] + while str.startswith(str_def, "long "): + prefix = "long " + prefix + str_def = str_def[5:] + while str.startswith(str_def, "short "): + prefix = "short " + prefix + str_def = str_def[6:] + + if str_def.find("<") != -1 and str_def.find("<") < str_def.find(" "): + closing = ( + find_closing(str_def[str_def.find("<") :], "<", ">") + + str_def.find("<") + + 1 + ) + arg.wtype = WType.from_string( + str_def[:closing].strip(), containing_file, line_number + ) + str_def = str_def[closing + 1 :] + else: + if str_def.count(" ") > 0: + arg.wtype = WType.from_string( + prefix + str_def[: str_def.find(" ")].strip(), + containing_file, + line_number, + ) + str_def = str_def[str_def.find(" ") + 1 :] + else: + arg.wtype = WType.from_string( + prefix + str_def.strip(), containing_file, line_number + ) + str_def = "" + arg.varname = "" + + if arg.wtype == None: + return None + if str_def.count("=") == 0: + arg.varname = str_def.strip() + if arg.varname.find(" ") > 0: + return None + else: + arg.varname = str_def[: str_def.find("=")].strip() + if arg.varname.find(" ") > 0: + return None + str_def = str_def[str_def.find("=") + 1 :].strip() + arg.default_value = str_def[arg.varname.find("=") + 1 :].strip() + if len(arg.varname) == 0: + arg.varname = None + return arg + if arg.varname[0] == "*": + arg.wtype.attr_type = attr_types.star + arg.varname = arg.varname[1:] + elif arg.varname[0] == "&": + if arg.wtype.attr_type != attr_types.default: + return None + if arg.varname[1] == "&": + arg.wtype.attr_type = attr_types.ampamp + arg.varname = arg.varname[2:] + else: + arg.wtype.attr_type = attr_types.amp + arg.varname = arg.varname[1:] + return arg + + # Generates the varname. If the attribute has no name in the header file, + # a name is generated + def gen_varname(self): + if self.varname != None: + return self.varname + if self.wtype.name == "void": + return "" + if self.pos == None: + self.pos = Attribute.pos_counter + Attribute.pos_counter = Attribute.pos_counter + 1 + return "gen_varname_" + str(self.pos) + + # Generates the test for the function headers with c++ types + def gen_listitem_cpp(self, include_varname=True): + postfix = self.gen_varname() * include_varname + prefix = "" + if self.is_const: + prefix = "const " + infix = "" + if self.wtype.attr_type == attr_types.star: + infix = "*" + elif self.wtype.attr_type == attr_types.amp: + infix = "&" + elif self.wtype.attr_type == attr_types.ampamp: + infix = "&&" + if self.wtype.name in known_containers: + return ( + prefix + + self.wtype.cont.gen_type_cpp() + + " " + + infix + + postfix + ) + if self.wtype.name in classnames: + return ( + prefix + + class_by_name(self.wtype.name).namespace + + "::" + + self.wtype.name + + " " + + infix + + postfix + ) + return prefix + self.wtype.name + " " + infix + postfix + + def gen_listitem_pyarg(self): + default = "" + if self.default_value is not None: + default = f" = {self.default_value}" + return f'py::arg("{self.varname}"){default}' + + # Generates the listitem withtout the varname, so the signature can be + # compared + def gen_listitem_hash(self): + prefix = "" + if self.is_const: + prefix = "const " + if self.wtype.name in classnames: + return prefix + self.wtype.name + "* " + if self.wtype.name in known_containers: + return self.wtype.cont.gen_identifier() + return prefix + self.wtype.name + + +class WClass: + name = None + namespace = None + link_type = None + base_class = None + id_ = None + string_id = None + hash_id = None + needs_clone = False + found_funs = [] + found_vars = [] + found_constrs = [] + + def __init__( + self, + name, + link_type, + *, + id_=None, + string_id=None, + hash_id=None, + needs_clone=False, + ): + self.name = name + self.namespace = None + self.base_class = None + self.link_type = link_type + self.id_ = id_ + self.string_id = string_id + self.hash_id = hash_id + self.needs_clone = needs_clone + self.found_funs = [] + self.found_vars = [] + self.found_constrs = [] + + @autostring + def gen_boost_py(self, *, stream): + name_qualified = f"{self.namespace}::{self.name}" + tpl_args = [name_qualified] + if self.link_type in [link_types.pointer, link_types.global_list]: + tpl_args.append(f"std::unique_ptr<{name_qualified}, py::nodelete>") + stream.write(f'\t\tpy::class_<{", ".join(tpl_args)}>(m, "{self.name}")\n') + for con in self.found_constrs: + # HACK: skip move constructors + if "&&" in con.orig_text: + continue + con.gen_boost_py(stream=stream) + for fun in sorted(self.found_funs, key=lambda f: (f.is_operator, f.name)): + fun.gen_boost_py(stream=stream) + if self.string_id: + stream.write( + f'\t\t\t.def("__str__", [](const {name_qualified} &self){{ return self.{self.string_id}; }})\n' + ) + if self.hash_id: + hash_member = f".{self.hash_id}" if self.hash_id != "" else "" + stream.write( + f'\t\t\t.def("__hash__", [](const {name_qualified} &self){{ return run_hash(self{hash_member}); }})\n' + ) + for var in self.found_vars: + var.gen_boost_py(stream=stream) + stream.write("\t\t;\n") + + def fully_qualified_name(self) -> str: + return f"{self.namespace}::{self.name}" + + def __repr__(self): + return f"{self.__class__.__qualname__}({repr(self.__dict__)})" + + +# CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE + +sources = [ + Source( + "kernel/celltypes", + [ + WClass("CellType", link_types.ref_copy, hash_id="type", needs_clone=True), + WClass("CellTypes", link_types.ref_copy, needs_clone=True), + ], + ), + Source( + "kernel/consteval", [WClass("ConstEval", link_types.ref_copy, needs_clone=True)] + ), + Source("kernel/log", []), + Source( + "kernel/register", + [ + # WClass("Pass", link_types.derive, needs_clone=True), # Manual mapping because of virtual method + ], + ), + Source( + "kernel/rtlil", + [ + WClass("IdString", link_types.ref_copy, string_id="str()", hash_id="str()"), + WClass("Const", link_types.ref_copy, string_id="as_string()"), + WClass("AttrObject", link_types.ref_copy), + WClass("NamedObject", link_types.ref_copy), + WClass("Selection", link_types.ref_copy), + #WClass("Monitor", link_types.derive), # Moved to tpl for virtual methods + WClass("CaseRule", link_types.ref_copy, needs_clone=True), + WClass("SwitchRule", link_types.ref_copy, needs_clone=True), + WClass("SyncRule", link_types.ref_copy, needs_clone=True), + WClass( + "Process", link_types.pointer, string_id="name.c_str()", hash_id="name" + ), + WClass("SigChunk", link_types.ref_copy), + WClass("SigBit", link_types.ref_copy, hash_id=""), + WClass("SigSpec", link_types.ref_copy, hash_id=""), + WClass( + "Cell", + link_types.global_list, + id_=Attribute(WType("unsigned int"), "hashidx_"), + string_id="name.c_str()", + hash_id="", + ), + WClass( + "Wire", + link_types.global_list, + id_=Attribute(WType("unsigned int"), "hashidx_"), + string_id="name.c_str()", + hash_id="", + ), + WClass( + "Memory", + link_types.global_list, + id_=Attribute(WType("unsigned int"), "hashidx_"), + string_id="name.c_str()", + hash_id="", + ), + WClass( + "Module", + link_types.global_list, + id_=Attribute(WType("unsigned int"), "hashidx_"), + string_id="name.c_str()", + hash_id="", + ), + WClass( + "Design", + link_types.ref_copy, + id_=Attribute(WType("unsigned int"), "hashidx_"), + string_id="hashidx_", + hash_id="", + ), + ], + ), + # Source("kernel/satgen",[ + # ] + # ), + # Source("libs/ezsat/ezsat",[ + # ] + # ), + # Source("libs/ezsat/ezminisat",[ + # ] + # ), + Source( + "kernel/sigtools", [WClass("SigMap", link_types.ref_copy, needs_clone=True)] + ), + Source("kernel/yosys", []), + Source("kernel/cost", []), +] + +blacklist_methods = [ + "YOSYS_NAMESPACE::Pass::run_register", + "YOSYS_NAMESPACE::Module::Pow", + "YOSYS_NAMESPACE::RTLIL::Design::selected_whole_modules", + "YOSYS_NAMESPACE::RTLIL::AttrObject::get_blackbox_attribute" +] + +enum_names = ["State", "SyncType", "ConstFlags"] + +enums = [] # Do not edit +glbls = [] + +unowned_functions = [] + +classnames = [] +for source in sources: + for wclass in source.classes: + classnames.append(wclass.name) + + +def class_by_name(name): + for source in sources: + for wclass in source.classes: + if wclass.name == name: + return wclass + return None + + +def enum_by_name(name): + for e in enums: + if e.name == name: + return e + return None + + +def find_closing(text, open_tok, close_tok): + if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok): + return text.find(close_tok) + return ( + text.find(close_tok) + + find_closing(text[text.find(close_tok) + 1 :], open_tok, close_tok) + + 1 + ) + + +def unpretty_string(s): + s = s.strip() + while s.find(" ") != -1: + s = s.replace(" ", " ") + while s.find("\t") != -1: + s = s.replace("\t", " ") + s = s.replace(" (", "(") + return s + + +class WEnum: + name = None + namespace = None + values = [] + + def from_string(str_def, namespace, line_number): + str_def = str_def.strip() + if not str.startswith(str_def, "enum "): + return None + if str_def.count(";") != 1: + return None + str_def = str_def[5:] + enum = WEnum() + split = str_def.split(":") + if len(split) != 2: + return None + enum.name = split[0].strip() + if enum.name not in enum_names: + return None + str_def = split[1] + if str_def.count("{") != str_def.count("}") != 1: + return None + if ( + len(str_def) < str_def.find("}") + 2 + or str_def[str_def.find("}") + 1] != ";" + ): + return None + str_def = str_def.split("{")[-1].split("}")[0] + enum.values = [] + for val in str_def.split(","): + enum.values.append(val.strip().split("=")[0].strip()) + enum.namespace = namespace + return enum + + @autostring + def gen_boost_py(self, *, stream): + stream.write( + f'\t\tpy::native_enum<{self.namespace}::{self.name}>(m, "{self.name}", "enum.Enum")\n' + ) + for value in self.values: + stream.write(f'\t\t\t.value("{value}", {self.namespace}::{value})\n') + stream.write("\t\t\t.finalize();\n") + + def __str__(self): + ret = "Enum " + self.namespace + "::" + self.name + "(\n" + for val in self.values: + ret = ret + "\t" + val + "\n" + return ret + ")" + + +class WConstructor: + orig_text = None + args = [] + containing_file = None + member_of = None + duplicate = False + protected = False + + def __init__(self, containing_file, class_): + self.orig_text = "Auto generated default constructor" + self.args = [] + self.containing_file = containing_file + self.member_of = class_ + self.protected = False + + def from_string(str_def, containing_file, class_, line_number, protected=False): + if class_ == None: + return None + if str_def.count("delete;") > 0: + return None + con = WConstructor(containing_file, class_) + con.orig_text = str_def + con.args = [] + con.duplicate = False + con.protected = protected + if str.startswith(str_def, "inline "): + str_def = str_def[7:] + if not str.startswith(str_def, class_.name + "("): + return None + str_def = str_def[len(class_.name) + 1 :] + found = find_closing(str_def, "(", ")") + if found == -1: + return None + str_def = str_def[0:found].strip() + if len(str_def) == 0: + return con + args = split_list(str_def, ",") + for i, arg in enumerate(args): + parsed = Attribute.from_string(arg.strip(), containing_file, line_number) + if parsed == None: + return None + # Only allow std::source_location as defaulted last argument, and + # don't append so it takes default value + if parsed.wtype.name in ["std::source_location", "source_location"]: + if parsed.default_value is None or i != len(args) - 1: + debug( + "std::source_location not defaulted last arg of " + + class_.name + + " is unsupported", + 2, + ) + return None + continue + con.args.append(parsed) + return con + + def gen_decl_hash_py(self): + text = self.member_of.name + "(" + for arg in self.args: + text += arg.gen_listitem_hash() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ");" + return text + + def overload_params(self): + return ", ".join([a.gen_listitem_cpp(include_varname=False) for a in self.args]) + + @autostring + def gen_boost_py(self, *, stream): + if self.duplicate or self.protected: + return + stream.write(f"\t\t\t.def(py::init<{self.overload_params()}>())\n") + + +class WFunction: + orig_text = None + is_static = False + is_inline = False + is_virtual = False + is_const = False + ret_attr_type = attr_types.default + is_operator = False + ret_type = None + name = None + alias = None + args = [] + containing_file = None + member_of = None + duplicate = False + namespace = "" + + def from_string(str_def, containing_file, class_, line_number, namespace): + if str_def.count("delete;") > 0: + return None + func = WFunction() + func.is_static = False + func.is_inline = False + func.is_virtual = False + func.is_const = False + func.ret_attr_type = attr_types.default + func.is_operator = False + func.member_of = None + func.orig_text = str_def + func.args = [] + func.containing_file = containing_file + func.member_of = class_ + func.duplicate = False + func.namespace = namespace + str_def = str_def.replace("operator ", "operator") + + # remove attributes from the start + if str.startswith(str_def, "[[") and "]]" in str_def: + str_def = str_def[str_def.find("]]") + 2 :] + + if str.startswith(str_def, "static "): + func.is_static = True + str_def = str_def[7:] + else: + func.is_static = False + if str.startswith(str_def, "inline "): + func.is_inline = True + str_def = str_def[7:] + else: + func.is_inline = False + if str.startswith(str_def, "virtual "): + func.is_virtual = True + str_def = str_def[8:] + else: + func.is_virtual = False + + if str_def.count(" ") == 0: + return None + + parts = split_list(str_def.strip(), " ") + + prefix = "" + i = 0 + for part in parts: + if part in ["unsigned", "long", "short", "const"]: + prefix += part + " " + i += 1 + else: + break + parts = parts[i:] + + if len(parts) <= 1: + return None + + func.ret_type = WType.from_string( + prefix + parts[0], containing_file, line_number + ) + + if func.ret_type == None: + return None + + str_def = parts[1] + for part in parts[2:]: + str_def = str_def + " " + part + + found = str_def.find("(") + if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")): + return None + func.name = str_def[:found] + str_def = str_def[found:] + if func.name.find("operator") != -1 and str.startswith(str_def, "()("): + func.name += "()" + str_def = str_def[2:] + str_def = str_def[1:] + if func.name.find("operator") != -1: + func.is_operator = True + if func.name.find("*") == 0: + func.name = func.name.replace("*", "") + func.ret_type.attr_type = attr_types.star + if func.name.find("&&") == 0: + func.name = func.name.replace("&&", "") + func.ret_type.attr_type = attr_types.ampamp + if func.name.find("&") == 0: + func.name = func.name.replace("&", "") + func.ret_type.attr_type = attr_types.amp + + found = find_closing(str_def, "(", ")") + if found == -1: + return None + + post_qualifiers = str_def[found + 1 :].lstrip() + if post_qualifiers.startswith("const"): + func.is_const = True + + str_def = str_def[0:found] + if func.name in blacklist_methods: + return None + if func.namespace != None and func.namespace != "": + if (func.namespace + "::" + func.name) in blacklist_methods: + return None + if func.member_of != None: + if ( + func.namespace + "::" + func.member_of.name + "::" + func.name + ) in blacklist_methods: + return None + if ( + func.is_operator + and func.name.replace(" ", "").replace("operator", "").split("::")[-1] + not in wrappable_operators + ): + return None + + testname = func.name + if func.is_operator: + testname = testname[: testname.find("operator")] + if ( + testname.count(")") != 0 + or testname.count("(") != 0 + or testname.count("~") != 0 + or testname.count(";") != 0 + or testname.count(">") != 0 + or testname.count("<") != 0 + or testname.count("throw") != 0 + ): + return None + + func.alias = func.name + if func.name in keyword_aliases: + func.alias = keyword_aliases[func.name] + str_def = str_def[:found].strip() + if len(str_def) == 0: + return func + args = split_list(str_def, ",") + for i, arg in enumerate(args): + if arg.strip() == "...": + continue + parsed = Attribute.from_string(arg.strip(), containing_file, line_number) + if parsed == None: + return None + # Only allow std::source_location as defaulted last argument, and + # don't append so it takes default value + if parsed.wtype.name in ["std::source_location", "source_location"]: + if parsed.default_value is None or i != len(args) - 1: + debug( + "std::source_location not defaulted last arg of " + + func.name + + " is unsupported", + 2, + ) + return None + continue + func.args.append(parsed) + # handle (void) parameter declarations + if len(func.args) == 1 and func.args[0].wtype.name == "void": + func.args = [] + return func + + @property + def mangled_name(self): + mangled_typename = ( + lambda code: code.replace("::", "_") + .replace("<", "_") + .replace(">", "_") + .replace(" ", "") + .replace("*", "") + .replace(",", "") + ) + + return self.name + "".join( + f"__{mangled_typename(arg.wtype.gen_text_cpp())}" for arg in self.args + ) + + def gen_alias(self): + self.alias = self.mangled_name + + def gen_post_qualifiers(self, derived=False): + if ( + self.member_of != None + and self.member_of.link_type == link_types.derive + and self.is_virtual + and derived + ): + # we drop the qualifiers when deriving callbacks to be implemented in Python + return "" + return " const" if self.is_const else "" + + def gen_decl_hash_py(self): + text = self.ret_type.gen_text() + " " + self.alias + "(" + for arg in self.args: + text += arg.gen_listitem_hash() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ");" + return text + + def overload_params(self): + return ", ".join([a.gen_listitem_cpp(False) for a in self.args]) + + def py_args(self): + return ", ".join([a.gen_listitem_pyarg() for a in self.args]) + + def wrapper_params(self): + return ", ".join([a.gen_listitem_cpp() for a in self.args]) + + def wrapper_args(self): + varnames = [] + for a in self.args: + if a.varname == "format": + # HACK: handle format strings (by ignoring the format part) + varnames.extend(['"%s"', "format"]) + else: + varnames.append(a.varname) + return ", ".join(varnames) + + @autostring + def gen_boost_py(self, *, stream): + if self.duplicate: + return + + fully_qualify = False + if self.member_of is not None and ( + (self.member_of.name == "IdString" and self.name == "in") + or (self.member_of.name == "Design" and self.name == "selection") + ): + fully_qualify = True + + # HACK: skip methods with inline-related nonsense + if self.alias in [ + "log_id", + "log_dump_val_worker", + "log_dump_args_worker", + "GetSize", + ]: + return + + prefix = "\t\tm" + ns = self.namespace + if self.member_of: + prefix = "\t\t\t" + ns = self.member_of.fully_qualified_name() + + stream.write(f"{prefix}.def") + if self.member_of and self.is_static: + stream.write("_static") + stream.write("(") + + if self.is_operator: + stream.write(f"py::self {self.name[len('operator'):]} py::self") + else: + stream.write(f'"{self.alias}", ') + # HACK: wrap variadics by only allowing a string + if "..." in self.orig_text: + stream.write( + f"[]({self.wrapper_params()}) {{ {self.namespace}::{self.name}({self.wrapper_args()}); }}" + ) + else: + + # HACK: Some of these needs special handling, i.e., a FULL + # overload disambiguation. Not sure why. Something to do with + # inlines and overloads. + # + # In theory, this disambiguation should work for everything but + # WType doesn't properly retain const return types yet. + if fully_qualify: + stream.write( + f"static_cast < {self.ret_type.gen_text_cpp()} ({ns}::*)({self.overload_params()}) {self.gen_post_qualifiers()} >(" + ) + elif not len(self.args) == 0: + stream.write(f"py::overload_cast<{self.overload_params()}>(") + stream.write(f"&{ns}::{self.name}") + if fully_qualify: + stream.write(")") + elif not len(self.args) == 0: + if self.is_const: + stream.write(f", py::const_") + stream.write(")") + py_args = self.py_args() + if len(py_args): + stream.write(", ") + stream.write(py_args) + stream.write(")\n" if self.member_of is not None else ");\n") + + def __repr__(self): + return f"{self.__class__.__qualname__}({repr(self.__dict__)})" + + +class WMember: + opaque_containers: ClassVar[dict] = dict() + orig_text = None + wtype = attr_types.default + name = None + containing_file = None + member_of = None + namespace = "" + is_const = False + + def from_string(str_def, containing_file, class_, line_number, namespace): + member = WMember() + member.orig_text = str_def + member.wtype = None + member.name = "" + member.containing_file = containing_file + member.member_of = class_ + member.namespace = namespace + member.is_const = False + + if str.startswith(str_def, "const "): + member.is_const = True + str_def = str_def[6:] + + if str_def.count(" ") == 0: + return None + + parts = split_list(str_def.strip(), " ") + + prefix = "" + i = 0 + for part in parts: + if part in ["unsigned", "long", "short"]: + prefix += part + " " + i += 1 + else: + break + parts = parts[i:] + + if len(parts) <= 1: + return None + + member.wtype = WType.from_string( + prefix + parts[0], containing_file, line_number + ) + + if member.wtype == None: + return None + + str_def = parts[1] + for part in parts[2:]: + str_def = str_def + " " + part + + if ( + str_def.find("(") != -1 + or str_def.find(")") != -1 + or str_def.find("{") != -1 + or str_def.find("}") != -1 + ): + return None + + found = str_def.find(";") + if found == -1: + return None + + found_eq = str_def.find("=") + if found_eq != -1: + found = found_eq + + member.name = str_def[:found] + str_def = str_def[found + 1 :] + if member.name.find("*") == 0: + member.name = member.name.replace("*", "") + member.wtype.attr_type = attr_types.star + if member.name.find("&&") == 0: + member.name = member.name.replace("&&", "") + member.wtype.attr_type = attr_types.ampamp + if member.name.find("&") == 0: + member.name = member.name.replace("&", "") + member.wtype.attr_type = attr_types.amp + + if len(str_def.strip()) != 0: + return None + + if len(member.name.split(",")) > 1: + member_list = [] + for name in member.name.split(","): + name = name.strip() + member_list.append(WMember()) + member_list[-1].orig_text = member.orig_text + member_list[-1].wtype = member.wtype + member_list[-1].name = name + member_list[-1].containing_file = member.containing_file + member_list[-1].member_of = member.member_of + member_list[-1].namespace = member.namespace + member_list[-1].is_const = member.is_const + return member_list + + if member.wtype.cont: + WMember.opaque_containers[member.wtype.gen_identifier()] = member.wtype + + return member + + @autostring + def gen_boost_py(self, *, stream): + if False and self.wtype.attr_type == attr_types.default: + property_type = self.wtype.gen_text_cpp() + stream.write(f'\t\t\t.def_property("{self.name}",\n') + stream.write(f'\t\t\t\t[]({self.member_of.fully_qualified_name()} &o) -> {property_type}& {{ return o.{self.name}; }},\n') + stream.write(f'\t\t\t\t[]({self.member_of.fully_qualified_name()} &o, {property_type} const &p) {{ o.{self.name} = p; }},\n') + stream.write(f'\t\t\t\tpy::return_value_policy::reference_internal\n') + stream.write(f'\t\t\t)\n') + else: + meth = "def_readonly" if self.is_const else "def_readwrite" + stream.write( + f'\t\t\t.{meth}("{self.name}", &{self.member_of.fully_qualified_name()}::{self.name})\n' + ) + + def __repr__(self): + return f"{self.__class__.__qualname__}({repr(self.__dict__)})" + + +class WGlobal: + orig_text = None + wtype = attr_types.default + name = None + containing_file = None + namespace = "" + is_const = False + + def from_string(str_def, containing_file, line_number, namespace): + glbl = WGlobal() + glbl.orig_text = str_def + glbl.wtype = None + glbl.name = "" + glbl.containing_file = containing_file + glbl.namespace = namespace + glbl.is_const = False + + if not str.startswith(str_def, "extern"): + return None + str_def = str_def[7:] + + if str.startswith(str_def, "const "): + glbl.is_const = True + str_def = str_def[6:] + + if str_def.count(" ") == 0: + return None + + parts = split_list(str_def.strip(), " ") + + prefix = "" + i = 0 + for part in parts: + if part in ["unsigned", "long", "short"]: + prefix += part + " " + i += 1 + else: + break + parts = parts[i:] + + if len(parts) <= 1: + return None + + glbl.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) + + if glbl.wtype == None: + return None + + str_def = parts[1] + for part in parts[2:]: + str_def = str_def + " " + part + + if ( + str_def.find("(") != -1 + or str_def.find(")") != -1 + or str_def.find("{") != -1 + or str_def.find("}") != -1 + ): + return None + + found = str_def.find(";") + if found == -1: + return None + + found_eq = str_def.find("=") + if found_eq != -1: + found = found_eq + + glbl.name = str_def[:found] + str_def = str_def[found + 1 :] + if glbl.name.find("*") == 0: + glbl.name = glbl.name.replace("*", "") + glbl.wtype.attr_type = attr_types.star + if glbl.name.find("&&") == 0: + glbl.name = glbl.name.replace("&&", "") + glbl.wtype.attr_type = attr_types.ampamp + if glbl.name.find("&") == 0: + glbl.name = glbl.name.replace("&", "") + glbl.wtype.attr_type = attr_types.amp + + if len(str_def.strip()) != 0: + return None + + if len(glbl.name.split(",")) > 1: + glbl_list = [] + for name in glbl.name.split(","): + name = name.strip() + glbl_list.append(WGlobal()) + glbl_list[-1].orig_text = glbl.orig_text + glbl_list[-1].wtype = glbl.wtype + glbl_list[-1].name = name + glbl_list[-1].containing_file = glbl.containing_file + glbl_list[-1].namespace = glbl.namespace + glbl_list[-1].is_const = glbl.is_const + return glbl_list + + return glbl + + @autostring + def gen_boost_py(self, *, stream): + args = [ + f'"{self.name}"', + ] + meth = "def_readonly_static" + if not self.is_const: + meth = "def_readwrite_static" + args.append(f"&{self.namespace}::{self.name}") + stream.write(f'\t\t\t.{meth}({", ".join(args)})\n') + + +def concat_namespace(tuple_list): + if len(tuple_list) == 0: + return "" + ret = "" + for namespace in tuple_list: + ret += "::" + namespace[0] + return ret[2:] + + +def calc_ident(text): + if len(text) == 0 or text[0] != " ": + return 0 + return calc_ident(text[1:]) + 1 + + +def assure_length(text, length, left=False): + if len(text) > length: + return text[:length] + if left: + return text + " " * (length - len(text)) + return " " * (length - len(text)) + text + + +def nesting_delta(s): + return s.count("{") - s.count("}") + + +def parse_header(source): + debug("Parsing " + source.name + ".pyh", 1) + source_file = open(source.name + ".pyh", "r") + + source_text = [] + in_line = source_file.readline() + + namespaces = [] + + while in_line: + if len(in_line) > 1: + source_text.append( + in_line.replace("char *", "char_p ").replace("char* ", "char_p ") + ) + in_line = source_file.readline() + + i = 0 + + namespaces = [] + classes = [] + private_segment = False + + while i < len(source_text): + line = ( + source_text[i] + .replace( + "YOSYS_NAMESPACE_BEGIN", + " namespace YOSYS_NAMESPACE{", + ) + .replace("YOSYS_NAMESPACE_END", " }") + ) + ugly_line = unpretty_string(line) + debug(f"READ:>> {line}", 2) + + # for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line + if "union {" in line: + j = i + 1 + while j < len(source_text): + union_line = source_text[j] + if "};" in union_line: + source_text[j] = "\n" + break + j += 1 + if j != len(source_text): + i += 1 + continue + + if str.startswith( + ugly_line, "namespace " + ): # and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: + namespace_name = ugly_line[10:].replace("{", "").strip() + namespaces.append((namespace_name, ugly_line.count("{"))) + debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----", 3) + i += 1 + continue + + if len(namespaces) != 0: + namespaces[-1] = ( + namespaces[-1][0], + namespaces[-1][1] + nesting_delta(ugly_line), + ) + if namespaces[-1][1] == 0: + debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----", 3) + namespaces.pop() + i += 1 + continue + + if ( + str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class") + ) and ugly_line.count(";") == 0: + # Opening a record declaration which isn't a forward declaration + struct_name = ugly_line.split(" ")[1].split("::")[-1] + impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1] + complete_namespace = concat_namespace(namespaces) + for namespace in impl_namespaces: + complete_namespace += "::" + namespace + debug("\tFound " + struct_name + " in " + complete_namespace, 2) + + base_class_name = None + if len(ugly_line.split(" : ")) > 1: # class is derived + deriv_str = ugly_line.split(" : ")[1] + if len(deriv_str.split("::")) > 1: # namespace of base class is given + base_class_name = deriv_str.split("::", 1)[1] + else: + base_class_name = deriv_str.split(" ")[0] + debug("\t " + struct_name + " is derived from " + base_class_name, 2) + base_class = class_by_name(base_class_name) + + c = (class_by_name(struct_name), ugly_line.count("{")) # calc_ident(line)) + debug(f"switch to {struct_name} in namespace {namespaces}", 2) + if struct_name in classnames: + c[0].namespace = complete_namespace + c[0].base_class = base_class + classes.append(c) + i += 1 + continue + + if len(classes): + c = (classes[-1][0], classes[-1][1] + nesting_delta(ugly_line)) + classes[-1] = c + if c[1] == 0: + if c[0] == None: + debug("\tExiting unknown class", 3) + else: + debug("\tExiting class " + c[0].name, 3) + classes.pop() + private_segment = False + i += 1 + continue + + class_ = classes[-1] if classes else None + + if class_ != None and ( + line.find("private:") != -1 or line.find("protected:") != -1 + ): + private_segment = True + i += 1 + continue + if class_ != None and line.find("public:") != -1: + private_segment = False + i += 1 + continue + + candidate = None + + if private_segment and class_ != None and class_[0] != None: + candidate = WConstructor.from_string( + ugly_line, source.name, class_[0], i, True + ) + if candidate != None: + debug( + '\t\tFound constructor of class "' + + class_[0].name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + class_[0].found_constrs.append(candidate) + i += 1 + continue + + if not private_segment and (class_ == None or class_[0] != None): + if class_ != None: + candidate = WFunction.from_string( + ugly_line, source.name, class_[0], i, concat_namespace(namespaces) + ) + else: + candidate = WFunction.from_string( + ugly_line, source.name, None, i, concat_namespace(namespaces) + ) + if candidate != None and candidate.name.find("::") == -1: + if class_ == None: + debug( + '\tFound unowned function "' + + candidate.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + unowned_functions.append(candidate) + else: + debug( + '\t\tFound function "' + + candidate.name + + '" of class "' + + class_[0].name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + class_[0].found_funs.append(candidate) + else: + candidate = WEnum.from_string( + ugly_line, concat_namespace(namespaces), i + ) + if candidate != None: + enums.append(candidate) + debug( + '\tFound enum "' + + candidate.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + elif class_ != None and class_[1] == 1: + candidate = WConstructor.from_string( + ugly_line, source.name, class_[0], i + ) + if candidate != None: + debug( + '\t\tFound constructor of class "' + + class_[0].name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + class_[0].found_constrs.append(candidate) + else: + candidate = WMember.from_string( + ugly_line, + source.name, + class_[0], + i, + concat_namespace(namespaces), + ) + if candidate != None: + if type(candidate) == list: + for c in candidate: + debug( + '\t\tFound member "' + + c.name + + '" of class "' + + class_[0].name + + '" of type "' + + c.wtype.name + + '"', + 2, + ) + class_[0].found_vars.extend(candidate) + else: + debug( + '\t\tFound member "' + + candidate.name + + '" of class "' + + class_[0].name + + '" of type "' + + candidate.wtype.name + + '"', + 2, + ) + class_[0].found_vars.append(candidate) + if candidate == None and class_ == None: + candidate = WGlobal.from_string( + ugly_line, source.name, i, concat_namespace(namespaces) + ) + if candidate != None: + if type(candidate) == list: + for c in candidate: + glbls.append(c) + debug( + '\tFound global "' + + c.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + else: + glbls.append(candidate) + debug( + '\tFound global "' + + candidate.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + + j = i + line = unpretty_string(line) + while ( + candidate == None + and j + 1 < len(source_text) + and line.count(";") <= 1 + and line.count("(") >= line.count(")") + ): + j += 1 + line = line + "\n" + unpretty_string(source_text[j]) + if class_ != None: + candidate = WFunction.from_string( + ugly_line, + source.name, + class_[0], + i, + concat_namespace(namespaces), + ) + else: + candidate = WFunction.from_string( + ugly_line, source.name, None, i, concat_namespace(namespaces) + ) + if candidate != None and candidate.name.find("::") == -1: + if class_ == None: + debug( + '\tFound unowned function "' + + candidate.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + unowned_functions.append(candidate) + else: + debug( + '\t\tFound function "' + + candidate.name + + '" of class "' + + class_[0].name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + class_[0].found_funs.append(candidate) + continue + candidate = WEnum.from_string(line, concat_namespace(namespaces), i) + if candidate != None: + enums.append(candidate) + debug( + '\tFound enum "' + + candidate.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + continue + if class_ != None: + candidate = WConstructor.from_string( + line, source.name, class_[0], i + ) + if candidate != None: + debug( + '\t\tFound constructor of class "' + + class_[0].name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + class_[0].found_constrs.append(candidate) + continue + if class_ == None: + candidate = WGlobal.from_string( + line, source.name, i, concat_namespace(namespaces) + ) + if candidate != None: + if type(candidate) == list: + for c in candidate: + glbls.append(c) + debug( + '\tFound global "' + + c.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + else: + glbls.append(candidate) + debug( + '\tFound global "' + + candidate.name + + '" in namespace ' + + concat_namespace(namespaces), + 2, + ) + continue + if candidate != None: + while i < j: + i += 1 + line = ( + source_text[i] + .replace( + "YOSYS_NAMESPACE_BEGIN", + " namespace YOSYS_NAMESPACE{", + ) + .replace("YOSYS_NAMESPACE_END", " }") + ) + ugly_line = unpretty_string(line) + if len(namespaces) != 0: + namespaces[-1] = ( + namespaces[-1][0], + namespaces[-1][1] + nesting_delta(ugly_line), + ) + if namespaces[-1][1] == 0: + debug( + "-----END NAMESPACE " + + concat_namespace(namespaces) + + "-----", + 3, + ) + namespaces.pop() + if len(classes): + c = (classes[-1][0], classes[-1][1] + nesting_delta(ugly_line)) + classes[-1] = c + if c[1] == 0: + if c[0] == None: + debug("\tExiting unknown class", 3) + else: + debug("\tExiting class " + c[0].name, 3) + classes.pop() + private_segment = False + i += 1 + else: + i += 1 + + +def debug(message, level): + if level <= debug.debug_level: + print(message) + + +def expand_functions(): + global unowned_functions + new_funs = [] + for fun in unowned_functions: + new_funs.append(fun) + unowned_functions = new_funs + for source in sources: + for class_ in source.classes: + new_funs = [] + for fun in class_.found_funs: + new_funs.append(fun) + class_.found_funs = new_funs + + +def inherit_members(): + for source in sources: + for class_ in source.classes: + if class_.base_class: + base_funs = copy.deepcopy(class_.base_class.found_funs) + for fun in base_funs: + fun.member_of = class_ + fun.namespace = class_.namespace + base_vars = copy.deepcopy(class_.base_class.found_vars) + for var in base_vars: + var.member_of = class_ + var.namespace = class_.namespace + class_.found_funs.extend(base_funs) + class_.found_vars.extend(base_vars) + + +def clean_duplicates(): + for source in sources: + for class_ in source.classes: + known_decls = {} + for fun in class_.found_funs: + if fun.gen_decl_hash_py() in known_decls: + debug("Multiple declarations of " + fun.gen_decl_hash_py(), 3) + + other = known_decls[fun.gen_decl_hash_py()] + if fun.mangled_name == other.mangled_name: + fun.duplicate = True + debug('Disabled "' + fun.gen_decl_hash_py() + '"', 3) + continue + + other.gen_alias() + fun.gen_alias() + else: + known_decls[fun.gen_decl_hash_py()] = fun + known_decls = [] + for con in class_.found_constrs: + if con.gen_decl_hash_py() in known_decls: + debug("Multiple declarations of " + con.gen_decl_hash_py(), 3) + con.duplicate = True + else: + known_decls.append(con.gen_decl_hash_py()) + known_decls = [] + for fun in unowned_functions: + if fun.gen_decl_hash_py() in known_decls: + debug("Multiple declarations of " + fun.gen_decl_hash_py(), 3) + fun.duplicate = True + else: + known_decls.append(fun.gen_decl_hash_py()) + + +def gen_wrappers(filename, debug_level_=0): + filename = Path(filename) + + debug.debug_level = debug_level_ + for source in sources: + parse_header(source) + + expand_functions() + inherit_members() + clean_duplicates() + + import shutil + import math + + col = shutil.get_terminal_size((80, 20)).columns + debug("-" * col, 1) + debug( + "-" * math.floor((col - 7) / 2) + "SUMMARY" + "-" * math.ceil((col - 7) / 2), 1 + ) + debug("-" * col, 1) + for source in sources: + for class_ in source.classes: + debug( + "Class " + + assure_length(class_.name, len(max(classnames, key=len)), True) + + " contains " + + assure_length(str(len(class_.found_vars)), 3, False) + + " member variables, " + + assure_length(str(len(class_.found_funs)), 3, False) + + " methods and " + + assure_length(str(len(class_.found_constrs)), 2, False) + + " constructors", + 1, + ) + if len(class_.found_constrs) == 0: + class_.found_constrs.append(WConstructor(source.name, class_)) + debug(str(len(unowned_functions)) + " functions are unowned", 1) + debug(str(len(unowned_functions)) + " global variables", 1) + for enum in enums: + debug( + "Enum " + + assure_length(enum.name, len(max(enum_names, key=len)), True) + + " contains " + + assure_length(str(len(enum.values)), 2, False) + + " values", + 1, + ) + debug("-" * col, 1) + + tpl = __file_dir__ / "wrappers_tpl.cc" + with open(tpl, encoding="utf8") as f, open( + filename, "w", encoding="utf8" + ) as wrapper_file: + do_line_directive = True + for i, line in enumerate(f): + if do_line_directive: + wrapper_file.write(f'#line {i + 1} "{tpl}"\n') + do_line_directive = False + if "" in line: + for source in sources: + wrapper_file.write(f'#include "{source.name}.h"\n') + do_line_directive = True + elif "" in line: + wrapper_file.write("// Opaque Container Declaration\n") + for i, (container_identifier, container) in enumerate(WMember.opaque_containers.items()): + wrapper_file.write(f"using {container_identifier} = {container.gen_text_cpp()};\n") + wrapper_file.write(f'PYBIND11_MAKE_OPAQUE({container_identifier})\n') + wrapper_file.write("\n") + do_line_directive = True + elif "" in line: + do_line_directive = True + elif "" in line: + wrapper_file.write("\t\t// Opaque Container Binding\n") + for container in WMember.opaque_containers.values(): + container.cont.gen_boost_py(stream=wrapper_file) + wrapper_file.write("\n") + + wrapper_file.write("\t\t// Enums\n") + for enum in enums: + enum.gen_boost_py(stream=wrapper_file) + wrapper_file.write("\n") + + wrapper_file.write("\t\t// Classes\n") + for source in sources: + for wclass in source.classes: + wclass.gen_boost_py(stream=wrapper_file) + wrapper_file.write("\n") + + wrapper_file.write("\t\t// Global Functions\n") + for fun in sorted(unowned_functions, key=lambda x: x.alias): + fun.gen_boost_py(stream=wrapper_file) + wrapper_file.write("\n") + + wrapper_file.write("\t\t// Global Variables\n") + wrapper_file.write('\t\tpy::class_(m, "Yosys")\n') + for glbl in sorted(glbls, key=lambda x: (not x.is_const, x.name)): + glbl.gen_boost_py(stream=wrapper_file) + wrapper_file.write("\t\t\t;\n") + do_line_directive = True + else: + wrapper_file.write(line) + + +def print_includes(): + for source in sources: + print(source.name + ".pyh") + + +if __name__ == "__main__": + ap = argparse.ArgumentParser() + ap.add_argument("--print-includes", action="store_true") + ap.add_argument("--debug", default=0, type=int) + ap.add_argument("output", nargs="?") + ns = ap.parse_args() + if ns.print_includes: + print_includes() + exit(0) + gen_wrappers(ns.output, ns.debug) diff --git a/pyosys/hashlib.h b/pyosys/hashlib.h new file mode 100644 index 000000000..e8ace90c8 --- /dev/null +++ b/pyosys/hashlib.h @@ -0,0 +1,275 @@ +// ------------------------------------------------------- +// Written by Mohamed Gaber in 2025 +// Based on kernel/hashlib.h by Claire Xenia Wolf +// ------------------------------------------------------- +// This header is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to +// ------------------------------------------------------- +// +// pybind11 bridging headers for hashlib template +// +// These are various binding functions that expose hashlib templates as opaque +// types (https://pybind11.readthedocs.io/en/latest/advanced/cast/stl.html#making-opaque-types). +// +// Opaque types cross language barries by reference, not value. This allows +// things like mutating containers that are class properties. +// +// All methods should be vaguely in the same order as the python reference +// https://docs.python.org/3/library/stdtypes.html +// +#include // optional maps cleanest to methods that accept None in Python + +#include // base +#include // std::optional +#include // easier operator binding + +#include "kernel/hashlib.h" + +namespace pybind11 { + +template +struct is_pointer { static const bool value = false; }; +template +struct is_pointer { static const bool value = true; }; + +bool is_mapping(object obj) { + object mapping = module_::import("collections.abc").attr("Mapping"); + return isinstance(obj, mapping); +} + + +// also used for std::set because the semantics are close enough +template +void bind_pool(module &m, const char *name_cstr) { + std::string {name_cstr}; + + class_(m, name_cstr) + .def(init<>()) + .def("__len__", [](const C &s){ return (size_t)s.size(); }) + .def("__contains__", [](const C &s, const T &v){ return s.count(v); }) + .def("__delitem__", [](C &s, const T &v) { + auto n = s.erase(v); + if (n == 0) throw key_error(str(cast(v))); + }) + // TODO: disjoint, subset, union, intersection, difference, symdif + .def("copy", [](const C &s) { + return new C(s); + }) + .def("update", [](C &s, iterable iterable) { + for (auto item: iterable) { + s.insert(item.cast()); + } + }) + .def("add", [](C &s, const T &v){ s.insert(v); }) + .def("remove", [](C &s, const T &v){ + auto n = s.erase(v); + if (n == 0) throw key_error(str(cast(v))); + }) + .def("discard", [](C &s, const T &v){ s.erase(v); }) + .def("clear", [](C &s){ s.clear(); }) + .def("pop", [](C &s){ + if (s.size() == 0) { + throw key_error("empty pool"); + } + auto result = *s.begin(); + s.erase(result); + return result; + }) + .def("__bool__", [](const C &s) { return s.size() != 0; }) + .def("__iter__", [](const C &s){ + return make_iterator(s.begin(), s.end()); + }, keep_alive<0,1>()) + .def("__repr__", [name_cstr](const C &s){ + return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">"; + }); +} + +template +void update_dict(C *target, iterable &iterable_or_mapping) { + if (is_mapping(iterable_or_mapping)) { + for (const auto &key: iterable_or_mapping) { + (*target)[cast(key)] = cast(iterable_or_mapping[key]); + } + } else { + for (const auto &pair: iterable_or_mapping) { + if (len(pair) != 2) { + throw value_error(str("iterable element %s has more than two elements").format(str(pair))); + } + (*target)[cast(pair[cast(0)])] = cast(pair[cast(1)]); + } + } +} + +template +void bind_dict(module &m, const char *name_cstr) { + std::string {name_cstr}; + + class_(m, name_cstr) + .def(init<>()) + .def("__len__", [](const C &s){ return (size_t)s.size(); }) + .def("__getitem__", [](const C &s, const K &k) { return s.at(k); }) + .def("__setitem__", [](C &s, const K &k, const V &v) { s[k] = v; }) + .def("__delitem__", [](C &s, const K &k) { + auto n = s.erase(k); + if (n == 0) throw key_error("remove: key not found"); + }) + .def("__contains__", [](const C &s, const K &k) { return s.count(k) != 0; }) + .def("__iter__", [](const C &s){ + return make_key_iterator(s.begin(), s.end()); + }, keep_alive<0,1>()) + .def("clear", [](C &s){ s.clear(); }) + .def("copy", [](const C &s) { + return new C(s); + }) + .def("get", [](const C &s, const K& k, std::optional &default_) { + if (default_.has_value()) { + return s.at(k, *default_); + } else { + return s.at(k); + } + }, arg("key"), arg("default") = std::nullopt) + .def("items", [](const C &s){ + return make_iterator(s.begin(), s.end()); + }, keep_alive<0,1>()) + .def("keys", [](const C &s){ + return make_key_iterator(s.begin(), s.end()); + }, keep_alive<0,1>()) + .def("pop", [](const C &s, const K& k, std::optional &default_) { + if (default_.has_value()) { + return s.at(k, *default_); + } else { + return s.at(k); + } + }, arg("key"), arg("default") = std::nullopt) + .def("popitem", [name_cstr](args _) { throw std::runtime_error(std::string(name_cstr) + " is not an ordered dictionary"); }) + .def("setdefault", [name_cstr](C &s, const K& k, std::optional &default_) { + auto it = s.find(k); + if (it != s.end()) { + return it->second; + } + if (default_.has_value()) { + s[k] = *default_; + return *default_; + } + // if pointer, nullptr can be our default + if constexpr (is_pointer::value) { + s[k] = nullptr; + return (V)nullptr; + } + // TODO: std::optional? do we care? + throw type_error(std::string("the value type of ") + name_cstr + " is not nullable"); + }, arg("key"), arg("default") = std::nullopt) + .def("update", [](C &s, iterable iterable_or_mapping) { + update_dict(&s, iterable_or_mapping); + }, arg("iterable_or_mapping")) + .def("values", [](const C &s){ + return make_value_iterator(s.begin(), s.end()); + }, keep_alive<0,1>()) + .def("__or__", [](const C &s, iterable iterable_or_mapping) { + auto result = new C(s); + update_dict(result, iterable_or_mapping); + return result; + }) + .def("__ior__", [](C &s, iterable iterable_or_mapping) { + update_dict(&s, iterable_or_mapping); + return s; + }) + .def("__bool__", [](const C &s) { return s.size() != 0; }) + .def("__repr__", [name_cstr](const C &s){ + return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">"; + }); +} + +// idict is a special bijection and doesn't map cleanly to dict +// +// it's cleanest, despite the inconsistency with __getitem__, to just think of +// the hashable as key and the integer as value +template +void bind_idict(module &m, const char *name_cstr) { + std::string {name_cstr}; + + auto cls = class_(m, name_cstr) + .def(init<>()) + .def("__len__", [](const C &s){ return (size_t)s.size(); }) + .def("__getitem__", [](const C &s, int v) { return s[v]; }) + .def("__call__", [](C &s, const K &k) { return s(k); }) + .def("__contains__", [](const C &s, const K &k) { + return s.count(k) != 0; + }) + .def("__iter__", [](const C &s){ + return make_iterator(s.begin(), s.end()); + }, keep_alive<0,1>()) + .def("clear", [](C &s) { + s.clear(); + }) + .def("copy", [](const C &s) { + return new C(s); + }) + .def("get", [](const C &s, const K& k, std::optional &default_) { + if (default_.has_value()) { + return s.at(k, *default_); + } else { + return s.at(k); + } + }, arg("key"), arg("default") = std::nullopt) + .def("keys", [](const C &s){ + return make_iterator(s.begin(), s.end()); + }) + .def("values", [](args _){ + throw type_error("idicts do not support iteration on the integers"); + }) + .def("items", [](args _){ + throw type_error("idicts do not support pairwise iteration"); + }) + .def("update", [](C &s, iterable iterable) { + for (auto &e: iterable) { + s(cast(e)); + } + }) + .def("__or__", [](const C &s, iterable iterable) { + auto result = new C(s); + for (auto &e: iterable) { + (*result)(cast(e)); + } + return result; + }) + .def("__ior__", [](C &s, iterable iterable) { + for (auto &e: iterable) { + s(cast(e)); + } + return s; + }) + .def("__bool__", [](const C &s) { return s.size() != 0; }) + .def("__repr__", [name_cstr](const C &s){ + return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">"; + }); + + for (const char *mutator: {"__setitem__", "__delitem__", "pop", "popitem", "setdefault"}) { + cls.def(mutator, [](args _) { + throw type_error("idicts do not support arbitrary element mutation"); + }); + } +} +}; // namespace pybind11 diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc new file mode 100644 index 000000000..e921ae17a --- /dev/null +++ b/pyosys/wrappers_tpl.cc @@ -0,0 +1,248 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * 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. + */ + +#ifdef WITH_PYTHON + +// + +#include +#include +#include "pyosys/hashlib.h" + +USING_YOSYS_NAMESPACE + +// + +namespace YOSYS_PYTHON { + + [[noreturn]] static void log_python_exception_as_error() { + PyErr_Print(); + log_error("Python interpreter encountered an exception.\\n"); + } + + struct YosysStatics{}; + + // + + // Trampolines for Classes with Python-Overridable Virtual Methods + // https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python + class PassTrampoline : public Pass { + public: + using Pass::Pass; + + void help() override { + PYBIND11_OVERRIDE(void, Pass, help); + } + + bool formatted_help() override { + PYBIND11_OVERRIDE(bool, Pass, formatted_help); + } + + void clear_flags() override { + PYBIND11_OVERRIDE(void, Pass, clear_flags); + } + + void execute(std::vector args, RTLIL::Design *design) override { + PYBIND11_OVERRIDE_PURE( + void, + Pass, + execute, + args, + design + ); + } + + void on_register() override { + PYBIND11_OVERRIDE(void, Pass, on_register); + } + + void on_shutdown() override { + PYBIND11_OVERRIDE(void, Pass, on_shutdown); + } + + bool replace_existing_pass() const override { + PYBIND11_OVERRIDE( + bool, + Pass, + replace_existing_pass + ); + } + }; + + class MonitorTrampoline : public RTLIL::Monitor { + public: + using RTLIL::Monitor::Monitor; + + void notify_module_add(RTLIL::Module *module) override { + PYBIND11_OVERRIDE( + void, + RTLIL::Monitor, + notify_module_add, + module + ); + } + + void notify_module_del(RTLIL::Module *module) override { + PYBIND11_OVERRIDE( + void, + RTLIL::Monitor, + notify_module_del, + module + ); + } + + void notify_connect( + RTLIL::Cell *cell, + const RTLIL::IdString &port, + const RTLIL::SigSpec &old_sig, + const RTLIL::SigSpec &sig + ) override { + PYBIND11_OVERRIDE( + void, + RTLIL::Monitor, + notify_connect, + cell, + port, + old_sig, + sig + ); + } + + void notify_connect( + RTLIL::Module *module, + const RTLIL::SigSig &sigsig + ) override { + PYBIND11_OVERRIDE( + void, + RTLIL::Monitor, + notify_connect, + module, + sigsig + ); + } + + void notify_connect( + RTLIL::Module *module, + const std::vector &sigsig_vec + ) override { + PYBIND11_OVERRIDE( + void, + RTLIL::Monitor, + notify_connect, + module, + sigsig_vec + ); + } + + void notify_blackout( + RTLIL::Module *module + ) override { + PYBIND11_OVERRIDE( + void, + RTLIL::Monitor, + notify_blackout, + module + ); + } + }; + + /// @brief Use an auxiliary function to adapt the legacy function. + void log_to_stream(py::object object) + { + // TODO + }; + + PYBIND11_MODULE(libyosys, m) { + // this code is run on import + m.doc() = "python access to libyosys"; + + if (!yosys_already_setup()) { + log_streams.push_back(&std::cout); + log_error_stderr = true; + yosys_setup(); + + // Cleanup + m.add_object("_cleanup_handle", py::capsule([](){ + yosys_shutdown(); + })); + } + + m.def("log_to_stream", &log_to_stream, "pipes yosys logs to a Python stream"); + + // Trampoline Classes + py::class_>(m, "Pass") + .def(py::init([](std::string name, std::string short_help) { + auto created = new YOSYS_PYTHON::PassTrampoline(name, short_help); + Pass::init_register(); + return created; + }), py::arg("name"), py::arg("short_help")) + .def("help", &Pass::help) + .def("formatted_help", &Pass::formatted_help) + .def("execute", &Pass::execute) + .def("clear_flags", &Pass::clear_flags) + .def("on_register", &Pass::on_register) + .def("on_shutdown", &Pass::on_shutdown) + .def("replace_existing_pass", &Pass::replace_existing_pass) + .def("experimental", &Pass::experimental) + .def("internal", &Pass::internal) + .def("pre_execute", &Pass::pre_execute) + .def("post_execute", &Pass::post_execute) + .def("cmd_log_args", &Pass::cmd_log_args) + .def("cmd_error", &Pass::cmd_error) + .def("extra_args", &Pass::extra_args) + .def("call", py::overload_cast(&Pass::call)) + .def("call", py::overload_cast>(&Pass::call)) + ; + + py::class_(m, "Monitor") + .def(py::init([]() { + return new YOSYS_PYTHON::MonitorTrampoline(); + })) + .def("notify_module_add", &RTLIL::Monitor::notify_module_add) + .def("notify_module_del", &RTLIL::Monitor::notify_module_del) + .def( + "notify_connect", + py::overload_cast< + RTLIL::Cell *, + const RTLIL::IdString &, + const RTLIL::SigSpec &, + const RTLIL::SigSpec & + >(&RTLIL::Monitor::notify_connect) + ) + .def( + "notify_connect", + py::overload_cast< + RTLIL::Module *, + const RTLIL::SigSig & + >(&RTLIL::Monitor::notify_connect) + ) + .def( + "notify_connect", + py::overload_cast< + RTLIL::Module *, + const std::vector & + >(&RTLIL::Monitor::notify_connect) + ) + .def("notify_blackout", &RTLIL::Monitor::notify_blackout) + ; + + // + }; +}; + +#endif // WITH_PYTHON diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..caa620528 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=42", + "pybind11>=3,<4", +] +build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index 4a6ef5af9..59c1c4b33 100644 --- a/setup.py +++ b/setup.py @@ -16,18 +16,19 @@ import os import re import shlex import shutil +from pathlib import Path from setuptools import setup, Extension -from setuptools.command.build_ext import build_ext -__dir__ = os.path.dirname(os.path.abspath(__file__)) +import pybind11 +from pybind11.setup_helpers import build_ext + +__yosys_root__ = Path(__file__).parent yosys_version_rx = re.compile(r"YOSYS_VER\s*:=\s*([\w\-\+\.]+)") -version = yosys_version_rx.search( - open(os.path.join(__dir__, "Makefile"), encoding="utf8").read() -)[1].replace( - "+", "." -) # Convert to patch version +with open(__yosys_root__ / "Makefile", encoding="utf8") as f: + # Extract and convert + to patch version + version = yosys_version_rx.search(f.read())[1].replace("+", ".") class libyosys_so_ext(Extension): @@ -38,7 +39,13 @@ class libyosys_so_ext(Extension): "libyosys.so", [], ) + + # when iterating locally, you probably want to set this variable + # to avoid mass rebuilds bec of pybind11's include path changing + pybind_include = os.getenv("_FORCE_PYBIND_INCLUDE", pybind11.get_include()) + self.args = [ + f"PYBIND11_INCLUDE={pybind_include}", "ENABLE_PYOSYS=1", # Would need to be installed separately by the user "ENABLE_TCL=0", @@ -73,22 +80,23 @@ class libyosys_so_ext(Extension): *self.args, ] ) - build_path = os.path.dirname(os.path.dirname(bext.get_ext_fullpath(self.name))) - pyosys_path = os.path.join(build_path, "pyosys") + ext_fullpath = Path(bext.get_ext_fullpath(self.name)) + build_path = ext_fullpath.parents[1] + pyosys_path = build_path / "pyosys" os.makedirs(pyosys_path, exist_ok=True) # libyosys.so - target = os.path.join(pyosys_path, os.path.basename(self.name)) + target = pyosys_path / self.name shutil.copy(self.name, target) - bext.spawn(["strip", "-S", target]) + bext.spawn(["strip", "-S", str(target)]) # yosys-abc - yosys_abc_target = os.path.join(pyosys_path, "yosys-abc") + yosys_abc_target = pyosys_path / "yosys-abc" shutil.copy("yosys-abc", yosys_abc_target) - bext.spawn(["strip", "-S", yosys_abc_target]) + bext.spawn(["strip", "-S", str(yosys_abc_target)]) # share directory - share_target = os.path.join(pyosys_path, "share") + share_target = pyosys_path / "share" try: shutil.rmtree(share_target) except FileNotFoundError: @@ -104,14 +112,16 @@ class custom_build_ext(build_ext): return ext.custom_build(self) +with open(__yosys_root__ / "README.md", encoding="utf8") as f: + long_description = f.read() + setup( name="pyosys", packages=["pyosys"], version=version, description="Python access to libyosys", - long_description=open(os.path.join(__dir__, "README.md")).read(), + long_description=long_description, long_description_content_type="text/markdown", - install_requires=["wheel", "setuptools"], license="MIT", classifiers=[ "Programming Language :: Python :: 3", @@ -119,7 +129,6 @@ setup( "Operating System :: POSIX :: Linux", "Operating System :: MacOS :: MacOS X", ], - package_dir={"pyosys": "misc"}, python_requires=">=3.8", ext_modules=[libyosys_so_ext()], cmdclass={ diff --git a/tests/pyosys/run_tests.py b/tests/pyosys/run_tests.py new file mode 100644 index 000000000..953462c4f --- /dev/null +++ b/tests/pyosys/run_tests.py @@ -0,0 +1,39 @@ +from pathlib import Path +import shutil +import subprocess +import sys + +__file_dir__ = Path(__file__).absolute().parent + +if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} {sys.argv[1]}") + exit(64) + +binary = [] +if sys.argv[1] in ["yosys"]: + binary = [__file_dir__.parents[1] / "yosys", "-Qy"] +else: + binary = [sys.argv[1]] + +tests = __file_dir__.glob("test_*.py") +errors = False +log_dir = __file_dir__ / "logs" +try: + shutil.rmtree(log_dir) +except FileNotFoundError: + pass +for test in tests: + print(f"* {test.name} ", end="") + log_dir.mkdir(parents=True, exist_ok=True) + log = log_dir / (test.stem + ".log") + result = subprocess.run([ + *binary, + test + ], stdout=open(log, "w"), stderr=subprocess.STDOUT) + if result.returncode == 0: + print("OK!") + else: + print(f"FAILED: {log}") + errors = True +if errors: + exit(1) diff --git a/tests/pyosys/spm.cut.v.gz b/tests/pyosys/spm.cut.v.gz new file mode 100644 index 0000000000000000000000000000000000000000..44791a035e534f1fc9ebdfc4c47bb0849bff1da8 GIT binary patch literal 5294 zcmbu92{hFGzsJSc8Oo9ed0H^WWGhj&glt)|W@p5MFvvEHC9*HcRtY1?I)fq2DBC2G zr4$+K7)ugkLNb=I+?k%|-2Z*feeOB;{_i=T^E%(p=lgztKflj+e!uxWorB}r?`_^p zEWv^P@;5_6RuqPI{(iXTU_Bc z8gINxO*nZ-wA}JGB!E@M%c6%cUcP1xW+!Y%10Q!BbblwozQfv`HKv_b> z#!S6lubRa)M^9<)!J%QJ5B&n_rWQ6cO+&Kd8y-?8ramsF_YZz@if%93?sF;VA101G zOmF!;W~aZ{$m?rHc*pKua_nIfZDf_$LsW>_pM5h*BbRhctwT{DS_Xo-Sf5JuD+i}$o z?LpMc=K)30^DAPD%|RFSa{o%aNdIl$lO#jaA6M;bx1eS=2INJTt%xl&w;jC9lKzJs zMoG9a;M6~%M{ZkJS(hs3LDFHMb7it8b{B)#+3LWNU}1~H>3@8#&xHGT`+{5$>uM>Z zk}l8TC%Vbj9V*NvN4GQZUI48#Yrn+}azyFRoM)8KcrR8h$eMlJAXk*_%yZ@vp+8HY zwM%h>oKa>o!OSHB+eP?AfYz@Pca+P_26M^r?N))4*(285JTX4eqk>)hQLHAEl*L11gR^Hg=OOtuEgN zlkyFK6%X8v+Br>rQ}q0pcf?9xiPaC}p?+l22ucU%xEVgoa*PfgtN^B1kb(OYfFCH4 zf&Yz+$Ir_{on_JGAMjzeV|3_a&tr;(7|5p36^RV|n=*+w%F%H;ET9Mg*1&^- zM9R@IiEIXhum)}jJqE1D{(nNwG30#;9fDYp8$yQx%Q55~3g(!Hqw#V8OGwL`i=oEhUV`=s>Tm0_Okj$)^O~qJaAQ(9q3=*;Z#I)(TY;1 z{cJfLvpG&(jcGZU96^yN)@8AKqldfm2Yr*`nW+2LL|J0Qi6Nhsr^DDv zMuZtwQqs&Ok-y?pF&3ickN6e;Cj&7*`4j-cq*k&TsYXc(nW+8NL|$Tq*pScY@Eno{ zSUr=*K~=_p;&i#1Pv6npC-;)>@7AWcn$seORG&pbI!A}wkSn~^(`nx}mFqzfx@ox6 zaLqPyFY*3_PrQojK6TBmHM03twF}X<{(Jh3EZ2v}ug$M7ZFXxMSjSSWP$L)Lw{?Nq zhV7j5GT&C}m#r^-JUh;}Duy0p_Zxgsy7-)S!H?FjhTZSZpv+c!%~xy;jxO@uSiI~~ zQsQbC91C;Z64~7#_U_d^k5vLm4P;f)por77)PRRE8$T}RiG9WOlS&2IDO=5yi65A*N&K1|%lwK=mL0y|x! z%mG<3eyw4BT<`5sd@^GJ8bK-bsB-9C{pQo0%H z{l?q-JvZ3H`>yB&Q)&4b9bXrjMmb+s+UIjk*c0}mndpdu&d%UWLsRh*g4@86nRWcG z8pfLa0U7^x9sg9iIwZ414PDKJ zDyYFcMs^*Cnw~>jaHEvYp_d+E9{Z3*$$1x4ROW9*`d+_>QYxHtVBTp;y9va2r7H?WY>DtN0?lRO9$=lN9>tN$N02&Nv7FyK~WBOmDt@p zG{@MV$RkavSgtW_t^nb*N~27Ou2UA5@6_W4V>^nm69RJm=xCGNO{F?s@n9x>+XN{l ztbDNvnx(J?KY{F8#5>3oqebo2UmrtQds7HQOQGrP31PRA2=}JE&z8QJyj6MZU8Rk9 zFo(WyVl>C{T<>GqCIX?9k{Wf?;Vd#o)PcRU_#PL9@S|78rorc7ci0#Go4-%^Z|1&k zY>vALeEqHl!*|75+uk)<<#Q>em+q2zlHnlY$gHVVb1uyBnheUL*1mTl+c8tB3FgS@ zspKnm@hgAES)OYgPR=^^b-H5YkJJRMWCE0P6T4Wxdk2uMDeFTda2YRM9uGV0<=raD zn6$m3RMP;Q4?Q3T(t4X;#orF4^^Q9YN$%+yMG>;`*w|z5hBd?}5$42Tf_iM;n}e!Y+k%Bb<>ZV(I5 z+{s)J(0g&@Ch}mNkXw%e-M}H8h>^GFYe9S?xi%;edmAV`kDvDbJt!-CAPDb`tKXZ?fKn5_zQT+Z6XeP*271>EoFze3%_Stgaow{L*b0&`c(pMAx9h2U`2UD^6rd6H1A{#%ma79(}g*wFBT%rBo z3|tXMpEQbYc#x}UoDvb-Z?t66BqjiDo$nG;HybPPR+a9Azey!`f)!3gWR@gl>wGJ<=`mXW`jsv@oKbvl+J60^V z>VxRl6eU2OAa&8t1;ZePYw2Tb8JC#m_kVe|=pNNi^c|h?FP|0MIccT_(MQEpw+izz z`~$+CuE$tSjRkZv)^qeVnj2I@Gj-Z3gtw9e8v-rE)s>WsRxBoqhrV_iO$rQ~*-Hdm zD$mT%Z3I^oKi8NJHV$3t3LQ)(BL%XyiY(__)Hvi|;cBv8xK-gB-=U^7=?6W9WKV4!YVg^30J@rG>X;SLx}K*3i_p0O zqyH@`PDM1j<1UUCgX+}HgPJ!y@`-abCk?)76x;-i!=~lx{DlJo(o^3QgIa=c&5ic0 zZ4hZ-I1)W3Cqe#Th5pk+-?0hr)|*-j8K@I!iRfsy_#SCOs{;X5OIF_U&a(v|MCqS0 zPk0G>Oi6S?wJK%9ob)xKhTV5IYPO<>pTm=`(-CGY$!{5m}QHjzN(Y`xg`a+1}4%uub; z@4I(EjUf?Hs%vPNq_nftU0j6F3j? zd_ju}dQ!9*S#H8e3R_){kela>Up8pMU+Q6}{($KfJF(#oES_9C9L!w~k0beZ=uf3| zoj&FbS1^>;c4tcc!Ey+d1ZIEJ=D33aJk_vv7fEIpzs{#{F{jI753qt*2=@{T0u=FW z8^hTw4_tisx~_QSl}z)UIi=0KwaI;-iEeCVVP^sEg}!B$WWEm&jNr>jX^5i)p3nKQ z$jzNIcbtdh1-hr7!=H*&S%A?rbC_O77)+;_t}okCSUFhkb7)U1NddcswuA=_#SI^` z7!4yQlrsR`HiK^Lva8w)q-;E}Tqrz1UR&Gogg1)XS_GApsSBKMWI7VGd9to=*d!_F zN%P!6^KU8ajKYM~i=^x)&CB_Bex<82fTGiNYWA8bD1)GAK1U0u&5wYO1g42yfNMFs|Nq$>qs15S!g$$NZp$@9^ojaIg z94PA9W~gKpdRucL9*~!R-JWET1Gl!_bN9c(Jk)oxb|QE-DO)BHr3K=d=(B5X_cFWg zxbB3{%A@$S)EJ2KCdoP*x=)@ ztns2uIZEE|C_u%XvJ3R&PU~DYJf;VNhNzr*`KqHuL$xLN#?RK6En03eiuUHP1rBfC zpM`C0hi(n3Z}43<>mGYEQmX>LdzU035wy14Z+;PeadvjW(n_*_3xaTTIrNQS(}PZ2 z8=m_VK*MRRn!>viP$tR}()Oi=${}V-{^dR=itWOwY_;wm^Vl5u4$s!6y_ZA`>nmv* z4MXfUh&|IY32YB@?SX7!SwJ*epVe2ZrCjku`O*b+!`sJ$`Cy*go|yGV-F>pYcJ@l9 zLqA1rh3$-#>^!Z=(AIpLA&l&}a)eJLFN70q3^TQXy^wHmvgZ}GmBL9wOzWY%%%~hk zt76AYgJN6Twj`V0TA!SXQA}iG zYB

?mDysFXSuX;4F^O7lLtzQ3eatMa1o@(T$cupie>-ZOUy)BOK^QjcuA_hst*+>b zavH)@KO^WX2#(ORk>EXRF~N1!SmKi;qevD2M+nwvh}t2WM!+%=f=?A&2^=*+Y*JY| z(dHMf@A_WM*WjWng$|f2a|}vd9A4iIEZYUomXT*SjvCH1AB^ECu)Iu iM^_(Fv>?ZgTU5hGU03U44{mSFt_EJpjj<_UV)_p!;ECJ- literal 0 HcmV?d00001 diff --git a/tests/pyosys/test_data_read.py b/tests/pyosys/test_data_read.py new file mode 100644 index 000000000..08b6695c2 --- /dev/null +++ b/tests/pyosys/test_data_read.py @@ -0,0 +1,45 @@ +from pyosys import libyosys as ys +from pathlib import Path + +__file_dir__ = Path(__file__).absolute().parent + +d = ys.Design() + +ys.run_pass(f"read_verilog {__file_dir__ / 'spm.cut.v.gz'}", d) +ys.run_pass("hierarchy -top spm", d) + +name_by_tv_location = [] +name_by_au_location = [] + +# test both dictionary mapping and equiv operators working fine +module = None +print(d.modules_) +for idstr, module_obj in d.modules_.items(): + if idstr != ys.IdString("\\spm"): + continue + if idstr.str() != "\\spm": + continue + module = module_obj + break + +assert module == d.top_module(), "top module search failed" +for name in module.ports: + wire = module.wires_[name] + name_str = name.str() + if name_str.endswith(".d"): # single reg output, in au + name_by_au_location.append(name_str[1:-2]) + elif name_str.endswith(".q"): # single reg input, in tv + name_by_tv_location.append(name_str[1:-2]) + else: # port/boundary scan + frm = wire.start_offset + wire.width + to = wire.start_offset + for i in range(frm - 1, to - 1, -1): + bit_name = name_str[1:] + f"\\[{i}\\]" + if wire.port_input: + name_by_tv_location.append(bit_name) + elif wire.port_output: + name_by_au_location.append(bit_name) + +assert name_by_tv_location == ['x\\[0\\]', 'a\\[31\\]', 'a\\[30\\]', 'a\\[29\\]', 'a\\[28\\]', 'a\\[27\\]', 'a\\[26\\]', 'a\\[25\\]', 'a\\[24\\]', 'a\\[23\\]', 'a\\[22\\]', 'a\\[21\\]', 'a\\[20\\]', 'a\\[19\\]', 'a\\[18\\]', 'a\\[17\\]', 'a\\[16\\]', 'a\\[15\\]', 'a\\[14\\]', 'a\\[13\\]', 'a\\[12\\]', 'a\\[11\\]', 'a\\[10\\]', 'a\\[9\\]', 'a\\[8\\]', 'a\\[7\\]', 'a\\[6\\]', 'a\\[5\\]', 'a\\[4\\]', 'a\\[3\\]', 'a\\[2\\]', 'a\\[1\\]', 'a\\[0\\]', '_315_', '_314_', '_313_', '_312_', '_311_', '_310_', '_309_', '_308_', '_307_', '_306_', '_305_', '_304_', '_303_', '_302_', '_301_', '_300_', '_299_', '_298_', '_297_', '_296_', '_295_', '_294_', '_293_', '_292_', '_291_', '_290_', '_289_', '_288_', '_287_', '_286_', '_285_', '_284_', '_283_', '_282_', '_281_', '_280_', '_279_', '_278_', '_277_', '_276_', '_275_', '_274_', '_273_', '_272_', '_271_', '_270_', '_269_', '_268_', '_267_', '_266_', '_265_', '_264_', '_263_', '_262_', '_261_', '_260_', '_259_', '_258_', '_257_', '_256_', '_255_', '_254_', '_253_', '_252_'], "failed to extract test vector register locations" +assert name_by_au_location == ['y\\[0\\]', '_315_', '_314_', '_313_', '_312_', '_311_', '_310_', '_309_', '_308_', '_307_', '_306_', '_305_', '_304_', '_303_', '_302_', '_301_', '_300_', '_299_', '_298_', '_297_', '_296_', '_295_', '_294_', '_293_', '_292_', '_291_', '_290_', '_289_', '_288_', '_287_', '_286_', '_285_', '_284_', '_283_', '_282_', '_281_', '_280_', '_279_', '_278_', '_277_', '_276_', '_275_', '_274_', '_273_', '_272_', '_271_', '_270_', '_269_', '_268_', '_267_', '_266_', '_265_', '_264_', '_263_', '_262_', '_261_', '_260_', '_259_', '_258_', '_257_', '_256_', '_255_', '_254_', '_253_', '_252_'], "failed to extract golden output register locations" +print("ok!") diff --git a/tests/pyosys/test_dict.py b/tests/pyosys/test_dict.py new file mode 100644 index 000000000..81e7b5516 --- /dev/null +++ b/tests/pyosys/test_dict.py @@ -0,0 +1,13 @@ +from pyosys import libyosys as ys + +my_dict = ys.StringToStringDict() +my_dict["foo"] = "bar" +my_dict.update([("first", "second")]) +my_dict.update({"key": "value"}) +for key, value in my_dict.items(): + print(key, value) + +new_dict = my_dict | {"tomato": "tomato"} +del new_dict["foo"] +assert set(my_dict.keys()) == {"first", "key", "foo"} +assert set(new_dict.keys()) == {"first", "key", "tomato"} diff --git a/tests/pyosys/test_idict.py b/tests/pyosys/test_idict.py new file mode 100644 index 000000000..fd04f4b8c --- /dev/null +++ b/tests/pyosys/test_idict.py @@ -0,0 +1,31 @@ +from pyosys import libyosys as ys + +my_idict = ys.IdstringIdict() +print(my_idict(ys.IdString("\\hello"))) +print(my_idict(ys.IdString("\\world"))) +print(my_idict.get(ys.IdString("\\world"))) +try: + print(my_idict.get(ys.IdString("\\dummy"))) +except IndexError as e: + print(f"{repr(e)}") +print(my_idict[0]) +print(my_idict[1]) +try: + print(my_idict[2]) +except IndexError as e: + print(f"{repr(e)}") + +for i in my_idict: + print(i) + +current_len = len(my_idict) +assert current_len == 2, "copy" + +my_copy = my_idict.copy() +my_copy(ys.IdString("\\copy")) +assert len(my_idict) == current_len, "copy seemed to have mutate original idict" +assert len(my_copy) == current_len + 1, "copy not behaving as expected" + +current_copy_len = len(my_copy) +my_copy |= (ys.IdString(e) for e in ("\\the", "\\world")) # 1 new element +assert len(my_copy) == current_copy_len + 1, "or operator returned unexpected result" diff --git a/tests/pyosys/test_import.py b/tests/pyosys/test_import.py new file mode 100644 index 000000000..48e911033 --- /dev/null +++ b/tests/pyosys/test_import.py @@ -0,0 +1,3 @@ +from pyosys import libyosys as ys + +ys.log("Hello, world!") diff --git a/tests/pyosys/test_monitor.py b/tests/pyosys/test_monitor.py new file mode 100644 index 000000000..2eefdad60 --- /dev/null +++ b/tests/pyosys/test_monitor.py @@ -0,0 +1,22 @@ +from pyosys import libyosys as ys +from pathlib import Path + +__file_dir__ = Path(__file__).absolute().parent + +d = ys.Design() + +class Monitor(ys.Monitor): + def __init__(self): + super().__init__() + self.mods = [] + + def notify_module_add(self, mod): + self.mods.append(mod.name.str()) + +m = Monitor() +d.monitors.add(m) + +ys.run_pass(f"read_verilog {__file_dir__ / 'spm.cut.v.gz'}", d) +ys.run_pass("hierarchy -top spm", d) + +assert m.mods == ["\\spm"] diff --git a/tests/pyosys/test_pass.py b/tests/pyosys/test_pass.py new file mode 100644 index 000000000..d8174d4fc --- /dev/null +++ b/tests/pyosys/test_pass.py @@ -0,0 +1,34 @@ +from pyosys import libyosys as ys + +import json +from pathlib import Path + +__file_dir__ = Path(__file__).absolute().parent + +class CellStatsPass(ys.Pass): + def __init__(self): + super().__init__( + "cell_stats", + "dumps cell statistics in JSON format" + ) + + def execute(self, args, design): + ys.log_header(design, "Dumping cell stats\n") + ys.log_push() + cell_stats = {} + for module in design.all_selected_whole_modules(): + for cell in module.selected_cells(): + if cell.type.str() in cell_stats: + cell_stats[cell.type.str()] += 1 + else: + cell_stats[cell.type.str()] = 1 + ys.log(json.dumps(cell_stats)) + ys.log_pop() + +p = CellStatsPass() # registration + +design = ys.Design() +ys.run_pass(f"read_verilog {__file_dir__.parent / 'simple' / 'fiedler-cooley.v'}", design) +ys.run_pass("prep", design) +ys.run_pass("opt -full", design) +ys.run_pass("cell_stats", design) diff --git a/tests/pyosys/test_script.py b/tests/pyosys/test_script.py new file mode 100644 index 000000000..7c3ec96ef --- /dev/null +++ b/tests/pyosys/test_script.py @@ -0,0 +1,21 @@ +from pathlib import Path +from pyosys import libyosys as ys + + +__file_dir__ = Path(__file__).absolute().parent +add_sub = __file_dir__.parent / "arch" / "common" / "add_sub.v" + +base = ys.Design() +ys.run_pass(f"read_verilog {add_sub}", base) +ys.run_pass("hierarchy -top top", base) +ys.run_pass("proc", base) +ys.run_pass("equiv_opt -assert -map +/ecp5/cells_sim.v synth_ecp5", base) + +postopt = ys.Design() +ys.run_pass("design -load postopt", postopt) +ys.run_pass("cd top", postopt) +ys.run_pass("select -assert-min 25 t:LUT4", postopt) +ys.run_pass("select -assert-max 26 t:LUT4", postopt) +ys.run_pass("select -assert-count 10 t:PFUMX", postopt) +ys.run_pass("select -assert-count 6 t:L6MUX21", postopt) +ys.run_pass("select -assert-none t:LUT4 t:PFUMX t:L6MUX21 %% t:* %D", postopt) From 384f7431fdb08b7ba348567b003745a3369c204f Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Sun, 21 Sep 2025 23:04:27 +0300 Subject: [PATCH 33/49] pyosys: rewrite wrapper generator [skip ci] --- pyosys/.gitignore | 1 + pyosys/__init__.py | 1 - pyosys/generator.py | 2695 ++++++++++--------------------------- pyosys/hashlib.h | 14 + pyosys/wrappers_tpl.cc | 25 +- pyproject.toml | 5 +- tests/pyosys/test_logs.py | 8 + 7 files changed, 738 insertions(+), 2011 deletions(-) create mode 100644 tests/pyosys/test_logs.py diff --git a/pyosys/.gitignore b/pyosys/.gitignore index f9fbdf4f6..925a2bd84 100644 --- a/pyosys/.gitignore +++ b/pyosys/.gitignore @@ -1 +1,2 @@ wrappers.cc +wrappers.inc.cc diff --git a/pyosys/__init__.py b/pyosys/__init__.py index 4622464da..d74e3f5bd 100644 --- a/pyosys/__init__.py +++ b/pyosys/__init__.py @@ -1,4 +1,3 @@ - import os import sys diff --git a/pyosys/generator.py b/pyosys/generator.py index ebe89737e..b8a7aa8dc 100644 --- a/pyosys/generator.py +++ b/pyosys/generator.py @@ -15,2025 +15,712 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -# Author: Benedikt Tutzer -# Modified for pybind11 by: Mohamed Gaber +# Written by Mohamed Gaber +# +# Inspired by py_wrap_generator.py by Benedikt Tutzer -import argparse -import copy -from enum import Enum -from io import StringIO +import io +import shutil from pathlib import Path -from functools import wraps -from typing import ClassVar, Optional +from sysconfig import get_paths +from dataclasses import dataclass, field +from typing import Any, Dict, FrozenSet, Iterable, Tuple, Union, Optional, List + +import pybind11 +import argparse +from cxxheaderparser.simple import parse_file, ClassScope, NamespaceScope, EnumDecl +from cxxheaderparser.options import ParserOptions +from cxxheaderparser.preprocessor import make_gcc_preprocessor +from cxxheaderparser.types import ( + PQName, + Type, + Pointer, + Reference, + MoveReference, + AnonymousName, + Method, + Function, + Field, + Variable, + Array, + FundamentalSpecifier, +) __file_dir__ = Path(__file__).absolute().parent +__yosys_root__ = __file_dir__.parent -def autostring(fn): - @wraps(fn) - def wrapper(*args, **kwargs): - if "stream" not in kwargs: - stream = StringIO() - fn(*args, stream=stream, **kwargs) - return stream.getvalue() - else: - fn(*args, **kwargs) +@dataclass +class PyosysClass: + """ + Metadata about classes or structs intended to be wrapped using Pyosys. - return wrapper + :param name: The base name of the class (without extra qualifiers) + :param ref_only: Whether this class can be copied to Python, or only + referenced. + :param string_expr: A C++ expression that will be used for the __str__ method in Python + :param hash_expr: A C++ expression that will be fed to ``run_hash`` to declare a __hash__ method for Python + :param denylist: If specified, one or more methods can be excluded from + wrapping. + """ + name: str + ref_only: bool = False + + # in the format s.(method or property) + string_expr: Optional[str] = None + hash_expr: Optional[str] = None + + denylist: FrozenSet[str] = frozenset({}) -# Map c++ operator Syntax to Python functions -wrappable_operators = { - "<": "__lt__", - "==": "__eq__", - "!=": "__ne__", - "+": "__add__", - "-": "__sub__", - "*": "__mul__", - "/": "__div__", - "()": "__call__", -} +@dataclass +class PyosysHeader: + """ + :param name: The name of the header, i.e., its relative path to the Yosys root + :param classes: A list of ``PyosysClass`` classes to be wrapped + :param enums: A list of enums to be wrapped + """ + name: str + classes: List[PyosysClass] = field(default_factory=lambda: []) + + def __post_init__(self): + self.classes_by_name = {} + if classes := self.classes: + for cls in classes: + self.classes_by_name[cls.name] = cls + +""" +Add headers and classes here! +""" +global_denylist = frozenset( + { + # deprecated + "builtin_ff_cell_types", + # no implementation + "set_verific_logging", + # can't bridge to python cleanly + ## std::regex + "log_warn_regexes", + "log_nowarn_regexes", + "log_werror_regexes", + ## function pointers + "log_error_atexit", + "log_verific_callback", + } +) +pyosys_headers = [ + # Headers for incomplete types + PyosysHeader("kernel/binding.h"), + PyosysHeader("libs/sha1/sha1.h"), + # Headers for globals + PyosysHeader("kernel/log.h"), + PyosysHeader("kernel/yosys.h"), + PyosysHeader("kernel/cost.h"), + # Headers with classes + PyosysHeader( + "kernel/celltypes.h", + [PyosysClass("CellType", hash_expr="s.type"), PyosysClass("CellTypes")], + ), + PyosysHeader("kernel/consteval.h", [PyosysClass("ConstEval")]), + PyosysHeader( + "kernel/register.h", + [ + # PyosysClass("Pass") # Virtual methods, manually bridged + ], + ), + PyosysHeader( + "kernel/rtlil.h", + [ + PyosysClass( + "IdString", + string_expr="s.str()", + hash_expr="s.str()", + denylist=frozenset( + # shouldn't be messed with from python in general + { + "global_id_storage_", + "global_id_index_", + "global_refcount_storage_", + "global_free_idx_list_", + "last_created_idx_ptr_", + "last_created_idx_", + "builtin_ff_cell_types", + } + ), + ), + PyosysClass("Const", string_expr="s.as_string()", denylist=frozenset({"bits", "bitvectorize"})), + PyosysClass("AttrObject", denylist=frozenset({"get_blackbox_attribute"})), + PyosysClass("NamedObject", denylist=frozenset({"get_blackbox_attribute"})), + PyosysClass("Selection"), + # PyosysClass("Monitor"), # Virtual methods, manually bridged + PyosysClass("CaseRule", denylist=frozenset({"get_blackbox_attribute"})), + PyosysClass("SwitchRule", denylist=frozenset({"get_blackbox_attribute"})), + PyosysClass("SyncRule"), + PyosysClass( + "Process", + ref_only=True, + string_expr="s.name.c_str()", + hash_expr="s.name", + ), + PyosysClass("SigChunk"), + PyosysClass("SigBit", hash_expr="s"), + PyosysClass("SigSpec", hash_expr="s"), + PyosysClass( + "Cell", + ref_only=True, + string_expr="s.name.c_str()", + hash_expr="s", + ), + PyosysClass( + "Wire", + ref_only=True, + string_expr="s.name.c_str()", + hash_expr="s", + ), + PyosysClass( + "Memory", + ref_only=True, + string_expr="s.name.c_str()", + hash_expr="s", + ), + PyosysClass( + "Module", + ref_only=True, + string_expr="s.name.c_str()", + hash_expr="s", + denylist=frozenset({"Pow"}), # has no implementation + ), + PyosysClass( + "Design", + ref_only=True, + string_expr="s.hashidx_", + hash_expr="s", + denylist=frozenset({"selected_whole_modules"}), # deprecated + ), + ], + ), +] + + +@dataclass(frozen=True) # hashable +class PyosysType: + """ + Bit of a hacky object all-around: this is more or less used to encapsulate + container types so they can be later made opaque using pybind. + """ + base: str + specialization: Tuple["PyosysType", ...] + const: bool = False + + @classmethod + def from_type(Self, type_obj, drop_const=False) -> "PyosysType": + const = type_obj.const and not drop_const + if isinstance(type_obj, Pointer): + ptr_to = Self.from_type(type_obj.ptr_to) + return Self("ptr", (ptr_to,), const) + elif isinstance(type_obj, Reference): + ref_to = Self.from_type(type_obj.ref_to) + return Self("ref", (ref_to,), const) + assert isinstance( + type_obj, Type + ), f"unexpected c++ type object of type {type(type_obj)}" + last_segment = type_obj.typename.segments[-1] + base = last_segment.name + specialization = tuple() + if ( + hasattr(last_segment, "specialization") + and last_segment.specialization is not None + ): + for template_arg in last_segment.specialization.args: + specialization = (*specialization, Self.from_type(template_arg.arg)) + return Self(base, specialization, const) + + def generate_identifier(self): + title = self.base.title() + if len(self.specialization) == 0: + return title + + if title == "Dict": + key, value = self.specialization + return f"{key.generate_identifier()}To{value.generate_identifier()}{title}" + + return ( + "".join(spec.generate_identifier() for spec in self.specialization) + title + ) + + def generate_cpp_name(self): + const_prefix = "const " * self.const + if len(self.specialization) == 0: + return const_prefix + self.base + elif self.base == "ptr": + return const_prefix + f"{self.specialization[0].generate_cpp_name()} *" + elif self.base == "ref": + return const_prefix + f"{self.specialization[0].generate_cpp_name()} &" + else: + return ( + const_prefix + + f"{self.base}<{', '.join(spec.generate_cpp_name() for spec in self.specialization)}>" + ) + + +class PyosysWrapperGenerator(object): + def __init__( + self, + from_headers: Iterable[PyosysHeader], + wrapper_stream: io.TextIOWrapper, + header_stream: io.TextIOWrapper, + ): + self.headers = from_headers + self.f = wrapper_stream + self.f_inc = header_stream + self.found_containers: Dict[PyosysType, Any] = {} + self.class_registry: Dict[str, ClassScope] = {} + + # entry point + def generate(self): + tpl = __file_dir__ / "wrappers_tpl.cc" + preprocessor_opts = self.make_preprocessor_options() + with open(tpl, encoding="utf8") as f: + do_line_directive = True + for i, line in enumerate(f): + if do_line_directive: + self.f.write(f'#line {i + 1} "{tpl}"\n') + do_line_directive = False + if "" in line: + for header in self.headers: + self.f.write(f'#include "{header.name}"\n') + do_line_directive = True + elif "" in line: + for header in self.headers: + header_path = __yosys_root__ / header.name + parsed = parse_file(header_path, options=preprocessor_opts) + global_namespace = parsed.namespace + self.process_namespace(header, global_namespace) + else: + self.f.write(line) + + for container, _ in self.found_containers.items(): + identifier = container.generate_identifier() + print( + f"using {identifier} = {container.generate_cpp_name()};", + file=self.f_inc, + ) + print(f"PYBIND11_MAKE_OPAQUE({identifier})", file=self.f_inc) + + print( + f"static void bind_autogenerated_opaque_containers(py::module &m) {{", + file=self.f_inc, + ) + for container, _ in self.found_containers.items(): + identifier = container.generate_identifier() + cxx = container.generate_cpp_name() + tpl_args = [cxx] + for spec in container.specialization: + tpl_args.append(spec.generate_cpp_name()) + print( + f'\tpy::hashlib::bind_{container.base}<{", ".join(tpl_args)}>(m, "{container.generate_identifier()}");', + file=self.f_inc, + ) + print(f"}}", file=self.f_inc) + + # helpers + def make_preprocessor_options(self): + py_include = get_paths()["include"] + preprocessor_bin = shutil.which("clang++") or "g++" + return ParserOptions( + preprocessor=make_gcc_preprocessor( + defines=["_YOSYS_", "WITH_PYTHON"], + gcc_args=[preprocessor_bin, "-fsyntax-only"], + include_paths=[str(__yosys_root__), py_include, pybind11.get_include()], + ), + ) + + @staticmethod + def find_containers( + containers: Iterable[str], type_info: Any + ) -> Dict[PyosysType, Any]: + if isinstance(type_info, Pointer): + return PyosysWrapperGenerator.find_containers(containers, type_info.ptr_to) + if isinstance(type_info, MoveReference): + return PyosysWrapperGenerator.find_containers( + containers, type_info.moveref_to + ) + if isinstance(type_info, Reference): + return PyosysWrapperGenerator.find_containers(containers, type_info.ref_to) + if not isinstance(type_info, Type): + return () + segments = type_info.typename.segments + containers_found = {} + for segment in segments: + if isinstance(segment, FundamentalSpecifier): + continue + if segment.name in containers: + containers_found.update( + {PyosysType.from_type(type_info, drop_const=True): type_info} + ) + if segment.specialization is not None: + for arg in segment.specialization.args: + sub_containers = PyosysWrapperGenerator.find_containers( + containers, arg.arg + ) + containers_found.update(sub_containers) + return containers_found + + @staticmethod + def find_anonymous_union(cls: ClassScope): + if cls.class_decl.typename.classkey != "union": + return None + for s in cls.class_decl.typename.segments: + if isinstance(s, AnonymousName): + return s + return None # named union + + @staticmethod + def get_parameter_types(function: Function) -> str: + return ", ".join(p.type.format() for p in function.parameters) + + def register_containers(self, target: Union[Function, Field, Variable]): + supported = ("dict", "idict", "pool", "set", "vector") + if isinstance(target, Function): + self.found_containers.update( + self.find_containers(supported, target.return_type) + ) + + for parameter in target.parameters: + self.found_containers.update( + self.find_containers(supported, parameter.type) + ) + else: + self.found_containers.update(self.find_containers(supported, target.type)) + + # processors + def get_overload_cast(self, function: Function, class_basename: Optional[str]) -> str: + is_method = isinstance(function, Method) + function_return_type = function.return_type.format() + if class_basename == "Const" and function_return_type in {"iterator", "const_iterator"}: + # HACK: qualify Const's iterators + function_return_type = f"{class_basename}::{function_return_type}" + + pointer_kind = f"{class_basename}::*" if (is_method and not function.static) else "*" + + retval = f"static_cast <" + retval += function_return_type + retval += f"({pointer_kind})" + retval += f"({self.get_parameter_types(function)})" + if is_method and function.const: + retval += " const" + retval += ">" + retval += "(&" + if is_method: + retval += f"{class_basename}::" + retval += function.name.segments[-1].format() + retval += ")" + return retval + + def get_definition_args(self, function: Function, class_basename: Optional[str], python_name_override: Optional[str] = None) -> List[str]: + function_basename = function.name.segments[-1].format() + + python_function_basename = python_name_override or keyword_aliases.get(function_basename, function_basename) + + def_args = [f'"{python_function_basename}"'] + def_args.append(self.get_overload_cast(function, class_basename)) + for parameter in function.parameters: + # ASSUMPTION: there are no unnamed parameters in the yosys codebase + parameter_arg = f'py::arg("{parameter.name}")' + if parameter.default is not None: + parameter_arg += f" = {parameter.default.format()}" + def_args.append(parameter_arg) + + return def_args + + def process_method(self, function: Method, class_basename: str): + if ( + function.deleted + or function.template + or function.vararg + or function.access != "public" + or function.pure_virtual + or function.destructor + ): + return + + if any(isinstance(p.type, MoveReference) for p in function.parameters): + # skip move constructors + return + + if len(function.name.segments) > 1: + # can't handle, skip + return + + if function.constructor: + print( + f"\t\t\t.def(py::init<{self.get_parameter_types(function)}>())", + file=self.f, + ) + return + + python_name_override = None + if function.operator is not None: + if function.operator == "==": + python_name_override = "__eq__" + elif function.operator == "!=": + python_name_override = "__ne__" + elif function.operator == "<": + python_name_override = "__lt__" + else: + return + + self.register_containers(function) + + definition_fn = "def" + if function.static: + definition_fn = "def_static" + + print(f"\t\t\t.{definition_fn}({", ".join(self.get_definition_args(function, class_basename, python_name_override))})", file=self.f) + + def process_function(self, function: Function): + if ( + function.deleted + or function.template + or function.vararg + or function.static + ): + return + + if function.operator is not None: + # Python doesn't do global operators + return + + if function.name.segments[-1].format() in global_denylist: + return + + self.register_containers(function) + + print(f"\t\t\tm.def({", ".join(self.get_definition_args(function, None))});", file=self.f) + + def process_field(self, field: Field, class_basename: str): + if field.access != "public": + return + + if field.name is None: + # anonymous structs and unions + # unions handled in calling function + # ASSUMPTION: No anonymous structs in the yosys codebase + # (they're not in the C++ standard anyway) + return + + unique_ptrs = self.find_containers(("unique_ptr",), field.type) + if len(unique_ptrs): + # TODO: figure out how to bridge unique pointers + return + + self.register_containers(field) + + definition_fn = f"def_{'readonly' if field.type.const else 'readwrite'}" + if field.static: + definition_fn += "_static" + + field_python_basename = keyword_aliases.get(field.name, field.name) + + print( + f'\t\t\t.{definition_fn}("{field_python_basename}", &{class_basename}::{field.name})', + file=self.f, + ) + + def process_variable(self, variable: Variable): + if isinstance(variable.type, Array): + return + + variable_basename = variable.name.segments[-1].format() + if variable_basename in global_denylist: + return + + self.register_containers(variable) + + definition_fn = f"def_{'readonly' if variable.type.const else 'readwrite'}_static" + + variable_python_basename = keyword_aliases.get(variable_basename, variable_basename) + variable_name = variable.name.format() + + print( + f'\t\t\tglobal_variables.{definition_fn}("{variable_python_basename}", &{variable_name});', + file=self.f, + ) + + def process_class_members( + self, + metadata: PyosysClass, + cls: ClassScope, + basename: str + ): + for method in cls.methods: + if method.name.segments[-1].name in metadata.denylist: + continue + self.process_method(method, basename) + + visited_anonymous_unions = set() + for field in cls.fields: + if field.name in metadata.denylist: + continue + self.process_field(field, basename) + + # Handle anonymous unions + for subclass in cls.classes: + if subclass.class_decl.access != "public": + continue + if au := self.find_anonymous_union(subclass): + if au.id in visited_anonymous_unions: + continue + visited_anonymous_unions.add(au.id) + for subfield in subclass.fields: + self.process_field(subfield, basename) + + def process_class( + self, + metadata: PyosysClass, + cls: ClassScope, + namespace_components: Tuple[str, ...], + ): + pqname: PQName = cls.class_decl.typename + full_path = list(namespace_components) + [ + segment.format() for segment in pqname.segments + ] + basename = full_path.pop() + self.class_registry[basename] = cls + + declaration_namespace = "::".join(full_path) + tpl_args = [basename] + if metadata.ref_only: + tpl_args.append(f"std::unique_ptr<{basename}, py::nodelete>") + print( + f'\t\t{{using namespace {declaration_namespace}; py::class_<{", ".join(tpl_args)}>(m, "{basename}")', + file=self.f, + ) + + self.process_class_members(metadata, cls, basename) + for base in cls.class_decl.bases: + if base.access != "public": + continue + name = base.typename.segments[-1].format() + if base_scope := self.class_registry.get(name): + self.process_class_members(metadata, base_scope, basename) + + if expr := metadata.string_expr: + print(f'\t\t.def("__str__", [](const {basename} &s) {{ return {expr}; }})', file=self.f) + + if expr := metadata.hash_expr: + print(f'\t\t.def("__hash__", [](const {basename} &s) {{ return run_hash({expr}); }})', file=self.f) + + print(f"\t\t;}}", file=self.f) + + def process_enum( + self, + enum: EnumDecl, + namespace_components: Tuple[str, ...], + ): + pqname: PQName = enum.typename + full_path = list(namespace_components) + [ + segment.format() for segment in pqname.segments + ] + basename = full_path.pop() + + declaration_namespace = "::".join(full_path) + print( + f'\t\t{{using namespace {declaration_namespace}; py::native_enum<{basename}>(m, "{basename}", "enum.Enum")', + file=self.f, + ) + enum_class = enum.typename.classkey == "enum class" + for value in enum.values: + enum_class_qualifier = f"{basename}::" * enum_class + print(f'\t\t\t.value("{value.name}", {enum_class_qualifier}{value.name})', file=self.f) + print(f"\t\t\t.finalize();}}", file=self.f) + + + def process_namespace( + self, + header: PyosysHeader, + ns: NamespaceScope, + namespace_components: Tuple[str, ...] = (), + ): + for name, subns in ns.namespaces.items(): + self.process_namespace(header, subns, (*namespace_components, name)) + if len(namespace_components) and (len(ns.functions) + len(ns.variables)): + # TODO: Not essential but maybe move namespace usage into + # process_function for consistency? + print(f"\t\t{{ using namespace {'::'.join(namespace_components)};", file=self.f) + for function in ns.functions: + self.process_function(function) + for variable in ns.variables: + self.process_variable(variable) + print(f"\t\t}}", file=self.f) + for enum in ns.enums: + self.process_enum(enum, namespace_components) + for cls in ns.classes: + pqname = cls.class_decl.typename + declared_name_str = pqname.segments[-1].format() + if cls_metadata := header.classes_by_name.get(declared_name_str): + self.process_class(cls_metadata, cls, namespace_components) + -# Restrict certain strings from being function names in Python keyword_aliases = { - "in": "in_", - "False": "False_", - "None": "None_", - "True": "True_", - "and": "and_", - "as": "as_", - "assert": "assert_", - "break": "break_", - "class": "class_", - "continue": "continue_", - "def": "def_", - "del": "del_", - "elif": "elif_", - "else": "else_", - "except": "except_", - "for": "for_", - "from": "from_", - "global": "global_", - "if": "if_", - "import": "import_", - "in": "in_", - "is": "is_", - "lambda": "lambda_", - "nonlocal": "nonlocal_", - "not": "not_", - "or": "or_", - "pass": "pass_", - "raise": "raise_", - "return": "return_", - "try": "try_", - "while": "while_", - "with": "with_", - "yield": "yield_", + "in": "in_", + "False": "False_", + "None": "None_", + "True": "True_", + "and": "and_", + "as": "as_", + "assert": "assert_", + "break": "break_", + "class": "class_", + "continue": "continue_", + "def": "def_", + "del": "del_", + "elif": "elif_", + "else": "else_", + "except": "except_", + "for": "for_", + "from": "from_", + "global": "global_", + "if": "if_", + "import": "import_", + "in": "in_", + "is": "is_", + "lambda": "lambda_", + "nonlocal": "nonlocal_", + "not": "not_", + "or": "or_", + "pass": "pass_", + "raise": "raise_", + "return": "return_", + "try": "try_", + "while": "while_", + "with": "with_", + "yield": "yield_", } -# These can be used without any explicit conversion -autocast_types = { - "void": "void", - "bool": "bool", - "int": "int", - "double": "double", - "size_t": "size_t", - "std::string": "std::string", - "string": "string", - "char_p": "char_p", - "std::source_location": "std::source_location", - "source_location": "source_location", - "State": "RTLIL::State", - # trampoline types - "Pass": "RTLIL::Pass", - "Monitor": "RTLIL::Monitor", -} - -def strip_std_prefix(str_in): - # removesuffix is python 3.9+ - std_namespace = "std::" - if str_in.startswith(std_namespace): - return str_in[len(std_namespace):] - return str_in - - -# Ways to link between Python- and C++ Objects -class link_types(Enum): - global_list = 1 # Identical to pointer, kept for historical reasons - ref_copy = 2 # Copy - pointer = 3 # The Python Object contains a pointer to its C++ - # counterpart - derive = 4 # Identical to ref_copy, kept for historical reasons - - -class attr_types(Enum): - star = "*" - amp = "&" - ampamp = "&&" - default = "" - - -# For source-files -class Source: - name = "" - classes = [] - - def __init__(self, name, classes): - self.name = name - self.classes = classes - - -# Splits a list by the given delimiter, without splitting strings inside -# pointy-brackets (< and >) -def split_list(str_def, delim): - str_def = str_def.strip() - if len(str_def) == 0: - return [] - if str_def.count(delim) == 0: - return [str_def] - if str_def.count("<") == 0: - return str_def.split(delim) - if str_def.find("<") < str_def.find(" "): - closing = find_closing( - str_def[str_def.find("<") + 1 :], "<", ">" - ) + str_def.find("<") - comma = str_def[closing:].find(delim) - if comma == -1: - return [str_def] - comma = closing + comma - else: - comma = str_def.find(delim) - rest = split_list(str_def[comma + 1 :], delim) - ret = [str_def[:comma]] - if rest != None and len(rest) != 0: - ret.extend(rest) - return ret - - -# Represents a Type -class WType: - name = "" - cont = None - attr_type = attr_types.default - - def __init__(self, name="", cont=None, attr_type=attr_types.default): - self.name = name - self.cont = cont - self.attr_type = attr_type - - # Python type-string - def gen_text(self): - text = self.name - if self.name in enum_names: - text = enum_by_name(self.name).namespace + "::" + self.name - if self.cont != None: - return self.cont.gen_identifier() - return text - - # C++ type-string - def gen_text_cpp(self): - postfix = "" - if self.attr_type == attr_types.star: - postfix = " *" - elif self.attr_type == attr_types.amp: - postfix = " &" - elif self.attr_type == attr_types.ampamp: - postfix = " &&" - if self.name in classnames: - return class_by_name(self.name).namespace + "::" + self.name + postfix - if self.name in enum_names: - return enum_by_name(self.name).namespace + "::" + self.name + postfix - if self.name in autocast_types: - return autocast_types[self.name] + postfix - text = self.name - if self.cont != None: - text += "<" - for a in self.cont.args: - text += a.gen_text_cpp() + ", " - text = text[:-2] - text += ">" - return text - - @staticmethod - def from_string(str_def, containing_file, line_number): - str_def = str_def.strip() - if len(str_def) == 0: - return None - str_def = str_def.replace( - "RTLIL::SigSig", "std::pair" - ).replace("SigSig", "std::pair") - t = WType() - t.name = "" - t.cont = None - t.attr_type = attr_types.default - if str_def.find("<") != -1: # and str_def.find("<") < str_def.find(" "): - str_def = str_def.replace("const ", "") - - candidate = WContainer.from_string(str_def, containing_file, line_number) - if candidate == None: - return None - t.name = str_def[: str_def.find("<")] - - if t.name.count("*") + t.name.count("&") > 1: - return None - - if t.name.count("*") == 1 or str_def[0] == "*" or str_def[-1] == "*": - t.attr_type = attr_types.star - t.name = t.name.replace("*", "") - elif t.name.count("&&") == 1: - t.attr_type = attr_types.ampamp - t.name = t.name.replace("&&", "") - elif t.name.count("&") == 1 or str_def[0] == "&" or str_def[-1] == "&": - t.attr_type = attr_types.amp - t.name = t.name.replace("&", "") - - t.cont = candidate - if t.name not in known_containers: - return None - return t - - prefix = "" - - if str.startswith(str_def, "const "): - if "char_p" in str_def: - prefix = "const " - str_def = str_def[6:] - if str.startswith(str_def, "unsigned "): - prefix = "unsigned " + prefix - str_def = str_def[9:] - while str.startswith(str_def, "long "): - prefix = "long " + prefix - str_def = str_def[5:] - while str.startswith(str_def, "short "): - prefix = "short " + prefix - str_def = str_def[6:] - - str_def = str_def.split("::")[-1] - - if str_def.count("*") + str_def.count("&") >= 2: - return None - - if str_def.count("*") == 1: - t.attr_type = attr_types.star - str_def = str_def.replace("*", "") - elif str_def.count("&&") == 1: - t.attr_type = attr_types.ampamp - str_def = str_def.replace("&&", "") - elif str_def.count("&") == 1: - t.attr_type = attr_types.amp - str_def = str_def.replace("&", "") - - if ( - len(str_def) > 0 - and str_def.split("::")[-1] not in autocast_types - and str_def.split("::")[-1] not in classnames - and str_def.split("::")[-1] not in enum_names - ): - return None - - if str_def.count(" ") == 0: - t.name = (prefix + str_def).replace("char_p", "char *") - t.cont = None - return t - return None - - def gen_identifier(self): - if self.cont: - return self.cont.gen_identifier() - return self.name.title() - - def as_wclass(self) -> Optional["WClass"]: - return class_by_name(self.name) - - def __repr__(self): - return f"{self.__class__.__qualname__}(**{repr(self.__dict__)})" - - -# Associate the "Translators" with their c++ type -known_containers = { - "std::set", - "std::vector", - "std::map", - "std::pair", - "pool", - "idict", - "dict", - "RTLIL::ObjRange" -} - -# Represents a container-type -class WContainer: - name = "" - args = [] - - def from_string(str_def, containing_file, line_number): - if str_def == None or len(str_def) < 4: - return None - cont = WContainer() - cont.name = str_def[: str_def.find("<")] - str_def = str_def[str_def.find("<") + 1 : find_closing(str_def, "<", ">")] - cont.args = [] - for arg in split_list(str_def, ","): - candidate = WType.from_string(arg.strip(), containing_file, line_number) - if candidate == None: - return None - if candidate.name == "void": - return None - cont.args.append(candidate) - return cont - - # generate the c++ type string - def gen_type_cpp(self): - tpl_args = [] - for arg in self.args: - postfix = (arg.attr_type == attr_types.star) * " *" - if arg.name in autocast_types: - tpl_args.append(autocast_types[arg.name] + postfix) - elif arg.name in known_containers: - tpl_args.append(arg.cont.gen_type_cpp()) - else: - tpl_args.append(arg.as_wclass().fully_qualified_name() + postfix) - return f'{self.name}<{ ", ".join(tpl_args) }>' - - def gen_identifier(self): - container = strip_std_prefix(self.name).title() - - if container == "Dict": - assert len(self.args) == 2 - return f"{self.args[0].gen_identifier()}To{self.args[1].gen_identifier()}{container}" - - args = [] - for arg in self.args: - arg_name = arg.name.title() - if arg.cont: - arg_name = arg.cont.gen_identifier() - args.append(arg_name) - args.append(container) - result = "".join(args) - if result == "SigspecSigspecPair": - return "SigSig" - return result - - @autostring - def gen_boost_py(self, *, stream): - bind_fn = "py::bind_" + strip_std_prefix(self.name) - tpl_args = [self.gen_type_cpp()] - if bind_fn != "py::bind_vector": - # using custom bind function, can't use ::value so need more - # template arguments - for arg in self.args: - postfix = (arg.attr_type == attr_types.star) * " *" - if arg.name in autocast_types: - tpl_args.append(autocast_types[arg.name] + postfix) - elif arg.name in known_containers: - tpl_args.append(arg.cont.gen_type_cpp()) - else: - tpl_args.append(arg.as_wclass().fully_qualified_name() + postfix) - if bind_fn == "py::bind_set": - bind_fn = "py::bind_pool" - stream.write(f'\t\t{bind_fn}<{",".join(tpl_args)}>(m, "{self.gen_identifier()}");\n') - - def __repr__(self): - return f"{self.__class__.__qualname__}(**{repr(self.__dict__)})" - - -class Attribute: - wtype = None - varname = None - is_const = False - default_value = None - pos = None - pos_counter = 0 - - def __init__(self, wtype, varname, is_const=False, default_value=None): - self.wtype = wtype - self.varname = varname - self.is_const = is_const - self.default_value = None - self.container = None - - @staticmethod - def from_string(str_def, containing_file, line_number): - if len(str_def) < 3: - return None - orig = str_def - arg = Attribute(None, None) - prefix = "" - arg.wtype = None - arg.varname = None - arg.is_const = False - arg.default_value = None - arg.container = None - if str.startswith(str_def, "const "): - arg.is_const = True - str_def = str_def[6:] - if str.startswith(str_def, "unsigned "): - prefix = "unsigned " - str_def = str_def[9:] - while str.startswith(str_def, "long "): - prefix = "long " + prefix - str_def = str_def[5:] - while str.startswith(str_def, "short "): - prefix = "short " + prefix - str_def = str_def[6:] - - if str_def.find("<") != -1 and str_def.find("<") < str_def.find(" "): - closing = ( - find_closing(str_def[str_def.find("<") :], "<", ">") - + str_def.find("<") - + 1 - ) - arg.wtype = WType.from_string( - str_def[:closing].strip(), containing_file, line_number - ) - str_def = str_def[closing + 1 :] - else: - if str_def.count(" ") > 0: - arg.wtype = WType.from_string( - prefix + str_def[: str_def.find(" ")].strip(), - containing_file, - line_number, - ) - str_def = str_def[str_def.find(" ") + 1 :] - else: - arg.wtype = WType.from_string( - prefix + str_def.strip(), containing_file, line_number - ) - str_def = "" - arg.varname = "" - - if arg.wtype == None: - return None - if str_def.count("=") == 0: - arg.varname = str_def.strip() - if arg.varname.find(" ") > 0: - return None - else: - arg.varname = str_def[: str_def.find("=")].strip() - if arg.varname.find(" ") > 0: - return None - str_def = str_def[str_def.find("=") + 1 :].strip() - arg.default_value = str_def[arg.varname.find("=") + 1 :].strip() - if len(arg.varname) == 0: - arg.varname = None - return arg - if arg.varname[0] == "*": - arg.wtype.attr_type = attr_types.star - arg.varname = arg.varname[1:] - elif arg.varname[0] == "&": - if arg.wtype.attr_type != attr_types.default: - return None - if arg.varname[1] == "&": - arg.wtype.attr_type = attr_types.ampamp - arg.varname = arg.varname[2:] - else: - arg.wtype.attr_type = attr_types.amp - arg.varname = arg.varname[1:] - return arg - - # Generates the varname. If the attribute has no name in the header file, - # a name is generated - def gen_varname(self): - if self.varname != None: - return self.varname - if self.wtype.name == "void": - return "" - if self.pos == None: - self.pos = Attribute.pos_counter - Attribute.pos_counter = Attribute.pos_counter + 1 - return "gen_varname_" + str(self.pos) - - # Generates the test for the function headers with c++ types - def gen_listitem_cpp(self, include_varname=True): - postfix = self.gen_varname() * include_varname - prefix = "" - if self.is_const: - prefix = "const " - infix = "" - if self.wtype.attr_type == attr_types.star: - infix = "*" - elif self.wtype.attr_type == attr_types.amp: - infix = "&" - elif self.wtype.attr_type == attr_types.ampamp: - infix = "&&" - if self.wtype.name in known_containers: - return ( - prefix - + self.wtype.cont.gen_type_cpp() - + " " - + infix - + postfix - ) - if self.wtype.name in classnames: - return ( - prefix - + class_by_name(self.wtype.name).namespace - + "::" - + self.wtype.name - + " " - + infix - + postfix - ) - return prefix + self.wtype.name + " " + infix + postfix - - def gen_listitem_pyarg(self): - default = "" - if self.default_value is not None: - default = f" = {self.default_value}" - return f'py::arg("{self.varname}"){default}' - - # Generates the listitem withtout the varname, so the signature can be - # compared - def gen_listitem_hash(self): - prefix = "" - if self.is_const: - prefix = "const " - if self.wtype.name in classnames: - return prefix + self.wtype.name + "* " - if self.wtype.name in known_containers: - return self.wtype.cont.gen_identifier() - return prefix + self.wtype.name - - -class WClass: - name = None - namespace = None - link_type = None - base_class = None - id_ = None - string_id = None - hash_id = None - needs_clone = False - found_funs = [] - found_vars = [] - found_constrs = [] - - def __init__( - self, - name, - link_type, - *, - id_=None, - string_id=None, - hash_id=None, - needs_clone=False, - ): - self.name = name - self.namespace = None - self.base_class = None - self.link_type = link_type - self.id_ = id_ - self.string_id = string_id - self.hash_id = hash_id - self.needs_clone = needs_clone - self.found_funs = [] - self.found_vars = [] - self.found_constrs = [] - - @autostring - def gen_boost_py(self, *, stream): - name_qualified = f"{self.namespace}::{self.name}" - tpl_args = [name_qualified] - if self.link_type in [link_types.pointer, link_types.global_list]: - tpl_args.append(f"std::unique_ptr<{name_qualified}, py::nodelete>") - stream.write(f'\t\tpy::class_<{", ".join(tpl_args)}>(m, "{self.name}")\n') - for con in self.found_constrs: - # HACK: skip move constructors - if "&&" in con.orig_text: - continue - con.gen_boost_py(stream=stream) - for fun in sorted(self.found_funs, key=lambda f: (f.is_operator, f.name)): - fun.gen_boost_py(stream=stream) - if self.string_id: - stream.write( - f'\t\t\t.def("__str__", [](const {name_qualified} &self){{ return self.{self.string_id}; }})\n' - ) - if self.hash_id: - hash_member = f".{self.hash_id}" if self.hash_id != "" else "" - stream.write( - f'\t\t\t.def("__hash__", [](const {name_qualified} &self){{ return run_hash(self{hash_member}); }})\n' - ) - for var in self.found_vars: - var.gen_boost_py(stream=stream) - stream.write("\t\t;\n") - - def fully_qualified_name(self) -> str: - return f"{self.namespace}::{self.name}" - - def __repr__(self): - return f"{self.__class__.__qualname__}({repr(self.__dict__)})" - - -# CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE - -sources = [ - Source( - "kernel/celltypes", - [ - WClass("CellType", link_types.ref_copy, hash_id="type", needs_clone=True), - WClass("CellTypes", link_types.ref_copy, needs_clone=True), - ], - ), - Source( - "kernel/consteval", [WClass("ConstEval", link_types.ref_copy, needs_clone=True)] - ), - Source("kernel/log", []), - Source( - "kernel/register", - [ - # WClass("Pass", link_types.derive, needs_clone=True), # Manual mapping because of virtual method - ], - ), - Source( - "kernel/rtlil", - [ - WClass("IdString", link_types.ref_copy, string_id="str()", hash_id="str()"), - WClass("Const", link_types.ref_copy, string_id="as_string()"), - WClass("AttrObject", link_types.ref_copy), - WClass("NamedObject", link_types.ref_copy), - WClass("Selection", link_types.ref_copy), - #WClass("Monitor", link_types.derive), # Moved to tpl for virtual methods - WClass("CaseRule", link_types.ref_copy, needs_clone=True), - WClass("SwitchRule", link_types.ref_copy, needs_clone=True), - WClass("SyncRule", link_types.ref_copy, needs_clone=True), - WClass( - "Process", link_types.pointer, string_id="name.c_str()", hash_id="name" - ), - WClass("SigChunk", link_types.ref_copy), - WClass("SigBit", link_types.ref_copy, hash_id=""), - WClass("SigSpec", link_types.ref_copy, hash_id=""), - WClass( - "Cell", - link_types.global_list, - id_=Attribute(WType("unsigned int"), "hashidx_"), - string_id="name.c_str()", - hash_id="", - ), - WClass( - "Wire", - link_types.global_list, - id_=Attribute(WType("unsigned int"), "hashidx_"), - string_id="name.c_str()", - hash_id="", - ), - WClass( - "Memory", - link_types.global_list, - id_=Attribute(WType("unsigned int"), "hashidx_"), - string_id="name.c_str()", - hash_id="", - ), - WClass( - "Module", - link_types.global_list, - id_=Attribute(WType("unsigned int"), "hashidx_"), - string_id="name.c_str()", - hash_id="", - ), - WClass( - "Design", - link_types.ref_copy, - id_=Attribute(WType("unsigned int"), "hashidx_"), - string_id="hashidx_", - hash_id="", - ), - ], - ), - # Source("kernel/satgen",[ - # ] - # ), - # Source("libs/ezsat/ezsat",[ - # ] - # ), - # Source("libs/ezsat/ezminisat",[ - # ] - # ), - Source( - "kernel/sigtools", [WClass("SigMap", link_types.ref_copy, needs_clone=True)] - ), - Source("kernel/yosys", []), - Source("kernel/cost", []), -] - -blacklist_methods = [ - "YOSYS_NAMESPACE::Pass::run_register", - "YOSYS_NAMESPACE::Module::Pow", - "YOSYS_NAMESPACE::RTLIL::Design::selected_whole_modules", - "YOSYS_NAMESPACE::RTLIL::AttrObject::get_blackbox_attribute" -] - -enum_names = ["State", "SyncType", "ConstFlags"] - -enums = [] # Do not edit -glbls = [] - -unowned_functions = [] - -classnames = [] -for source in sources: - for wclass in source.classes: - classnames.append(wclass.name) - - -def class_by_name(name): - for source in sources: - for wclass in source.classes: - if wclass.name == name: - return wclass - return None - - -def enum_by_name(name): - for e in enums: - if e.name == name: - return e - return None - - -def find_closing(text, open_tok, close_tok): - if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok): - return text.find(close_tok) - return ( - text.find(close_tok) - + find_closing(text[text.find(close_tok) + 1 :], open_tok, close_tok) - + 1 - ) - - -def unpretty_string(s): - s = s.strip() - while s.find(" ") != -1: - s = s.replace(" ", " ") - while s.find("\t") != -1: - s = s.replace("\t", " ") - s = s.replace(" (", "(") - return s - - -class WEnum: - name = None - namespace = None - values = [] - - def from_string(str_def, namespace, line_number): - str_def = str_def.strip() - if not str.startswith(str_def, "enum "): - return None - if str_def.count(";") != 1: - return None - str_def = str_def[5:] - enum = WEnum() - split = str_def.split(":") - if len(split) != 2: - return None - enum.name = split[0].strip() - if enum.name not in enum_names: - return None - str_def = split[1] - if str_def.count("{") != str_def.count("}") != 1: - return None - if ( - len(str_def) < str_def.find("}") + 2 - or str_def[str_def.find("}") + 1] != ";" - ): - return None - str_def = str_def.split("{")[-1].split("}")[0] - enum.values = [] - for val in str_def.split(","): - enum.values.append(val.strip().split("=")[0].strip()) - enum.namespace = namespace - return enum - - @autostring - def gen_boost_py(self, *, stream): - stream.write( - f'\t\tpy::native_enum<{self.namespace}::{self.name}>(m, "{self.name}", "enum.Enum")\n' - ) - for value in self.values: - stream.write(f'\t\t\t.value("{value}", {self.namespace}::{value})\n') - stream.write("\t\t\t.finalize();\n") - - def __str__(self): - ret = "Enum " + self.namespace + "::" + self.name + "(\n" - for val in self.values: - ret = ret + "\t" + val + "\n" - return ret + ")" - - -class WConstructor: - orig_text = None - args = [] - containing_file = None - member_of = None - duplicate = False - protected = False - - def __init__(self, containing_file, class_): - self.orig_text = "Auto generated default constructor" - self.args = [] - self.containing_file = containing_file - self.member_of = class_ - self.protected = False - - def from_string(str_def, containing_file, class_, line_number, protected=False): - if class_ == None: - return None - if str_def.count("delete;") > 0: - return None - con = WConstructor(containing_file, class_) - con.orig_text = str_def - con.args = [] - con.duplicate = False - con.protected = protected - if str.startswith(str_def, "inline "): - str_def = str_def[7:] - if not str.startswith(str_def, class_.name + "("): - return None - str_def = str_def[len(class_.name) + 1 :] - found = find_closing(str_def, "(", ")") - if found == -1: - return None - str_def = str_def[0:found].strip() - if len(str_def) == 0: - return con - args = split_list(str_def, ",") - for i, arg in enumerate(args): - parsed = Attribute.from_string(arg.strip(), containing_file, line_number) - if parsed == None: - return None - # Only allow std::source_location as defaulted last argument, and - # don't append so it takes default value - if parsed.wtype.name in ["std::source_location", "source_location"]: - if parsed.default_value is None or i != len(args) - 1: - debug( - "std::source_location not defaulted last arg of " - + class_.name - + " is unsupported", - 2, - ) - return None - continue - con.args.append(parsed) - return con - - def gen_decl_hash_py(self): - text = self.member_of.name + "(" - for arg in self.args: - text += arg.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");" - return text - - def overload_params(self): - return ", ".join([a.gen_listitem_cpp(include_varname=False) for a in self.args]) - - @autostring - def gen_boost_py(self, *, stream): - if self.duplicate or self.protected: - return - stream.write(f"\t\t\t.def(py::init<{self.overload_params()}>())\n") - - -class WFunction: - orig_text = None - is_static = False - is_inline = False - is_virtual = False - is_const = False - ret_attr_type = attr_types.default - is_operator = False - ret_type = None - name = None - alias = None - args = [] - containing_file = None - member_of = None - duplicate = False - namespace = "" - - def from_string(str_def, containing_file, class_, line_number, namespace): - if str_def.count("delete;") > 0: - return None - func = WFunction() - func.is_static = False - func.is_inline = False - func.is_virtual = False - func.is_const = False - func.ret_attr_type = attr_types.default - func.is_operator = False - func.member_of = None - func.orig_text = str_def - func.args = [] - func.containing_file = containing_file - func.member_of = class_ - func.duplicate = False - func.namespace = namespace - str_def = str_def.replace("operator ", "operator") - - # remove attributes from the start - if str.startswith(str_def, "[[") and "]]" in str_def: - str_def = str_def[str_def.find("]]") + 2 :] - - if str.startswith(str_def, "static "): - func.is_static = True - str_def = str_def[7:] - else: - func.is_static = False - if str.startswith(str_def, "inline "): - func.is_inline = True - str_def = str_def[7:] - else: - func.is_inline = False - if str.startswith(str_def, "virtual "): - func.is_virtual = True - str_def = str_def[8:] - else: - func.is_virtual = False - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short", "const"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - func.ret_type = WType.from_string( - prefix + parts[0], containing_file, line_number - ) - - if func.ret_type == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - found = str_def.find("(") - if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")): - return None - func.name = str_def[:found] - str_def = str_def[found:] - if func.name.find("operator") != -1 and str.startswith(str_def, "()("): - func.name += "()" - str_def = str_def[2:] - str_def = str_def[1:] - if func.name.find("operator") != -1: - func.is_operator = True - if func.name.find("*") == 0: - func.name = func.name.replace("*", "") - func.ret_type.attr_type = attr_types.star - if func.name.find("&&") == 0: - func.name = func.name.replace("&&", "") - func.ret_type.attr_type = attr_types.ampamp - if func.name.find("&") == 0: - func.name = func.name.replace("&", "") - func.ret_type.attr_type = attr_types.amp - - found = find_closing(str_def, "(", ")") - if found == -1: - return None - - post_qualifiers = str_def[found + 1 :].lstrip() - if post_qualifiers.startswith("const"): - func.is_const = True - - str_def = str_def[0:found] - if func.name in blacklist_methods: - return None - if func.namespace != None and func.namespace != "": - if (func.namespace + "::" + func.name) in blacklist_methods: - return None - if func.member_of != None: - if ( - func.namespace + "::" + func.member_of.name + "::" + func.name - ) in blacklist_methods: - return None - if ( - func.is_operator - and func.name.replace(" ", "").replace("operator", "").split("::")[-1] - not in wrappable_operators - ): - return None - - testname = func.name - if func.is_operator: - testname = testname[: testname.find("operator")] - if ( - testname.count(")") != 0 - or testname.count("(") != 0 - or testname.count("~") != 0 - or testname.count(";") != 0 - or testname.count(">") != 0 - or testname.count("<") != 0 - or testname.count("throw") != 0 - ): - return None - - func.alias = func.name - if func.name in keyword_aliases: - func.alias = keyword_aliases[func.name] - str_def = str_def[:found].strip() - if len(str_def) == 0: - return func - args = split_list(str_def, ",") - for i, arg in enumerate(args): - if arg.strip() == "...": - continue - parsed = Attribute.from_string(arg.strip(), containing_file, line_number) - if parsed == None: - return None - # Only allow std::source_location as defaulted last argument, and - # don't append so it takes default value - if parsed.wtype.name in ["std::source_location", "source_location"]: - if parsed.default_value is None or i != len(args) - 1: - debug( - "std::source_location not defaulted last arg of " - + func.name - + " is unsupported", - 2, - ) - return None - continue - func.args.append(parsed) - # handle (void) parameter declarations - if len(func.args) == 1 and func.args[0].wtype.name == "void": - func.args = [] - return func - - @property - def mangled_name(self): - mangled_typename = ( - lambda code: code.replace("::", "_") - .replace("<", "_") - .replace(">", "_") - .replace(" ", "") - .replace("*", "") - .replace(",", "") - ) - - return self.name + "".join( - f"__{mangled_typename(arg.wtype.gen_text_cpp())}" for arg in self.args - ) - - def gen_alias(self): - self.alias = self.mangled_name - - def gen_post_qualifiers(self, derived=False): - if ( - self.member_of != None - and self.member_of.link_type == link_types.derive - and self.is_virtual - and derived - ): - # we drop the qualifiers when deriving callbacks to be implemented in Python - return "" - return " const" if self.is_const else "" - - def gen_decl_hash_py(self): - text = self.ret_type.gen_text() + " " + self.alias + "(" - for arg in self.args: - text += arg.gen_listitem_hash() + ", " - if len(self.args) > 0: - text = text[:-2] - text += ");" - return text - - def overload_params(self): - return ", ".join([a.gen_listitem_cpp(False) for a in self.args]) - - def py_args(self): - return ", ".join([a.gen_listitem_pyarg() for a in self.args]) - - def wrapper_params(self): - return ", ".join([a.gen_listitem_cpp() for a in self.args]) - - def wrapper_args(self): - varnames = [] - for a in self.args: - if a.varname == "format": - # HACK: handle format strings (by ignoring the format part) - varnames.extend(['"%s"', "format"]) - else: - varnames.append(a.varname) - return ", ".join(varnames) - - @autostring - def gen_boost_py(self, *, stream): - if self.duplicate: - return - - fully_qualify = False - if self.member_of is not None and ( - (self.member_of.name == "IdString" and self.name == "in") - or (self.member_of.name == "Design" and self.name == "selection") - ): - fully_qualify = True - - # HACK: skip methods with inline-related nonsense - if self.alias in [ - "log_id", - "log_dump_val_worker", - "log_dump_args_worker", - "GetSize", - ]: - return - - prefix = "\t\tm" - ns = self.namespace - if self.member_of: - prefix = "\t\t\t" - ns = self.member_of.fully_qualified_name() - - stream.write(f"{prefix}.def") - if self.member_of and self.is_static: - stream.write("_static") - stream.write("(") - - if self.is_operator: - stream.write(f"py::self {self.name[len('operator'):]} py::self") - else: - stream.write(f'"{self.alias}", ') - # HACK: wrap variadics by only allowing a string - if "..." in self.orig_text: - stream.write( - f"[]({self.wrapper_params()}) {{ {self.namespace}::{self.name}({self.wrapper_args()}); }}" - ) - else: - - # HACK: Some of these needs special handling, i.e., a FULL - # overload disambiguation. Not sure why. Something to do with - # inlines and overloads. - # - # In theory, this disambiguation should work for everything but - # WType doesn't properly retain const return types yet. - if fully_qualify: - stream.write( - f"static_cast < {self.ret_type.gen_text_cpp()} ({ns}::*)({self.overload_params()}) {self.gen_post_qualifiers()} >(" - ) - elif not len(self.args) == 0: - stream.write(f"py::overload_cast<{self.overload_params()}>(") - stream.write(f"&{ns}::{self.name}") - if fully_qualify: - stream.write(")") - elif not len(self.args) == 0: - if self.is_const: - stream.write(f", py::const_") - stream.write(")") - py_args = self.py_args() - if len(py_args): - stream.write(", ") - stream.write(py_args) - stream.write(")\n" if self.member_of is not None else ");\n") - - def __repr__(self): - return f"{self.__class__.__qualname__}({repr(self.__dict__)})" - - -class WMember: - opaque_containers: ClassVar[dict] = dict() - orig_text = None - wtype = attr_types.default - name = None - containing_file = None - member_of = None - namespace = "" - is_const = False - - def from_string(str_def, containing_file, class_, line_number, namespace): - member = WMember() - member.orig_text = str_def - member.wtype = None - member.name = "" - member.containing_file = containing_file - member.member_of = class_ - member.namespace = namespace - member.is_const = False - - if str.startswith(str_def, "const "): - member.is_const = True - str_def = str_def[6:] - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - member.wtype = WType.from_string( - prefix + parts[0], containing_file, line_number - ) - - if member.wtype == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - if ( - str_def.find("(") != -1 - or str_def.find(")") != -1 - or str_def.find("{") != -1 - or str_def.find("}") != -1 - ): - return None - - found = str_def.find(";") - if found == -1: - return None - - found_eq = str_def.find("=") - if found_eq != -1: - found = found_eq - - member.name = str_def[:found] - str_def = str_def[found + 1 :] - if member.name.find("*") == 0: - member.name = member.name.replace("*", "") - member.wtype.attr_type = attr_types.star - if member.name.find("&&") == 0: - member.name = member.name.replace("&&", "") - member.wtype.attr_type = attr_types.ampamp - if member.name.find("&") == 0: - member.name = member.name.replace("&", "") - member.wtype.attr_type = attr_types.amp - - if len(str_def.strip()) != 0: - return None - - if len(member.name.split(",")) > 1: - member_list = [] - for name in member.name.split(","): - name = name.strip() - member_list.append(WMember()) - member_list[-1].orig_text = member.orig_text - member_list[-1].wtype = member.wtype - member_list[-1].name = name - member_list[-1].containing_file = member.containing_file - member_list[-1].member_of = member.member_of - member_list[-1].namespace = member.namespace - member_list[-1].is_const = member.is_const - return member_list - - if member.wtype.cont: - WMember.opaque_containers[member.wtype.gen_identifier()] = member.wtype - - return member - - @autostring - def gen_boost_py(self, *, stream): - if False and self.wtype.attr_type == attr_types.default: - property_type = self.wtype.gen_text_cpp() - stream.write(f'\t\t\t.def_property("{self.name}",\n') - stream.write(f'\t\t\t\t[]({self.member_of.fully_qualified_name()} &o) -> {property_type}& {{ return o.{self.name}; }},\n') - stream.write(f'\t\t\t\t[]({self.member_of.fully_qualified_name()} &o, {property_type} const &p) {{ o.{self.name} = p; }},\n') - stream.write(f'\t\t\t\tpy::return_value_policy::reference_internal\n') - stream.write(f'\t\t\t)\n') - else: - meth = "def_readonly" if self.is_const else "def_readwrite" - stream.write( - f'\t\t\t.{meth}("{self.name}", &{self.member_of.fully_qualified_name()}::{self.name})\n' - ) - - def __repr__(self): - return f"{self.__class__.__qualname__}({repr(self.__dict__)})" - - -class WGlobal: - orig_text = None - wtype = attr_types.default - name = None - containing_file = None - namespace = "" - is_const = False - - def from_string(str_def, containing_file, line_number, namespace): - glbl = WGlobal() - glbl.orig_text = str_def - glbl.wtype = None - glbl.name = "" - glbl.containing_file = containing_file - glbl.namespace = namespace - glbl.is_const = False - - if not str.startswith(str_def, "extern"): - return None - str_def = str_def[7:] - - if str.startswith(str_def, "const "): - glbl.is_const = True - str_def = str_def[6:] - - if str_def.count(" ") == 0: - return None - - parts = split_list(str_def.strip(), " ") - - prefix = "" - i = 0 - for part in parts: - if part in ["unsigned", "long", "short"]: - prefix += part + " " - i += 1 - else: - break - parts = parts[i:] - - if len(parts) <= 1: - return None - - glbl.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) - - if glbl.wtype == None: - return None - - str_def = parts[1] - for part in parts[2:]: - str_def = str_def + " " + part - - if ( - str_def.find("(") != -1 - or str_def.find(")") != -1 - or str_def.find("{") != -1 - or str_def.find("}") != -1 - ): - return None - - found = str_def.find(";") - if found == -1: - return None - - found_eq = str_def.find("=") - if found_eq != -1: - found = found_eq - - glbl.name = str_def[:found] - str_def = str_def[found + 1 :] - if glbl.name.find("*") == 0: - glbl.name = glbl.name.replace("*", "") - glbl.wtype.attr_type = attr_types.star - if glbl.name.find("&&") == 0: - glbl.name = glbl.name.replace("&&", "") - glbl.wtype.attr_type = attr_types.ampamp - if glbl.name.find("&") == 0: - glbl.name = glbl.name.replace("&", "") - glbl.wtype.attr_type = attr_types.amp - - if len(str_def.strip()) != 0: - return None - - if len(glbl.name.split(",")) > 1: - glbl_list = [] - for name in glbl.name.split(","): - name = name.strip() - glbl_list.append(WGlobal()) - glbl_list[-1].orig_text = glbl.orig_text - glbl_list[-1].wtype = glbl.wtype - glbl_list[-1].name = name - glbl_list[-1].containing_file = glbl.containing_file - glbl_list[-1].namespace = glbl.namespace - glbl_list[-1].is_const = glbl.is_const - return glbl_list - - return glbl - - @autostring - def gen_boost_py(self, *, stream): - args = [ - f'"{self.name}"', - ] - meth = "def_readonly_static" - if not self.is_const: - meth = "def_readwrite_static" - args.append(f"&{self.namespace}::{self.name}") - stream.write(f'\t\t\t.{meth}({", ".join(args)})\n') - - -def concat_namespace(tuple_list): - if len(tuple_list) == 0: - return "" - ret = "" - for namespace in tuple_list: - ret += "::" + namespace[0] - return ret[2:] - - -def calc_ident(text): - if len(text) == 0 or text[0] != " ": - return 0 - return calc_ident(text[1:]) + 1 - - -def assure_length(text, length, left=False): - if len(text) > length: - return text[:length] - if left: - return text + " " * (length - len(text)) - return " " * (length - len(text)) + text - - -def nesting_delta(s): - return s.count("{") - s.count("}") - - -def parse_header(source): - debug("Parsing " + source.name + ".pyh", 1) - source_file = open(source.name + ".pyh", "r") - - source_text = [] - in_line = source_file.readline() - - namespaces = [] - - while in_line: - if len(in_line) > 1: - source_text.append( - in_line.replace("char *", "char_p ").replace("char* ", "char_p ") - ) - in_line = source_file.readline() - - i = 0 - - namespaces = [] - classes = [] - private_segment = False - - while i < len(source_text): - line = ( - source_text[i] - .replace( - "YOSYS_NAMESPACE_BEGIN", - " namespace YOSYS_NAMESPACE{", - ) - .replace("YOSYS_NAMESPACE_END", " }") - ) - ugly_line = unpretty_string(line) - debug(f"READ:>> {line}", 2) - - # for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line - if "union {" in line: - j = i + 1 - while j < len(source_text): - union_line = source_text[j] - if "};" in union_line: - source_text[j] = "\n" - break - j += 1 - if j != len(source_text): - i += 1 - continue - - if str.startswith( - ugly_line, "namespace " - ): # and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: - namespace_name = ugly_line[10:].replace("{", "").strip() - namespaces.append((namespace_name, ugly_line.count("{"))) - debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----", 3) - i += 1 - continue - - if len(namespaces) != 0: - namespaces[-1] = ( - namespaces[-1][0], - namespaces[-1][1] + nesting_delta(ugly_line), - ) - if namespaces[-1][1] == 0: - debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----", 3) - namespaces.pop() - i += 1 - continue - - if ( - str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class") - ) and ugly_line.count(";") == 0: - # Opening a record declaration which isn't a forward declaration - struct_name = ugly_line.split(" ")[1].split("::")[-1] - impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1] - complete_namespace = concat_namespace(namespaces) - for namespace in impl_namespaces: - complete_namespace += "::" + namespace - debug("\tFound " + struct_name + " in " + complete_namespace, 2) - - base_class_name = None - if len(ugly_line.split(" : ")) > 1: # class is derived - deriv_str = ugly_line.split(" : ")[1] - if len(deriv_str.split("::")) > 1: # namespace of base class is given - base_class_name = deriv_str.split("::", 1)[1] - else: - base_class_name = deriv_str.split(" ")[0] - debug("\t " + struct_name + " is derived from " + base_class_name, 2) - base_class = class_by_name(base_class_name) - - c = (class_by_name(struct_name), ugly_line.count("{")) # calc_ident(line)) - debug(f"switch to {struct_name} in namespace {namespaces}", 2) - if struct_name in classnames: - c[0].namespace = complete_namespace - c[0].base_class = base_class - classes.append(c) - i += 1 - continue - - if len(classes): - c = (classes[-1][0], classes[-1][1] + nesting_delta(ugly_line)) - classes[-1] = c - if c[1] == 0: - if c[0] == None: - debug("\tExiting unknown class", 3) - else: - debug("\tExiting class " + c[0].name, 3) - classes.pop() - private_segment = False - i += 1 - continue - - class_ = classes[-1] if classes else None - - if class_ != None and ( - line.find("private:") != -1 or line.find("protected:") != -1 - ): - private_segment = True - i += 1 - continue - if class_ != None and line.find("public:") != -1: - private_segment = False - i += 1 - continue - - candidate = None - - if private_segment and class_ != None and class_[0] != None: - candidate = WConstructor.from_string( - ugly_line, source.name, class_[0], i, True - ) - if candidate != None: - debug( - '\t\tFound constructor of class "' - + class_[0].name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - class_[0].found_constrs.append(candidate) - i += 1 - continue - - if not private_segment and (class_ == None or class_[0] != None): - if class_ != None: - candidate = WFunction.from_string( - ugly_line, source.name, class_[0], i, concat_namespace(namespaces) - ) - else: - candidate = WFunction.from_string( - ugly_line, source.name, None, i, concat_namespace(namespaces) - ) - if candidate != None and candidate.name.find("::") == -1: - if class_ == None: - debug( - '\tFound unowned function "' - + candidate.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - unowned_functions.append(candidate) - else: - debug( - '\t\tFound function "' - + candidate.name - + '" of class "' - + class_[0].name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - class_[0].found_funs.append(candidate) - else: - candidate = WEnum.from_string( - ugly_line, concat_namespace(namespaces), i - ) - if candidate != None: - enums.append(candidate) - debug( - '\tFound enum "' - + candidate.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - elif class_ != None and class_[1] == 1: - candidate = WConstructor.from_string( - ugly_line, source.name, class_[0], i - ) - if candidate != None: - debug( - '\t\tFound constructor of class "' - + class_[0].name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - class_[0].found_constrs.append(candidate) - else: - candidate = WMember.from_string( - ugly_line, - source.name, - class_[0], - i, - concat_namespace(namespaces), - ) - if candidate != None: - if type(candidate) == list: - for c in candidate: - debug( - '\t\tFound member "' - + c.name - + '" of class "' - + class_[0].name - + '" of type "' - + c.wtype.name - + '"', - 2, - ) - class_[0].found_vars.extend(candidate) - else: - debug( - '\t\tFound member "' - + candidate.name - + '" of class "' - + class_[0].name - + '" of type "' - + candidate.wtype.name - + '"', - 2, - ) - class_[0].found_vars.append(candidate) - if candidate == None and class_ == None: - candidate = WGlobal.from_string( - ugly_line, source.name, i, concat_namespace(namespaces) - ) - if candidate != None: - if type(candidate) == list: - for c in candidate: - glbls.append(c) - debug( - '\tFound global "' - + c.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - else: - glbls.append(candidate) - debug( - '\tFound global "' - + candidate.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - - j = i - line = unpretty_string(line) - while ( - candidate == None - and j + 1 < len(source_text) - and line.count(";") <= 1 - and line.count("(") >= line.count(")") - ): - j += 1 - line = line + "\n" + unpretty_string(source_text[j]) - if class_ != None: - candidate = WFunction.from_string( - ugly_line, - source.name, - class_[0], - i, - concat_namespace(namespaces), - ) - else: - candidate = WFunction.from_string( - ugly_line, source.name, None, i, concat_namespace(namespaces) - ) - if candidate != None and candidate.name.find("::") == -1: - if class_ == None: - debug( - '\tFound unowned function "' - + candidate.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - unowned_functions.append(candidate) - else: - debug( - '\t\tFound function "' - + candidate.name - + '" of class "' - + class_[0].name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - class_[0].found_funs.append(candidate) - continue - candidate = WEnum.from_string(line, concat_namespace(namespaces), i) - if candidate != None: - enums.append(candidate) - debug( - '\tFound enum "' - + candidate.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - continue - if class_ != None: - candidate = WConstructor.from_string( - line, source.name, class_[0], i - ) - if candidate != None: - debug( - '\t\tFound constructor of class "' - + class_[0].name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - class_[0].found_constrs.append(candidate) - continue - if class_ == None: - candidate = WGlobal.from_string( - line, source.name, i, concat_namespace(namespaces) - ) - if candidate != None: - if type(candidate) == list: - for c in candidate: - glbls.append(c) - debug( - '\tFound global "' - + c.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - else: - glbls.append(candidate) - debug( - '\tFound global "' - + candidate.name - + '" in namespace ' - + concat_namespace(namespaces), - 2, - ) - continue - if candidate != None: - while i < j: - i += 1 - line = ( - source_text[i] - .replace( - "YOSYS_NAMESPACE_BEGIN", - " namespace YOSYS_NAMESPACE{", - ) - .replace("YOSYS_NAMESPACE_END", " }") - ) - ugly_line = unpretty_string(line) - if len(namespaces) != 0: - namespaces[-1] = ( - namespaces[-1][0], - namespaces[-1][1] + nesting_delta(ugly_line), - ) - if namespaces[-1][1] == 0: - debug( - "-----END NAMESPACE " - + concat_namespace(namespaces) - + "-----", - 3, - ) - namespaces.pop() - if len(classes): - c = (classes[-1][0], classes[-1][1] + nesting_delta(ugly_line)) - classes[-1] = c - if c[1] == 0: - if c[0] == None: - debug("\tExiting unknown class", 3) - else: - debug("\tExiting class " + c[0].name, 3) - classes.pop() - private_segment = False - i += 1 - else: - i += 1 - - -def debug(message, level): - if level <= debug.debug_level: - print(message) - - -def expand_functions(): - global unowned_functions - new_funs = [] - for fun in unowned_functions: - new_funs.append(fun) - unowned_functions = new_funs - for source in sources: - for class_ in source.classes: - new_funs = [] - for fun in class_.found_funs: - new_funs.append(fun) - class_.found_funs = new_funs - - -def inherit_members(): - for source in sources: - for class_ in source.classes: - if class_.base_class: - base_funs = copy.deepcopy(class_.base_class.found_funs) - for fun in base_funs: - fun.member_of = class_ - fun.namespace = class_.namespace - base_vars = copy.deepcopy(class_.base_class.found_vars) - for var in base_vars: - var.member_of = class_ - var.namespace = class_.namespace - class_.found_funs.extend(base_funs) - class_.found_vars.extend(base_vars) - - -def clean_duplicates(): - for source in sources: - for class_ in source.classes: - known_decls = {} - for fun in class_.found_funs: - if fun.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + fun.gen_decl_hash_py(), 3) - - other = known_decls[fun.gen_decl_hash_py()] - if fun.mangled_name == other.mangled_name: - fun.duplicate = True - debug('Disabled "' + fun.gen_decl_hash_py() + '"', 3) - continue - - other.gen_alias() - fun.gen_alias() - else: - known_decls[fun.gen_decl_hash_py()] = fun - known_decls = [] - for con in class_.found_constrs: - if con.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + con.gen_decl_hash_py(), 3) - con.duplicate = True - else: - known_decls.append(con.gen_decl_hash_py()) - known_decls = [] - for fun in unowned_functions: - if fun.gen_decl_hash_py() in known_decls: - debug("Multiple declarations of " + fun.gen_decl_hash_py(), 3) - fun.duplicate = True - else: - known_decls.append(fun.gen_decl_hash_py()) - - -def gen_wrappers(filename, debug_level_=0): - filename = Path(filename) - - debug.debug_level = debug_level_ - for source in sources: - parse_header(source) - - expand_functions() - inherit_members() - clean_duplicates() - - import shutil - import math - - col = shutil.get_terminal_size((80, 20)).columns - debug("-" * col, 1) - debug( - "-" * math.floor((col - 7) / 2) + "SUMMARY" + "-" * math.ceil((col - 7) / 2), 1 - ) - debug("-" * col, 1) - for source in sources: - for class_ in source.classes: - debug( - "Class " - + assure_length(class_.name, len(max(classnames, key=len)), True) - + " contains " - + assure_length(str(len(class_.found_vars)), 3, False) - + " member variables, " - + assure_length(str(len(class_.found_funs)), 3, False) - + " methods and " - + assure_length(str(len(class_.found_constrs)), 2, False) - + " constructors", - 1, - ) - if len(class_.found_constrs) == 0: - class_.found_constrs.append(WConstructor(source.name, class_)) - debug(str(len(unowned_functions)) + " functions are unowned", 1) - debug(str(len(unowned_functions)) + " global variables", 1) - for enum in enums: - debug( - "Enum " - + assure_length(enum.name, len(max(enum_names, key=len)), True) - + " contains " - + assure_length(str(len(enum.values)), 2, False) - + " values", - 1, - ) - debug("-" * col, 1) - - tpl = __file_dir__ / "wrappers_tpl.cc" - with open(tpl, encoding="utf8") as f, open( - filename, "w", encoding="utf8" - ) as wrapper_file: - do_line_directive = True - for i, line in enumerate(f): - if do_line_directive: - wrapper_file.write(f'#line {i + 1} "{tpl}"\n') - do_line_directive = False - if "" in line: - for source in sources: - wrapper_file.write(f'#include "{source.name}.h"\n') - do_line_directive = True - elif "" in line: - wrapper_file.write("// Opaque Container Declaration\n") - for i, (container_identifier, container) in enumerate(WMember.opaque_containers.items()): - wrapper_file.write(f"using {container_identifier} = {container.gen_text_cpp()};\n") - wrapper_file.write(f'PYBIND11_MAKE_OPAQUE({container_identifier})\n') - wrapper_file.write("\n") - do_line_directive = True - elif "" in line: - do_line_directive = True - elif "" in line: - wrapper_file.write("\t\t// Opaque Container Binding\n") - for container in WMember.opaque_containers.values(): - container.cont.gen_boost_py(stream=wrapper_file) - wrapper_file.write("\n") - - wrapper_file.write("\t\t// Enums\n") - for enum in enums: - enum.gen_boost_py(stream=wrapper_file) - wrapper_file.write("\n") - - wrapper_file.write("\t\t// Classes\n") - for source in sources: - for wclass in source.classes: - wclass.gen_boost_py(stream=wrapper_file) - wrapper_file.write("\n") - - wrapper_file.write("\t\t// Global Functions\n") - for fun in sorted(unowned_functions, key=lambda x: x.alias): - fun.gen_boost_py(stream=wrapper_file) - wrapper_file.write("\n") - - wrapper_file.write("\t\t// Global Variables\n") - wrapper_file.write('\t\tpy::class_(m, "Yosys")\n') - for glbl in sorted(glbls, key=lambda x: (not x.is_const, x.name)): - glbl.gen_boost_py(stream=wrapper_file) - wrapper_file.write("\t\t\t;\n") - do_line_directive = True - else: - wrapper_file.write(line) - def print_includes(): - for source in sources: - print(source.name + ".pyh") + for header in pyosys_headers: + print(header.name) if __name__ == "__main__": - ap = argparse.ArgumentParser() - ap.add_argument("--print-includes", action="store_true") - ap.add_argument("--debug", default=0, type=int) - ap.add_argument("output", nargs="?") - ns = ap.parse_args() - if ns.print_includes: - print_includes() - exit(0) - gen_wrappers(ns.output, ns.debug) + ap = argparse.ArgumentParser() + ap.add_argument("--debug", default=0, type=int) + group = ap.add_mutually_exclusive_group(required=True) + group.add_argument("--print-includes", action="store_true") + group.add_argument("output", nargs="?") + ns = ap.parse_args() + if ns.print_includes: + print_includes() + exit(0) + + out_path = Path(ns.output) + out_inc = out_path.parent / (out_path.stem + ".inc.cc") + with open(out_path, "w", encoding="utf8") as f, open( + out_inc, "w", encoding="utf8" + ) as inc_f: + generator = PyosysWrapperGenerator( + from_headers=pyosys_headers, wrapper_stream=f, header_stream=inc_f + ) + generator.generate() diff --git a/pyosys/hashlib.h b/pyosys/hashlib.h index e8ace90c8..2ecadc3f1 100644 --- a/pyosys/hashlib.h +++ b/pyosys/hashlib.h @@ -48,6 +48,7 @@ #include "kernel/hashlib.h" namespace pybind11 { +namespace hashlib { template struct is_pointer { static const bool value = false; }; @@ -59,6 +60,11 @@ bool is_mapping(object obj) { return isinstance(obj, mapping); } +// shim +template +void bind_vector(module &m, const char *name_cstr) { + pybind11::bind_vector(m, name_cstr); +} // also used for std::set because the semantics are close enough template @@ -106,6 +112,13 @@ void bind_pool(module &m, const char *name_cstr) { }); } +// shim +template +void bind_set(module &m, const char *name_cstr) { + bind_pool(m, name_cstr); +} + + template void update_dict(C *target, iterable &iterable_or_mapping) { if (is_mapping(iterable_or_mapping)) { @@ -272,4 +285,5 @@ void bind_idict(module &m, const char *name_cstr) { }); } } +}; // namespace hashlib }; // namespace pybind11 diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc index e921ae17a..d235b2c55 100644 --- a/pyosys/wrappers_tpl.cc +++ b/pyosys/wrappers_tpl.cc @@ -26,7 +26,12 @@ USING_YOSYS_NAMESPACE -// +using std::set; +using std::regex; +using std::ostream; +using namespace RTLIL; + +#include "wrappers.inc.cc" namespace YOSYS_PYTHON { @@ -37,8 +42,6 @@ namespace YOSYS_PYTHON { struct YosysStatics{}; - // - // Trampolines for Classes with Python-Overridable Virtual Methods // https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python class PassTrampoline : public Pass { @@ -182,7 +185,18 @@ namespace YOSYS_PYTHON { })); } - m.def("log_to_stream", &log_to_stream, "pipes yosys logs to a Python stream"); + // Logging Methods + m.def("log_header", [](Design *d, std::string s) { log_formatted_header(d, "%s", s); }); + m.def("log", [](std::string s) { log_formatted_string("%s", s); }); + m.def("log_file_info", [](std::string_view file, int line, std::string s) { log_formatted_file_info(file, line, s); }); + m.def("log_warning", [](std::string s) { log_formatted_warning("Warning: ", s); }); + m.def("log_warning_noprefix", [](std::string s) { log_formatted_warning("", s); }); + m.def("log_file_warning", [](std::string_view file, int line, std::string s) { log_formatted_file_warning(file, line, s); }); + m.def("log_error", [](std::string s) { log_formatted_error(s); }); + m.def("log_file_error", [](std::string_view file, int line, std::string s) { log_formatted_file_error(file, line, s); }); + + // Namespace to host global objects + auto global_variables = py::class_(m, "Yosys"); // Trampoline Classes py::class_>(m, "Pass") @@ -241,6 +255,9 @@ namespace YOSYS_PYTHON { .def("notify_blackout", &RTLIL::Monitor::notify_blackout) ; + // Bind Opaque Containers + bind_autogenerated_opaque_containers(m); + // }; }; diff --git a/pyproject.toml b/pyproject.toml index caa620528..5a218c19d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,7 @@ [build-system] requires = [ - "setuptools>=42", - "pybind11>=3,<4", + "setuptools>=42", + "pybind11>=3,<4", + "cxxheaderparser", ] build-backend = "setuptools.build_meta" diff --git a/tests/pyosys/test_logs.py b/tests/pyosys/test_logs.py new file mode 100644 index 000000000..b6bd02222 --- /dev/null +++ b/tests/pyosys/test_logs.py @@ -0,0 +1,8 @@ +from pyosys import libyosys as ys + +d = ys.Design(); ys.log_header(d, "foo\n") +ys.log("foo\n") +ys.log_warning("foo\n") +ys.log_warning_noprefix("foo\n") +ys.log_file_info("foo.ys", 1, "foo\n") +ys.log_file_warning("foo.ys", 1, "foo\n") From 54799bb8be85f784b9682f5643e0f41f93684863 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 23 Sep 2025 03:44:34 +0300 Subject: [PATCH 34/49] pyosys: globals, set operators for opaque types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is so much templating going on that compiling wrappers.cc now takes 1m1.668s on an Apple M4… --- Makefile | 2 +- kernel/yosys.cc | 10 +- pyosys/generator.py | 48 ++++--- pyosys/hashlib.h | 241 +++++++++++++++++++++++++++++++++--- pyosys/wrappers_tpl.cc | 6 - pyproject.toml | 4 + tests/pyosys/test_dict.py | 18 ++- tests/pyosys/test_import.py | 19 ++- tests/pyosys/test_set.py | 42 +++++++ 9 files changed, 343 insertions(+), 47 deletions(-) create mode 100644 tests/pyosys/test_set.py diff --git a/Makefile b/Makefile index c9cbd0810..027f18a7a 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ all: top-all YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) -CXXSTD ?= c++17 +export CXXSTD ?= c++17 CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include LIBS := $(LIBS) -lstdc++ -lm PLUGIN_LINKFLAGS := diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 9cab12bf6..47057c1ca 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -185,13 +185,12 @@ bool already_setup = false; bool already_shutdown = false; #ifdef WITH_PYTHON -// Include pyosys as a module so 'from pyosys import libyosys' also works -// in interpreter mode. +// Include pyosys as a package for some compatibility with wheels. // // This should not affect using wheels as the dylib has to actually be called -// pyosys.so for this module to be interacted with at all. +// pyosys.so for this function to be interacted with at all. PYBIND11_MODULE(pyosys, m) { - m.add_object("libyosys", m.import("libyosys")); + m.add_object("__path__", py::list()); } #endif @@ -209,7 +208,8 @@ void yosys_setup() // initialized platform fails (such as when libyosys is imported // from a Python interpreter) if (!Py_IsInitialized()) { - PyImport_AppendInittab((char*)"libyosys", PyInit_libyosys); + PyImport_AppendInittab((char*)"pyosys.libyosys", PyInit_libyosys); + // compatibility with wheels PyImport_AppendInittab((char*)"pyosys", PyInit_pyosys); Py_Initialize(); PyRun_SimpleString("import sys"); diff --git a/pyosys/generator.py b/pyosys/generator.py index b8a7aa8dc..b0cec99e3 100644 --- a/pyosys/generator.py +++ b/pyosys/generator.py @@ -18,7 +18,19 @@ # Written by Mohamed Gaber # # Inspired by py_wrap_generator.py by Benedikt Tutzer +""" +This generates: +- Wrapper calls for opaque container types +- Full wrappers for select classes and all enums, global functions and global + variables +Jump to "MARK: Inclusion and Exclusion" to control the above. + +Please run ruff on this file in particular to make sure it parses with Python +<= 3.12. There is so much f-string use here that the outer quote thing +is a common problem. ``ruff check pyosys/generator.py`` suffices. +""" +import os import io import shutil from pathlib import Path @@ -58,15 +70,24 @@ class PyosysClass: :param name: The base name of the class (without extra qualifiers) :param ref_only: Whether this class can be copied to Python, or only referenced. - :param string_expr: A C++ expression that will be used for the __str__ method in Python - :param hash_expr: A C++ expression that will be fed to ``run_hash`` to declare a __hash__ method for Python + :param string_expr: + A C++ expression that will be used for the ``__str__`` method in Python. + + The object will be available as a const reference with the identifier + `s`. + :param hash_expr: + A C++ expression that will be fed to ``run_hash`` to declare a + ``__hash__`` method for Python. + + The object will be vailable as a const reference with the identifier + `s`. :param denylist: If specified, one or more methods can be excluded from wrapping. """ name: str ref_only: bool = False - # in the format s.(method or property) + # in the format s.(method or property) (or just s) string_expr: Optional[str] = None hash_expr: Optional[str] = None @@ -89,9 +110,7 @@ class PyosysHeader: for cls in classes: self.classes_by_name[cls.name] = cls -""" -Add headers and classes here! -""" +# MARK: Inclusion and Exclusion global_denylist = frozenset( { # deprecated @@ -327,10 +346,11 @@ class PyosysWrapperGenerator(object): def make_preprocessor_options(self): py_include = get_paths()["include"] preprocessor_bin = shutil.which("clang++") or "g++" + cxx_std = os.getenv("CXX_STD", "c++17") return ParserOptions( preprocessor=make_gcc_preprocessor( defines=["_YOSYS_", "WITH_PYTHON"], - gcc_args=[preprocessor_bin, "-fsyntax-only"], + gcc_args=[preprocessor_bin, "-fsyntax-only", f"-std={cxx_std}"], include_paths=[str(__yosys_root__), py_include, pybind11.get_include()], ), ) @@ -476,7 +496,7 @@ class PyosysWrapperGenerator(object): if function.static: definition_fn = "def_static" - print(f"\t\t\t.{definition_fn}({", ".join(self.get_definition_args(function, class_basename, python_name_override))})", file=self.f) + print(f"\t\t\t.{definition_fn}({', '.join(self.get_definition_args(function, class_basename, python_name_override))})", file=self.f) def process_function(self, function: Function): if ( @@ -496,7 +516,7 @@ class PyosysWrapperGenerator(object): self.register_containers(function) - print(f"\t\t\tm.def({", ".join(self.get_definition_args(function, None))});", file=self.f) + print(f"\t\t\tm.def({', '.join(self.get_definition_args(function, None))});", file=self.f) def process_field(self, field: Field, class_basename: str): if field.access != "public": @@ -511,7 +531,8 @@ class PyosysWrapperGenerator(object): unique_ptrs = self.find_containers(("unique_ptr",), field.type) if len(unique_ptrs): - # TODO: figure out how to bridge unique pointers + # TODO: figure out how to bridge unique pointers maybe does anyone + # care return self.register_containers(field) @@ -559,10 +580,10 @@ class PyosysWrapperGenerator(object): self.process_method(method, basename) visited_anonymous_unions = set() - for field in cls.fields: - if field.name in metadata.denylist: + for field_ in cls.fields: + if field_.name in metadata.denylist: continue - self.process_field(field, basename) + self.process_field(field_, basename) # Handle anonymous unions for subclass in cls.classes: @@ -663,7 +684,6 @@ class PyosysWrapperGenerator(object): keyword_aliases = { - "in": "in_", "False": "False_", "None": "None_", "True": "True_", diff --git a/pyosys/hashlib.h b/pyosys/hashlib.h index 2ecadc3f1..b772a2bb3 100644 --- a/pyosys/hashlib.h +++ b/pyosys/hashlib.h @@ -37,7 +37,7 @@ // things like mutating containers that are class properties. // // All methods should be vaguely in the same order as the python reference -// https://docs.python.org/3/library/stdtypes.html +// https://docs.python.org/3.13/library/stdtypes.html // #include // optional maps cleanest to methods that accept None in Python @@ -60,26 +60,188 @@ bool is_mapping(object obj) { return isinstance(obj, mapping); } +// Set Operations +bool is_subset(const iterable &lhs, const iterable &rhs, bool strict = false) { + for (auto &element: lhs) { + if (!rhs.contains(element)) { + return false; + } + } + if (strict) { + return len(rhs) > len(lhs); + } + return true; +} + +template +void unionize(C &lhs, const iterable &rhs) { + for (auto &element: rhs) { + lhs.insert(cast(element)); + } +} + +template +void difference(C &lhs, const iterable &rhs) { + for (auto &element: rhs) { + auto element_cxx = cast(element); + if (lhs.count(element_cxx)) { + lhs.erase(element_cxx); + } + } +} + +template +void intersect(C &lhs, const iterable &rhs) { + // Doing it in-place is a lot slower + // TODO?: Leave modifying lhs to caller (saves a copy) but complicates + // chaining intersections. + C storage(lhs); + + for (auto &element_cxx: lhs) { + if (!rhs.contains(cast(element_cxx))) { + storage.erase(element_cxx); + } + } + lhs = std::move(storage); +} + +template +void symmetric_difference(C &lhs, const iterable &rhs) { + C storage(lhs); + + for (auto &element: rhs) { + auto element_cxx = cast(element); + if (lhs.count(element_cxx)) { + storage.erase(element_cxx); + } else { + storage.insert(element_cxx); + } + } + for (auto &element_cxx: lhs) { + if (rhs.contains(cast(element_cxx))) { + storage.erase(element_cxx); + } + } + lhs = std::move(storage); +} + // shim template void bind_vector(module &m, const char *name_cstr) { pybind11::bind_vector(m, name_cstr); } -// also used for std::set because the semantics are close enough +// also used for hashlib pool because the semantics are close enough template -void bind_pool(module &m, const char *name_cstr) { - std::string {name_cstr}; - +void bind_set(module &m, const char *name_cstr) { class_(m, name_cstr) .def(init<>()) + .def(init()) // copy constructor + .def(init([](const iterable &other){ // copy instructor from arbitrary iterables + auto s = new C(); + unionize(*s, other); + return s; + })) .def("__len__", [](const C &s){ return (size_t)s.size(); }) .def("__contains__", [](const C &s, const T &v){ return s.count(v); }) .def("__delitem__", [](C &s, const T &v) { auto n = s.erase(v); if (n == 0) throw key_error(str(cast(v))); }) - // TODO: disjoint, subset, union, intersection, difference, symdif + .def("disjoint", [](const C &s, const iterable &other) { + for (const auto &element: other) { + if (s.count(cast(element))) { + return false; + } + } + return true; + }) + .def("issubset", [](const iterable &s, const iterable &other) { + return is_subset(s, other); + }) + .def("__eq__", [](const iterable &s, const iterable &other) { + return is_subset(s, other) && len(s) == len(other); + }) + .def("__le__", [](const iterable &s, const iterable &other) { + return is_subset(s, other); + }) + .def("__lt__", [](const iterable &s, const iterable &other) { + return is_subset(s, other, true); + }) + .def("issuperset", [](const iterable &s, const iterable &other) { + return is_subset(other, s); + }) + .def("__ge__", [](const iterable &s, const iterable &other) { + return is_subset(other, s); + }) + .def("__gt__", [](const iterable &s, const iterable &other) { + return is_subset(other, s, true); + }) + .def("union", [](const C &s, const args &others) { + auto result = new C(s); + for (const auto &arg: others) { + auto arg_iterable = reinterpret_borrow(arg); + unionize(*result, arg_iterable); + } + return result; + }) + .def("__or__", [](const C &s, const iterable &other) { + auto result = new C(s); + unionize(*result, other); + return result; + }) + .def("__ior__", [](C &s, const iterable &other) { + unionize(s, other); + return s; + }) + .def("intersection", [](const C &s, const args &others) { + auto result = new C(s); + for (const auto &arg: others) { + auto arg_iterable = reinterpret_borrow(arg); + intersect(*result, arg_iterable); + } + return result; + }) + .def("__and__", [](const C &s, const iterable &other) { + auto result = new C(s); + intersect(*result, other); + return result; + }) + .def("__iand__", [](C &s, const iterable &other) { + intersect(s, other); + return s; + }) + .def("difference", [](const C &s, const args &others) { + auto result = new C(s); + for (const auto &arg: others) { + auto arg_iterable = reinterpret_borrow(arg); + difference(*result, arg_iterable); + } + return result; + }) + .def("__sub__", [](const C &s, const iterable &other) { + auto result = new C(s); + difference(*result, other); + return result; + }) + .def("__isub__", [](C &s, const iterable &other) { + difference(s, other); + return s; + }) + .def("symmetric_difference", [](const C &s, const iterable &other) { + auto result = new C(s); + symmetric_difference(*result, other); + return result; + }) + .def("__xor__", [](const C &s, const iterable &other) { + auto result = new C(s); + symmetric_difference(*result, other); + return result; + }) + .def("__ixor__", [](C &s, const iterable &other) { + symmetric_difference(s, other); + return s; + }) .def("copy", [](const C &s) { return new C(s); }) @@ -107,20 +269,29 @@ void bind_pool(module &m, const char *name_cstr) { .def("__iter__", [](const C &s){ return make_iterator(s.begin(), s.end()); }, keep_alive<0,1>()) - .def("__repr__", [name_cstr](const C &s){ - return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">"; + .def("__repr__", [name_cstr](const py::iterable &s){ + // repr(set(s)) where s is iterable would be more terse/robust + // but are there concerns with copying? + str representation = str(name_cstr) + str("({"); + str comma(", "); + for (const auto &element: s) { + representation += repr(element); + representation += comma; // python supports trailing commas + } + representation += str("})"); + return representation; }); } // shim template -void bind_set(module &m, const char *name_cstr) { - bind_pool(m, name_cstr); +void bind_pool(module &m, const char *name_cstr) { + bind_set(m, name_cstr); } template -void update_dict(C *target, iterable &iterable_or_mapping) { +void update_dict(C *target, const iterable &iterable_or_mapping) { if (is_mapping(iterable_or_mapping)) { for (const auto &key: iterable_or_mapping) { (*target)[cast(key)] = cast(iterable_or_mapping[key]); @@ -137,10 +308,14 @@ void update_dict(C *target, iterable &iterable_or_mapping) { template void bind_dict(module &m, const char *name_cstr) { - std::string {name_cstr}; - - class_(m, name_cstr) + auto cls = class_(m, name_cstr) .def(init<>()) + .def(init()) // copy constructor + .def(init([](const iterable &other){ // copy instructor from arbitrary iterables and mappings + auto s = new C(); + update_dict(s, other); + return s; + })) .def("__len__", [](const C &s){ return (size_t)s.size(); }) .def("__getitem__", [](const C &s, const K &k) { return s.at(k); }) .def("__setitem__", [](C &s, const K &k, const V &v) { s[k] = v; }) @@ -210,9 +385,29 @@ void bind_dict(module &m, const char *name_cstr) { return s; }) .def("__bool__", [](const C &s) { return s.size() != 0; }) - .def("__repr__", [name_cstr](const C &s){ - return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">"; + .def("__repr__", [name_cstr](const C &s) { + // repr(dict(s)) where s is iterable would be more terse/robust + // but are there concerns with copying? + str representation = str(name_cstr) + str("({"); + str colon(": "); + str comma(", "); + for (const auto &item: s) { + representation += repr(cast(item.first)); + representation += colon; + representation += repr(cast(item.second)); + representation += comma; // python supports trailing commas + } + representation += str("})"); + return representation; }); + + // Inherit from collections.abc.Mapping so update operators (and a bunch + // of other things) work. + auto collections_abc = module_::import("collections.abc"); + auto mapping = getattr(collections_abc, "Mapping"); + auto current_bases = list(getattr(cls, "__bases__")); + current_bases.append(mapping); + setattr(cls, "__bases__", tuple(current_bases)); } // idict is a special bijection and doesn't map cleanly to dict @@ -221,10 +416,9 @@ void bind_dict(module &m, const char *name_cstr) { // the hashable as key and the integer as value template void bind_idict(module &m, const char *name_cstr) { - std::string {name_cstr}; - auto cls = class_(m, name_cstr) .def(init<>()) + .def(init()) // copy constructor .def("__len__", [](const C &s){ return (size_t)s.size(); }) .def("__getitem__", [](const C &s, int v) { return s[v]; }) .def("__call__", [](C &s, const K &k) { return s(k); }) @@ -276,7 +470,16 @@ void bind_idict(module &m, const char *name_cstr) { }) .def("__bool__", [](const C &s) { return s.size() != 0; }) .def("__repr__", [name_cstr](const C &s){ - return std::string("<") + name_cstr + " size=" + std::to_string(s.size()) + ">"; + // repr(dict(s)) where s is iterable would be more terse/robust + // but are there concerns with copying? + str representation = str(name_cstr) + str("() | {"); + str comma(", "); + for (const auto &item: s) { + representation += repr(cast(item)); + representation += comma; // python supports trailing commas + } + representation += str("}"); + return representation; }); for (const char *mutator: {"__setitem__", "__delitem__", "pop", "popitem", "setdefault"}) { diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc index d235b2c55..84e201657 100644 --- a/pyosys/wrappers_tpl.cc +++ b/pyosys/wrappers_tpl.cc @@ -34,12 +34,6 @@ using namespace RTLIL; #include "wrappers.inc.cc" namespace YOSYS_PYTHON { - - [[noreturn]] static void log_python_exception_as_error() { - PyErr_Print(); - log_error("Python interpreter encountered an exception.\\n"); - } - struct YosysStatics{}; // Trampolines for Classes with Python-Overridable Virtual Methods diff --git a/pyproject.toml b/pyproject.toml index 5a218c19d..d5882084c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,3 +5,7 @@ requires = [ "cxxheaderparser", ] build-backend = "setuptools.build_meta" + +[tool.ruff] +target-version = "py38" +lint.ignore = ["F541"] diff --git a/tests/pyosys/test_dict.py b/tests/pyosys/test_dict.py index 81e7b5516..916d69b92 100644 --- a/tests/pyosys/test_dict.py +++ b/tests/pyosys/test_dict.py @@ -1,6 +1,12 @@ +from typing import Mapping from pyosys import libyosys as ys -my_dict = ys.StringToStringDict() +StringToStringDict = ys.StringToStringDict + +my_dict = StringToStringDict() + +assert isinstance(my_dict, Mapping) + my_dict["foo"] = "bar" my_dict.update([("first", "second")]) my_dict.update({"key": "value"}) @@ -11,3 +17,13 @@ new_dict = my_dict | {"tomato": "tomato"} del new_dict["foo"] assert set(my_dict.keys()) == {"first", "key", "foo"} assert set(new_dict.keys()) == {"first", "key", "tomato"} + +constructor_test_1 = ys.StringToStringDict(new_dict) +constructor_test_2 = ys.StringToStringDict([("tomato", "tomato")]) +constructor_test_3 = ys.StringToStringDict({ "im running": "out of string ideas" }) + +the_great_or = constructor_test_1 | constructor_test_2 | constructor_test_3 + +assert set(the_great_or) == {"first", "key", "tomato", "im running"} +repr_test = eval(repr(the_great_or)) +assert repr_test == the_great_or diff --git a/tests/pyosys/test_import.py b/tests/pyosys/test_import.py index 48e911033..b6a36b0c1 100644 --- a/tests/pyosys/test_import.py +++ b/tests/pyosys/test_import.py @@ -1,3 +1,20 @@ +import os +import sys + from pyosys import libyosys as ys -ys.log("Hello, world!") +print(ys) + +ys.log("Hello, world!\n") + +from pyosys.libyosys import log + +print(log) + +log("Goodbye, world!\n") + +import pyosys + +if os.path.basename(sys.executable) == "yosys": + # make sure it's not importing the directory + assert "built-in" in repr(pyosys) diff --git a/tests/pyosys/test_set.py b/tests/pyosys/test_set.py new file mode 100644 index 000000000..d89c5243e --- /dev/null +++ b/tests/pyosys/test_set.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from pyosys.libyosys import StringSet, StringPool + +for cls in [StringSet, StringPool]: + print(f"Testing {cls.__name__}...") + A = cls() + A.add("a") + + B = cls() + B = A | {"b"} + + assert A < B + assert A <= B + + A.add("b") + + assert A == B + assert A <= B + assert not A < B + + A.add("c") + + assert A > B + + A &= B + assert A == B + + Ø = A - B + assert len(Ø) == 0 + + C = cls({"A", "B", "C"}) + D = cls() + C |= {"A", "B", "C"} + D |= {"C", "D", "E"} + c_symdiff_d = (C ^ D) + assert (c_symdiff_d) == {"A", "B", "D", "E"} + + repr_test = eval(repr(c_symdiff_d)) + c_symdiff_d == repr_test + + +print("Done.") From dc88906c9199e93e89a2d78e6a66acc9567cf834 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 23 Sep 2025 08:05:04 +0300 Subject: [PATCH 35/49] tests/pyosys: print log on failed test, fix make clean --- .github/workflows/wheels.yml | 3 ++- Makefile | 7 ++++--- tests/pyosys/run_tests.py | 39 +++++++++++++++++++++--------------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b561b5d32..d6e9832aa 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -2,6 +2,7 @@ name: Build Wheels for PyPI # run every Sunday at 10 AM on: + push: # TODO: REMOVE THIS, DO NOT MERGE TO UPSTREAM THIS IS JUST SO I DON'T HAVE TO MANUALLY RUN THE WORKFLOW WITH EVERY PUSH workflow_dispatch: schedule: - cron: "0 10 * * 0" @@ -107,7 +108,7 @@ jobs: makeFlags='CONFIG=clang' PATH="$PWD/bison/src:$PATH" CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh - CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py python3 + CIBW_TEST_COMMAND: python3 {project}/tests/pyosys/run_tests.py - uses: actions/upload-artifact@v4 with: name: python-wheels-${{ matrix.os.runner }} diff --git a/Makefile b/Makefile index 027f18a7a..09d5f055d 100644 --- a/Makefile +++ b/Makefile @@ -344,6 +344,8 @@ ifeq ($(ENABLE_LIBYOSYS),1) TARGETS += libyosys.so endif +PY_WRAPPER_FILE = pyosys/wrappers + ifeq ($(ENABLE_PYOSYS),1) # python-config --ldflags includes -l and -L, but LINKFLAGS is only -L LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags)) @@ -353,7 +355,6 @@ PYBIND11_INCLUDE ?= $(shell $(PYTHON_EXECUTABLE) -m pybind11 --includes) CXXFLAGS += -I$(PYBIND11_INCLUDE) -DWITH_PYTHON CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON -PY_WRAPPER_FILE = pyosys/wrappers OBJS += $(PY_WRAPPER_FILE).o PY_GEN_SCRIPT = pyosys/generator.py PY_WRAP_INCLUDES := $(shell $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) @@ -1110,9 +1111,9 @@ docs: docs/prep clean: rm -rf share rm -rf kernel/*.pyh - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc + rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc rm -f kernel/version_*.o kernel/version_*.cc - rm -f kernel/python_wrappers.o + rm -f $(PY_WRAPPER_FILE).o rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d rm -rf tests/asicworld/*.out tests/asicworld/*.log rm -rf tests/hana/*.out tests/hana/*.log diff --git a/tests/pyosys/run_tests.py b/tests/pyosys/run_tests.py index 953462c4f..6c631c507 100644 --- a/tests/pyosys/run_tests.py +++ b/tests/pyosys/run_tests.py @@ -1,39 +1,46 @@ -from pathlib import Path -import shutil -import subprocess import sys +import shutil +import shlex +import subprocess +from pathlib import Path __file_dir__ = Path(__file__).absolute().parent -if len(sys.argv) != 2: - print(f"Usage: {sys.argv[0]} {sys.argv[1]}") +if len(sys.argv) > 2 or len(sys.argv) == 2 and sys.argv[1] != 'yosys': + print(f"Usage: {sys.argv[0]} [yosys]") exit(64) -binary = [] -if sys.argv[1] in ["yosys"]: - binary = [__file_dir__.parents[1] / "yosys", "-Qy"] +if len(sys.argv) == 2: + binary = [str(__file_dir__.parents[1] / "yosys"), "-Qy"] else: - binary = [sys.argv[1]] + binary = [sys.executable or shutil.which("python3") or "python3"] # sys.executable can actually be None tests = __file_dir__.glob("test_*.py") -errors = False + log_dir = __file_dir__ / "logs" try: shutil.rmtree(log_dir) except FileNotFoundError: pass +fail_logs = set() for test in tests: print(f"* {test.name} ", end="") log_dir.mkdir(parents=True, exist_ok=True) log = log_dir / (test.stem + ".log") - result = subprocess.run([ - *binary, - test - ], stdout=open(log, "w"), stderr=subprocess.STDOUT) + cmd = [*binary, str(test)] + log_file = open(log, "w", encoding="utf8") + log_file.write(f"$ {shlex.join(cmd)}\n") + log_file.flush() + result = subprocess.run(cmd, stdout=log_file, stderr=subprocess.STDOUT) if result.returncode == 0: print("OK!") else: print(f"FAILED: {log}") - errors = True -if errors: + fail_logs.add(log) + log_file.close() +for log in fail_logs: + print(f">>> {log}") + with open(log, encoding="utf8") as f: + print(f.read()) +if len(fail_logs): exit(1) From 447a6cb3f00d088c1fd92b304b8ad40ddf28dbd2 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 23 Sep 2025 15:29:01 +0300 Subject: [PATCH 36/49] misc: `WITH_PYTHON` -> `YOSYS_ENABLE_PYTHON` For consistency. Also trying a new thing: only rebuilding objects that use the pybind11 library. The idea is these are the only objects that include the Python/pybind headers and thus the only ones that depend on the Python ABI in any capacity, so other objects can be reused across wheel builds. This has the potential to cut down build times. --- .github/workflows/wheels/cibw_before_build.sh | 4 +-- Makefile | 20 +++++++++---- kernel/driver.cc | 16 +++++++---- kernel/rtlil.cc | 28 +++++++++---------- kernel/rtlil.h | 10 +++---- kernel/yosys.cc | 20 ++++++++----- kernel/yosys.h | 4 +-- kernel/yosys_common.h | 7 ----- passes/cmds/plugin.cc | 16 +++++++---- pyosys/generator.py | 2 +- pyosys/hashlib.h | 5 ++-- pyosys/wrappers_tpl.cc | 10 ++++--- 12 files changed, 82 insertions(+), 60 deletions(-) diff --git a/.github/workflows/wheels/cibw_before_build.sh b/.github/workflows/wheels/cibw_before_build.sh index 4e81688d0..1ce96b291 100644 --- a/.github/workflows/wheels/cibw_before_build.sh +++ b/.github/workflows/wheels/cibw_before_build.sh @@ -1,8 +1,8 @@ set -e set -x -# Don't use objects from previous compiles on Windows/macOS -make clean +# Don't use Python objects from previous compiles +make clean-py # DEBUG: show python3 and python3-config outputs if [ "$(uname)" != "Linux" ]; then diff --git a/Makefile b/Makefile index 09d5f055d..22aeee5e8 100644 --- a/Makefile +++ b/Makefile @@ -346,14 +346,18 @@ endif PY_WRAPPER_FILE = pyosys/wrappers +# running make clean on just those and then recompiling saves a lot of +# time when running cibuildwheel +PYTHON_OBJECTS = pyosys/wrappers.o kernel/drivers.o kernel/yosys.o passes/cmds/plugin.o + ifeq ($(ENABLE_PYOSYS),1) # python-config --ldflags includes -l and -L, but LINKFLAGS is only -L LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags)) LIBS += $(shell $(PYTHON_CONFIG) --libs) EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) PYBIND11_INCLUDE ?= $(shell $(PYTHON_EXECUTABLE) -m pybind11 --includes) -CXXFLAGS += -I$(PYBIND11_INCLUDE) -DWITH_PYTHON -CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON +CXXFLAGS += -I$(PYBIND11_INCLUDE) -DYOSYS_ENABLE_PYTHON +CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DYOSYS_ENABLE_PYTHON OBJS += $(PY_WRAPPER_FILE).o PY_GEN_SCRIPT = pyosys/generator.py @@ -1108,12 +1112,10 @@ DOC_TARGET ?= html docs: docs/prep $(Q) $(MAKE) -C docs $(DOC_TARGET) -clean: +clean: clean-py rm -rf share - rm -rf kernel/*.pyh - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc + rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) rm -f kernel/version_*.o kernel/version_*.cc - rm -f $(PY_WRAPPER_FILE).o rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d rm -rf tests/asicworld/*.out tests/asicworld/*.log rm -rf tests/hana/*.out tests/hana/*.log @@ -1127,8 +1129,14 @@ clean: rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS)) -$(MAKE) -C docs clean rm -rf docs/util/__pycache__ + rm -f libyosys.so + +clean-py: + rm -f $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc + rm -f $(PYTHON_OBJECTS) rm -f *.whl rm -f libyosys.so + rm -rf kernel/*.pyh clean-abc: $(MAKE) -C abc DEP= clean diff --git a/kernel/driver.cc b/kernel/driver.cc index a27c0a00f..795fd9fc5 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -37,6 +37,12 @@ # include #endif +#ifdef YOSYS_ENABLE_PYTHON +# include +# include +namespace py = pybind11; +#endif + #include #include #include @@ -91,7 +97,7 @@ int main(int argc, char **argv) log_error_stderr = true; yosys_banner(); yosys_setup(); -#ifdef WITH_PYTHON +#ifdef YOSYS_ENABLE_PYTHON py::object sys = py::module_::import("sys"); sys.attr("path").attr("append")(proc_self_dirname()); sys.attr("path").attr("append")(proc_share_dirname()); @@ -227,10 +233,10 @@ int main(int argc, char **argv) cxxopts::value(),"") ("C,tcl-interactive", "enters TCL interactive shell mode") #endif // YOSYS_ENABLE_TCL -#ifdef WITH_PYTHON +#ifdef YOSYS_ENABLE_PYTHON ("y,py-scriptfile", "execute the Python