From e7058593f41ace45cb19aba24935a39de70733ca Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Apr 2020 15:57:48 -0700 Subject: [PATCH 001/197] opt_expr: improve single-bit $and/$or/$xor/$xnor cells; gate cells too --- passes/opt/opt_expr.cc | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 2b35ace5e..b213d2280 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -148,7 +148,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ std::vector bits_a = sig_a, bits_b = sig_b, bits_y = sig_y; - enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N }; + enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_CONST_X, GRP_N }; std::map, std::set> grouped_bits[GRP_N]; for (int i = 0; i < GetSize(bits_y); i++) @@ -165,9 +165,9 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ if (bit_a.wire == NULL && bit_b.wire == NULL) group_idx = GRP_CONST_AB; else if (bit_a.wire == NULL) - group_idx = GRP_CONST_A; + group_idx = (bit_a == State::S0 || bit_a == State::S1 ? GRP_CONST_A : GRP_CONST_X); else if (bit_b.wire == NULL && commutative) - group_idx = GRP_CONST_A, std::swap(bit_a, bit_b); + group_idx = (bit_b == State::S0 || bit_b == State::S1 ? GRP_CONST_A : GRP_CONST_X), std::swap(bit_a, bit_b); else if (bit_b.wire == NULL) group_idx = GRP_CONST_B; @@ -476,13 +476,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (detect_const_and && (found_zero || found_inv)) { + if (detect_const_and && (found_zero || found_inv || (!keepdc && found_undef))) { cover("opt.opt_expr.const_and"); replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); goto next_cell; } - if (detect_const_or && (found_one || found_inv)) { + if (detect_const_or && (found_one || found_inv || (!keepdc && found_undef))) { cover("opt.opt_expr.const_or"); replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); goto next_cell; @@ -499,9 +499,23 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { SigBit sig_a = assign_map(cell->getPort(ID::A)); SigBit sig_b = assign_map(cell->getPort(ID::B)); + if (sig_a == sig_b) { + if (cell->type.in(ID($xor), ID($_XOR_))) { + cover("opt.opt_expr.const_xor"); + replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0); + goto next_cell; + } + if (cell->type.in(ID($xnor), ID($_XNOR_))) { + cover("opt.opt_expr.const_xnor"); + replace_cell(assign_map, module, cell, "const_xnor", ID::Y, RTLIL::State::S1); + goto next_cell; + } + log_abort(); + } + if (!sig_a.wire) std::swap(sig_a, sig_b); - if (sig_b == State::S0 || sig_b == State::S1) { + if (!sig_b.wire && (sig_b == State::S0 || sig_b == State::S1 || !keepdc)) { if (cell->type.in(ID($xor), ID($_XOR_))) { cover("opt.opt_expr.xor_buffer"); SigSpec sig_y; @@ -844,7 +858,7 @@ skip_fine_alu: if (input.match("**")) ACTION_DO_Y(x); if (input.match("1*")) ACTION_DO_Y(x); if (input.match("*1")) ACTION_DO_Y(x); - if (consume_x) { + if (!keepdc) { if (input.match(" *")) ACTION_DO_Y(0); if (input.match("* ")) ACTION_DO_Y(0); } @@ -863,7 +877,7 @@ skip_fine_alu: if (input.match("**")) ACTION_DO_Y(x); if (input.match("0*")) ACTION_DO_Y(x); if (input.match("*0")) ACTION_DO_Y(x); - if (consume_x) { + if (!keepdc) { if (input.match(" *")) ACTION_DO_Y(1); if (input.match("* ")) ACTION_DO_Y(1); } @@ -880,8 +894,10 @@ skip_fine_alu: if (input.match("01")) ACTION_DO_Y(1); if (input.match("10")) ACTION_DO_Y(1); if (input.match("11")) ACTION_DO_Y(0); - if (input.match(" *")) ACTION_DO_Y(x); - if (input.match("* ")) ACTION_DO_Y(x); + if (!keepdc) { + if (input.match(" *")) ACTION_DO(ID::Y, input.extract(0, 1)); + if (input.match("* ")) ACTION_DO(ID::Y, input.extract(1, 1)); + } } if (cell->type == ID($_MUX_)) { @@ -1094,6 +1110,9 @@ skip_fine_alu: if (b.is_fully_const() && b.as_bool() == false) identity_wrt_a = true; + + if (cell->type == ID($xor) && a == b) + identity_wrt_a = true; } if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) From b84415094c193fbeb2053f0a888689ea1502e7cc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Apr 2020 15:58:36 -0700 Subject: [PATCH 002/197] tests: add opt_expr tests --- tests/opt/bug1758.ys | 21 +++++++++ tests/opt/opt_expr_and.ys | 85 ++++++++++++++++++++++++++++++++++++ tests/opt/opt_expr_or.ys | 85 ++++++++++++++++++++++++++++++++++++ tests/opt/opt_expr_xnor.ys | 85 ++++++++++++++++++++++++++++++++++++ tests/opt/opt_expr_xor.ys | 89 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 tests/opt/bug1758.ys create mode 100644 tests/opt/opt_expr_and.ys create mode 100644 tests/opt/opt_expr_or.ys create mode 100644 tests/opt/opt_expr_xnor.ys diff --git a/tests/opt/bug1758.ys b/tests/opt/bug1758.ys new file mode 100644 index 000000000..85dfaceb8 --- /dev/null +++ b/tests/opt/bug1758.ys @@ -0,0 +1,21 @@ +read_verilog -noopt < Date: Thu, 23 Apr 2020 18:15:07 -0700 Subject: [PATCH 003/197] opt_expr: do not group by X, more fixes --- passes/opt/opt_expr.cc | 77 +++++++++++++++++++++++++++++--------- tests/opt/opt_expr_xnor.ys | 2 +- tests/opt/opt_expr_xor.ys | 2 +- 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index b213d2280..5ada11336 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -132,7 +132,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, did_something = true; } -bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap) +bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc) { IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A; @@ -148,7 +148,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ std::vector bits_a = sig_a, bits_b = sig_b, bits_y = sig_y; - enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_CONST_X, GRP_N }; + enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N }; std::map, std::set> grouped_bits[GRP_N]; for (int i = 0; i < GetSize(bits_y); i++) @@ -162,14 +162,16 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) bit_a = bit_b = RTLIL::State::S0; - if (bit_a.wire == NULL && bit_b.wire == NULL) - group_idx = GRP_CONST_AB; - else if (bit_a.wire == NULL) - group_idx = (bit_a == State::S0 || bit_a == State::S1 ? GRP_CONST_A : GRP_CONST_X); - else if (bit_b.wire == NULL && commutative) - group_idx = (bit_b == State::S0 || bit_b == State::S1 ? GRP_CONST_A : GRP_CONST_X), std::swap(bit_a, bit_b); - else if (bit_b.wire == NULL) - group_idx = GRP_CONST_B; + if (!keepdc || (bit_a != State::Sx && bit_a != State::Sz && bit_a != State::Sx && bit_a != State::Sx)) { + if (bit_a.wire == NULL && bit_b.wire == NULL) + group_idx = GRP_CONST_AB; + else if (bit_a.wire == NULL) + group_idx = GRP_CONST_A; + else if (bit_b.wire == NULL && commutative) + group_idx = GRP_CONST_A, std::swap(bit_a, bit_b); + else if (bit_b.wire == NULL) + group_idx = GRP_CONST_B; + } grouped_bits[group_idx][std::pair(bit_a, bit_b)].insert(bits_y[i]); } @@ -186,26 +188,64 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ if (grouped_bits[i].empty()) continue; - RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); + RTLIL::SigSpec new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); RTLIL::SigSpec new_a, new_b; RTLIL::SigSig new_conn; for (auto &it : grouped_bits[i]) { for (auto &bit : it.second) { new_conn.first.append(bit); - new_conn.second.append(RTLIL::SigBit(new_y, new_a.size())); + new_conn.second.append(new_y[new_a.size()]); } new_a.append(it.first.first); new_b.append(it.first.second); } if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) { + if (cell->type == ID($and)) + new_a.replace(dict{{State::Sx, State::S0}, {State::Sz, State::S0}}, &new_b); + else if (cell->type == ID($or)) + new_a.replace(dict{{State::Sx, State::S1}, {State::Sz, State::S1}}, &new_b); + else log_abort(); log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); module->connect(new_y, new_b); module->connect(new_conn); continue; } + if (!keepdc && cell->type.in(ID($xor), ID($xnor)) && i == GRP_CONST_A) { + SigSpec undef_a, undef_y, undef_b; + SigSpec def_y, def_a, def_b; + for (int i = 0; i < GetSize(new_y); i++) + if (new_a[i] == State::Sx || new_a[i] == State::Sz) { + undef_a.append(new_a[i]); + if (cell->type == ID($xor)) + undef_b.append(State::S0); + // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_ + else if (cell->type == ID($xnor)) + undef_b.append(State::S1); + else log_abort(); + undef_y.append(new_y[i]); + } + else { + def_a.append(new_a[i]); + def_b.append(new_b[i]); + def_y.append(new_y[i]); + } + if (!undef_y.empty()) { + log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(undef_b), log_id(cell->type), log_signal(undef_a)); + module->connect(undef_y, undef_b); + } + if (def_y.empty()) { + module->connect(new_conn); + continue; + } + new_a = std::move(def_a); + new_b = std::move(def_b); + new_y = std::move(def_y); + } + + RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); c->setPort(ID::A, new_a); @@ -219,7 +259,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ } c->setPort(ID::Y, new_y); - c->parameters[ID::Y_WIDTH] = new_y->width; + c->parameters[ID::Y_WIDTH] = GetSize(new_y); c->check(); module->connect(new_conn); @@ -499,7 +539,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { SigBit sig_a = assign_map(cell->getPort(ID::A)); SigBit sig_b = assign_map(cell->getPort(ID::B)); - if (sig_a == sig_b) { + if (!keepdc && (sig_a == sig_b || sig_a == State::Sx || sig_a == State::Sz || sig_b == State::Sx || sig_b == State::Sz)) { if (cell->type.in(ID($xor), ID($_XOR_))) { cover("opt.opt_expr.const_xor"); replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0); @@ -507,6 +547,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (cell->type.in(ID($xnor), ID($_XNOR_))) { cover("opt.opt_expr.const_xnor"); + // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_ replace_cell(assign_map, module, cell, "const_xnor", ID::Y, RTLIL::State::S1); goto next_cell; } @@ -515,7 +556,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (!sig_a.wire) std::swap(sig_a, sig_b); - if (!sig_b.wire && (sig_b == State::S0 || sig_b == State::S1 || !keepdc)) { + if (sig_b == State::S0 || sig_b == State::S1) { if (cell->type.in(ID($xor), ID($_XOR_))) { cover("opt.opt_expr.xor_buffer"); SigSpec sig_y; @@ -564,7 +605,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (do_fine) { if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor))) - if (group_cell_inputs(module, cell, true, assign_map)) + if (group_cell_inputs(module, cell, true, assign_map, keepdc)) goto next_cell; if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool))) @@ -895,8 +936,8 @@ skip_fine_alu: if (input.match("10")) ACTION_DO_Y(1); if (input.match("11")) ACTION_DO_Y(0); if (!keepdc) { - if (input.match(" *")) ACTION_DO(ID::Y, input.extract(0, 1)); - if (input.match("* ")) ACTION_DO(ID::Y, input.extract(1, 1)); + if (input.match(" *")) ACTION_DO_Y(0); + if (input.match("* ")) ACTION_DO_Y(0); } } diff --git a/tests/opt/opt_expr_xnor.ys b/tests/opt/opt_expr_xnor.ys index d712842d5..eadd3ce56 100644 --- a/tests/opt/opt_expr_xnor.ys +++ b/tests/opt/opt_expr_xnor.ys @@ -80,6 +80,6 @@ select -assert-count t c:$_XOR_ cd miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 -sat -verify -prove-asserts -show-ports -enable_undef -set-def in_i miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 sat -verify -prove-asserts -show-ports -enable_undef miter4 diff --git a/tests/opt/opt_expr_xor.ys b/tests/opt/opt_expr_xor.ys index b581ac644..411bc396c 100644 --- a/tests/opt/opt_expr_xor.ys +++ b/tests/opt/opt_expr_xor.ys @@ -136,6 +136,6 @@ select -assert-count t c:$_XOR_ cd miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 -sat -verify -prove-asserts -show-ports -enable_undef -set-def in_i miter3 +sat -verify -prove-asserts -show-ports -enable_undef miter3 miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 sat -verify -prove-asserts -show-ports -enable_undef miter4 From 83570bc0da7773b16eca7cebfd792ae799eb5c0f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 24 Apr 2020 11:15:29 -0700 Subject: [PATCH 004/197] opt_expr: more fixes for $xor/$xnor --- passes/opt/opt_expr.cc | 70 ++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 5ada11336..38dc09af5 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -156,13 +156,27 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ int group_idx = GRP_DYN; RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; - if (cell->type == ID($or) && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) - bit_a = bit_b = RTLIL::State::S1; + if (cell->type == ID($or)) { + if (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1) + bit_a = bit_b = RTLIL::State::S1; + } + else if (cell->type == ID($and)) { + if (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0) + bit_a = bit_b = RTLIL::State::S0; + } + else if (!keepdc) { + if (cell->type == ID($xor)) { + if (bit_a == bit_b) + bit_a = bit_b = RTLIL::State::S0; + } + else if (cell->type == ID($xnor)) { + if (bit_a == bit_b) + bit_a = bit_b = RTLIL::State::S1; // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_ + } + } - if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) - bit_a = bit_b = RTLIL::State::S0; - - if (!keepdc || (bit_a != State::Sx && bit_a != State::Sz && bit_a != State::Sx && bit_a != State::Sx)) { + bool def = (bit_a != State::Sx && bit_a != State::Sz && bit_b != State::Sx && bit_b != State::Sx); + if (def || !keepdc) { if (bit_a.wire == NULL && bit_b.wire == NULL) group_idx = GRP_CONST_AB; else if (bit_a.wire == NULL) @@ -202,43 +216,56 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ } if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) { - if (cell->type == ID($and)) - new_a.replace(dict{{State::Sx, State::S0}, {State::Sz, State::S0}}, &new_b); - else if (cell->type == ID($or)) - new_a.replace(dict{{State::Sx, State::S1}, {State::Sz, State::S1}}, &new_b); - else log_abort(); + if (!keepdc) { + if (cell->type == ID($and)) + new_a.replace(dict{{State::Sx, State::S0}, {State::Sz, State::S0}}, &new_b); + else if (cell->type == ID($or)) + new_a.replace(dict{{State::Sx, State::S1}, {State::Sz, State::S1}}, &new_b); + else log_abort(); + } log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); module->connect(new_y, new_b); module->connect(new_conn); continue; } - if (!keepdc && cell->type.in(ID($xor), ID($xnor)) && i == GRP_CONST_A) { + if (cell->type.in(ID($xor), ID($xnor)) && i == GRP_CONST_A) { SigSpec undef_a, undef_y, undef_b; SigSpec def_y, def_a, def_b; - for (int i = 0; i < GetSize(new_y); i++) - if (new_a[i] == State::Sx || new_a[i] == State::Sz) { + for (int i = 0; i < GetSize(new_y); i++) { + bool undef = new_a[i] == State::Sx || new_a[i] == State::Sz; + if (!keepdc && (undef || new_a[i] == new_b[i])) { undef_a.append(new_a[i]); if (cell->type == ID($xor)) undef_b.append(State::S0); - // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_ + // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_ else if (cell->type == ID($xnor)) undef_b.append(State::S1); else log_abort(); undef_y.append(new_y[i]); } + else if (new_a[i] == State::S0 || new_a[i] == State::S1) { + undef_a.append(new_a[i]); + if (cell->type == ID($xor)) + undef_b.append(new_a[i] == State::S1 ? module->Not(NEW_ID, new_b[i]).as_bit() : new_b[i]); + else if (cell->type == ID($xnor)) + undef_b.append(new_a[i] == State::S1 ? new_b[i] : module->Not(NEW_ID, new_b[i]).as_bit()); + else log_abort(); + undef_y.append(new_y[i]); + } else { def_a.append(new_a[i]); def_b.append(new_b[i]); def_y.append(new_y[i]); } + } if (!undef_y.empty()) { log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(undef_b), log_id(cell->type), log_signal(undef_a)); module->connect(undef_y, undef_b); - } - if (def_y.empty()) { - module->connect(new_conn); - continue; + if (def_y.empty()) { + module->connect(new_conn); + continue; + } } new_a = std::move(def_a); new_b = std::move(def_b); @@ -547,7 +574,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (cell->type.in(ID($xnor), ID($_XNOR_))) { cover("opt.opt_expr.const_xnor"); - // For consistency with gate-level which does $xnor -> $_XOR_ + $_NOT_ + // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_ replace_cell(assign_map, module, cell, "const_xnor", ID::Y, RTLIL::State::S1); goto next_cell; } @@ -1151,9 +1178,6 @@ skip_fine_alu: if (b.is_fully_const() && b.as_bool() == false) identity_wrt_a = true; - - if (cell->type == ID($xor) && a == b) - identity_wrt_a = true; } if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) From ebd6fa945d4f0afa9a7507e791d13653571c8a63 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 24 Apr 2020 11:16:25 -0700 Subject: [PATCH 005/197] tests: opt_expr update xnor/xor tests --- tests/opt/opt_expr_xnor.ys | 6 +++--- tests/opt/opt_expr_xor.ys | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/opt/opt_expr_xnor.ys b/tests/opt/opt_expr_xnor.ys index eadd3ce56..0f9463379 100644 --- a/tests/opt/opt_expr_xnor.ys +++ b/tests/opt/opt_expr_xnor.ys @@ -56,7 +56,7 @@ copy gold fine_keepdc cd coarse opt_expr -fine -select -assert-count 1 t:$xnor # FIXME: Should be zero +select -assert-none t:$xnor cd fine simplemap @@ -71,12 +71,12 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2 cd coarse_keepdc opt_expr -keepdc -fine -select -assert-count 2 t:$xnor $ FIXME: Should be one +select -assert-count 1 t:$xnor cd fine_keepdc simplemap opt_expr -keepdc -select -assert-count t c:$_XOR_ +select -assert-count 0 c:$_XOR_ cd miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 diff --git a/tests/opt/opt_expr_xor.ys b/tests/opt/opt_expr_xor.ys index 411bc396c..a879f3ec9 100644 --- a/tests/opt/opt_expr_xor.ys +++ b/tests/opt/opt_expr_xor.ys @@ -111,7 +111,7 @@ copy gold fine_keepdc cd coarse opt_expr -fine -select -assert-count 1 t:$xor # FIXME: Should be zero +select -assert-count 0 t:$xor cd fine simplemap @@ -126,13 +126,12 @@ sat -verify -prove-asserts -show-ports -enable_undef miter2 cd coarse_keepdc opt_expr -keepdc -fine -dump -select -assert-count 2 t:$xor $ FIXME: Should be one +select -assert-count 1 t:$xor cd fine_keepdc simplemap opt_expr -keepdc -select -assert-count t c:$_XOR_ +select -assert-count 3 t:$_XOR_ cd miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 From b5f38f834207fab3a563c55568c4543a3b5dcc1f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 24 Apr 2020 14:13:45 -0700 Subject: [PATCH 006/197] opt_expr: const_xnor replacement to pad Y with 1'b1 --- passes/opt/opt_expr.cc | 3 ++- tests/opt/opt_expr_xnor.ys | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 38dc09af5..d895fc691 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -575,7 +575,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (cell->type.in(ID($xnor), ID($_XNOR_))) { cover("opt.opt_expr.const_xnor"); // For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_ - replace_cell(assign_map, module, cell, "const_xnor", ID::Y, RTLIL::State::S1); + int width = cell->getParam(ID::Y_WIDTH).as_int(); + replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width)); goto next_cell; } log_abort(); diff --git a/tests/opt/opt_expr_xnor.ys b/tests/opt/opt_expr_xnor.ys index 0f9463379..f8ef0d352 100644 --- a/tests/opt/opt_expr_xnor.ys +++ b/tests/opt/opt_expr_xnor.ys @@ -83,3 +83,49 @@ miter -equiv -flatten -make_assert -make_outputs gold coarse_keepdc miter3 sat -verify -prove-asserts -show-ports -enable_undef miter3 miter -equiv -flatten -make_assert -make_outputs coarse_keepdc fine_keepdc miter4 sat -verify -prove-asserts -show-ports -enable_undef miter4 + + +# Single-bit $xnor extension +design -reset +read_verilog -noopt < Date: Fri, 24 Apr 2020 14:31:33 -0700 Subject: [PATCH 007/197] tests: fsm to use a randomly-generated seed --- tests/fsm/generate.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/fsm/generate.py b/tests/fsm/generate.py index c8eda0cd1..784e5a054 100644 --- a/tests/fsm/generate.py +++ b/tests/fsm/generate.py @@ -36,9 +36,11 @@ parser.add_argument('-S', '--seed', type = int, help = 'seed for PRNG') parser.add_argument('-c', '--count', type = int, default = 50, help = 'number of test cases to generate') args = parser.parse_args() -if args.seed is not None: - print("PRNG seed: %d" % args.seed) - random.seed(args.seed) +seed = args.seed +if seed is None: + seed = random.randrange(sys.maxsize) +print("PRNG seed: %d" % seed) +random.seed(seed) for idx in range(args.count): with open('temp/uut_%05d.v' % idx, 'w') as f: From 2e911bc806d0a54e4d7e84ef2218ff088ea20b5f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 4 May 2020 12:18:02 -0700 Subject: [PATCH 008/197] test: add failing test --- tests/verilog/upto.ys | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/verilog/upto.ys diff --git a/tests/verilog/upto.ys b/tests/verilog/upto.ys new file mode 100644 index 000000000..d87f4424e --- /dev/null +++ b/tests/verilog/upto.ys @@ -0,0 +1,5 @@ +read_verilog < Date: Mon, 4 May 2020 12:18:20 -0700 Subject: [PATCH 009/197] ast: swap range regardless of range_left >= 0 --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 837c14ad7..cdb7e91e0 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1079,7 +1079,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (old_range_valid != range_valid) did_something = true; - if (range_valid && range_left >= 0 && range_right > range_left) { + if (range_valid && range_right > range_left) { int tmp = range_right; range_right = range_left; range_left = tmp; From 66d0ed2bcc7195aab5b107b2536e6818fe5b244c Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 5 May 2020 04:11:16 +0000 Subject: [PATCH 010/197] ast/simplify: don't bitblast async ROMs declared as `logic`. Fixes #2020. --- frontends/ast/simplify.cc | 4 ++-- tests/svtypes/logic_rom.sv | 6 ++++++ tests/svtypes/logic_rom.ys | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/svtypes/logic_rom.sv create mode 100644 tests/svtypes/logic_rom.ys diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 837c14ad7..9453937e3 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3477,8 +3477,8 @@ void AstNode::mem2reg_as_needed_pass1(dict> &mem2reg } } - // also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' - if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !is_reg)) + // also activate if requested, either by using mem2reg attribute or by declaring array as 'wire' instead of 'reg' or 'logic' + if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !(is_reg || is_logic))) mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED; if (type == AST_MODULE && get_bool_attribute(ID::mem2reg)) diff --git a/tests/svtypes/logic_rom.sv b/tests/svtypes/logic_rom.sv new file mode 100644 index 000000000..45fe0a4ca --- /dev/null +++ b/tests/svtypes/logic_rom.sv @@ -0,0 +1,6 @@ +module top(input [3:0] addr, output [7:0] data); + logic [7:0] mem[0:15]; + assign data = mem[addr]; + integer i; + initial for(i = 0; i < 16; i = i + 1) mem[i] = i; +endmodule diff --git a/tests/svtypes/logic_rom.ys b/tests/svtypes/logic_rom.ys new file mode 100644 index 000000000..7b079c136 --- /dev/null +++ b/tests/svtypes/logic_rom.ys @@ -0,0 +1,3 @@ +read_verilog -sv logic_rom.sv +prep -top top +select -assert-count 1 t:$mem r:SIZE=16 %i r:WIDTH=8 %i From 004999218f52cd5a1308023a474ee608b842a5b7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 5 May 2020 08:01:27 -0700 Subject: [PATCH 011/197] techlibs/common: more robustness when *_WIDTH = 0 --- techlibs/common/cmp2lcu.v | 8 ++++++-- techlibs/common/techmap.v | 29 ++++++++++++++++++++++++----- tests/verilog/upto.ys | 1 - 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/techlibs/common/cmp2lcu.v b/techlibs/common/cmp2lcu.v index b6f4aeed6..e42f346d1 100644 --- a/techlibs/common/cmp2lcu.v +++ b/techlibs/common/cmp2lcu.v @@ -108,8 +108,12 @@ generate // Generate if any comparisons call for it wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG}; end - $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) - _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); + if (AB_WIDTH == 1) + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) + _TECHMAP_REPLACE_ (.A(), .B(), .P(P_), .G(G_), .Y(Y)); + else + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) + _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); end end endgenerate diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index ecf4d5dc5..225cff449 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -285,13 +285,32 @@ module _90_alu (A, B, CI, BI, X, Y, CO); input CI, BI; output [Y_WIDTH-1:0] CO; - 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)); - - wire [Y_WIDTH-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] AA, BB; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + if (A_WIDTH == 0) begin + wire [Y_WIDTH-1:0] B_buf; + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + assign AA = {Y_WIDTH{1'b0}}; + assign BB = BI ? ~B_buf : B_buf; + end + else if (B_WIDTH == 0) begin + wire [Y_WIDTH-1:0] A_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + + assign AA = A_buf; + assign BB = {Y_WIDTH{BI ? 1'b0 : 1'b1}}; + end + else begin + 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)); + + assign AA = A_buf; + assign BB = BI ? ~B_buf : B_buf; + end + \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO)); assign X = AA ^ BB; diff --git a/tests/verilog/upto.ys b/tests/verilog/upto.ys index d87f4424e..2f3394761 100644 --- a/tests/verilog/upto.ys +++ b/tests/verilog/upto.ys @@ -2,4 +2,3 @@ read_verilog < Date: Wed, 6 May 2020 01:01:14 +0200 Subject: [PATCH 012/197] Add extmodule support to firrtl backend The current firrtl backend emits blackboxes as standard modules with an empty body, but this causes the firrtl compiler to optimize out entire circuits due to the absence of any drivers. Yosys already tags blackboxes with a (*blackbox*) attribute, so this commit just propagates this change to firrtl's syntax for blackboxes. --- backends/firrtl/firrtl.cc | 48 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 40d05a036..ff1329532 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -392,7 +392,37 @@ struct FirrtlWorker return result; } - void run() + void emit_extmodule() + { + std::string moduleFileinfo = getFileinfo(module); + f << stringf(" extmodule %s: %s\n", make_id(module->name), moduleFileinfo.c_str()); + vector port_decls; + + for (auto wire : module->wires()) + { + const auto wireName = make_id(wire->name); + std::string wireFileinfo = getFileinfo(wire); + + // Maybe not needed? + if (wire->port_id) + { + if (wire->port_input && wire->port_output) + { + log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire)); + } + port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output", + wireName, wire->width, wireFileinfo.c_str())); + } + } + + for (auto str : port_decls) { + f << str; + } + + f << stringf("\n"); + } + + void emit_module() { std::string moduleFileinfo = getFileinfo(module); f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str()); @@ -1076,6 +1106,22 @@ struct FirrtlWorker for (auto str : wire_exprs) f << str; + + f << stringf("\n"); + } + + void run() + { + // Blackboxes should be emitted as `extmodule`s in firrtl. Only ports are + // emitted in such a case. + if (module->get_blackbox_attribute()) + { + emit_extmodule(); + } + else + { + emit_module(); + } } }; From 323aa1df75dcc21e94c4dfbdb77eaad40f48d081 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Wed, 6 May 2020 07:22:17 +0000 Subject: [PATCH 013/197] verilog: Move lexer location variables from global namespace to `VERILOG_FRONTEND` namespace. --- frontends/verilog/verilog_lexer.l | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index f6a3ac4db..63c0ba159 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -48,16 +48,18 @@ USING_YOSYS_NAMESPACE using namespace AST; using namespace VERILOG_FRONTEND; +#define YYSTYPE FRONTEND_VERILOG_YYSTYPE +#define YYLTYPE FRONTEND_VERILOG_YYLTYPE + YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { std::vector fn_stack; std::vector ln_stack; + YYLTYPE real_location; + YYLTYPE old_location; } YOSYS_NAMESPACE_END -#define YYSTYPE FRONTEND_VERILOG_YYSTYPE -#define YYLTYPE FRONTEND_VERILOG_YYLTYPE - #define SV_KEYWORD(_tok) \ if (sv_mode) return _tok; \ log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\ @@ -73,9 +75,6 @@ YOSYS_NAMESPACE_END #define YY_INPUT(buf,result,max_size) \ result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) -YYLTYPE real_location; -YYLTYPE old_location; - #define YY_USER_ACTION \ old_location = real_location; \ real_location.first_line = real_location.last_line; \ From 1688a625007b0ea7a1b9114ecf7a50d81fcfa38d Mon Sep 17 00:00:00 2001 From: Sahand Kashani Date: Wed, 6 May 2020 21:15:32 +0200 Subject: [PATCH 014/197] Formatting fixes --- backends/firrtl/firrtl.cc | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index ff1329532..e83d4f654 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -396,26 +396,23 @@ struct FirrtlWorker { std::string moduleFileinfo = getFileinfo(module); f << stringf(" extmodule %s: %s\n", make_id(module->name), moduleFileinfo.c_str()); - vector port_decls; + vector port_decls; for (auto wire : module->wires()) { const auto wireName = make_id(wire->name); std::string wireFileinfo = getFileinfo(wire); - // Maybe not needed? - if (wire->port_id) + if (wire->port_input && wire->port_output) { - if (wire->port_input && wire->port_output) - { - log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire)); - } - port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output", - wireName, wire->width, wireFileinfo.c_str())); + log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire)); } + port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output", + wireName, wire->width, wireFileinfo.c_str())); } - for (auto str : port_decls) { + for (auto &str : port_decls) + { f << str; } @@ -1115,13 +1112,9 @@ struct FirrtlWorker // Blackboxes should be emitted as `extmodule`s in firrtl. Only ports are // emitted in such a case. if (module->get_blackbox_attribute()) - { emit_extmodule(); - } else - { emit_module(); - } } }; From 495acf981547850ac7ad5b765dd215b0c33d59ac Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 May 2020 11:07:11 -0700 Subject: [PATCH 015/197] tests: opt_expr tests that depend on consumex --- tests/opt/opt_expr_consumex.ys | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/opt/opt_expr_consumex.ys diff --git a/tests/opt/opt_expr_consumex.ys b/tests/opt/opt_expr_consumex.ys new file mode 100644 index 000000000..d4af10f22 --- /dev/null +++ b/tests/opt/opt_expr_consumex.ys @@ -0,0 +1,35 @@ +read_verilog < Date: Fri, 8 May 2020 11:07:44 -0700 Subject: [PATCH 016/197] opt_expr: restore consume_x; use for coarse grained too --- passes/opt/opt_expr.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index d895fc691..60221f32d 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -543,13 +543,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (detect_const_and && (found_zero || found_inv || (!keepdc && found_undef))) { + if (detect_const_and && (found_zero || found_inv || (!keepdc && found_undef && consume_x))) { cover("opt.opt_expr.const_and"); replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); goto next_cell; } - if (detect_const_or && (found_one || found_inv || (!keepdc && found_undef))) { + if (detect_const_or && (found_one || found_inv || (!keepdc && found_undef && consume_x))) { cover("opt.opt_expr.const_or"); replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); goto next_cell; @@ -927,7 +927,7 @@ skip_fine_alu: if (input.match("**")) ACTION_DO_Y(x); if (input.match("1*")) ACTION_DO_Y(x); if (input.match("*1")) ACTION_DO_Y(x); - if (!keepdc) { + if (consume_x) { if (input.match(" *")) ACTION_DO_Y(0); if (input.match("* ")) ACTION_DO_Y(0); } @@ -946,7 +946,7 @@ skip_fine_alu: if (input.match("**")) ACTION_DO_Y(x); if (input.match("0*")) ACTION_DO_Y(x); if (input.match("*0")) ACTION_DO_Y(x); - if (!keepdc) { + if (consume_x) { if (input.match(" *")) ACTION_DO_Y(1); if (input.match("* ")) ACTION_DO_Y(1); } @@ -963,7 +963,7 @@ skip_fine_alu: if (input.match("01")) ACTION_DO_Y(1); if (input.match("10")) ACTION_DO_Y(1); if (input.match("11")) ACTION_DO_Y(0); - if (!keepdc) { + if (consume_x) { if (input.match(" *")) ACTION_DO_Y(0); if (input.match("* ")) ACTION_DO_Y(0); } @@ -1149,7 +1149,7 @@ skip_fine_alu: goto next_cell; } - if (!keepdc) + if (!keepdc && consume_x) { bool identity_wrt_a = false; bool identity_wrt_b = false; From 9694dc42dd8badde03a27072b294556cb77f5bb5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 May 2020 11:12:43 -0700 Subject: [PATCH 017/197] opt_expr: consume_x to require/imply !keepdc --- passes/opt/opt_expr.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 60221f32d..9a8bc0869 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -543,13 +543,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (detect_const_and && (found_zero || found_inv || (!keepdc && found_undef && consume_x))) { + if (detect_const_and && (found_zero || found_inv || (found_undef && consume_x))) { cover("opt.opt_expr.const_and"); replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); goto next_cell; } - if (detect_const_or && (found_one || found_inv || (!keepdc && found_undef && consume_x))) { + if (detect_const_or && (found_one || found_inv || (found_undef && consume_x))) { cover("opt.opt_expr.const_or"); replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); goto next_cell; @@ -1149,7 +1149,7 @@ skip_fine_alu: goto next_cell; } - if (!keepdc && consume_x) + if (consume_x) { bool identity_wrt_a = false; bool identity_wrt_b = false; @@ -2041,11 +2041,12 @@ struct OptExprPass : public Pass { do { do { did_something = false; - replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv); + replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv); if (did_something) design->scratchpad_set_bool("opt.did_something", true); } while (did_something); - replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); + if (!keepdc) + replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv); if (did_something) design->scratchpad_set_bool("opt.did_something", true); } while (did_something); From 49e64ad492633781e030c795eecd44e73a1bdc1c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 May 2020 11:12:58 -0700 Subject: [PATCH 018/197] test: update opt_expr_alu test --- tests/opt/opt_expr_alu.ys | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/opt/opt_expr_alu.ys b/tests/opt/opt_expr_alu.ys index 9121c0096..477555da9 100644 --- a/tests/opt/opt_expr_alu.ys +++ b/tests/opt/opt_expr_alu.ys @@ -59,9 +59,8 @@ EOT alumacc equiv_opt -assert opt_expr -fine design -load postopt -select -assert-count 1 t:$pos select -assert-count 1 t:$not -select -assert-none t:$pos t:$not %% t:* %D +select -assert-none t:$not %% t:* %D design -reset From b11cf67a8170ee830beedadc7156c4e83e4f1134 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 11 May 2020 10:30:20 -0700 Subject: [PATCH 019/197] Setup tests/verilog properly --- Makefile | 1 + tests/verilog/.gitignore | 3 +++ tests/verilog/run-test.sh | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 tests/verilog/.gitignore create mode 100755 tests/verilog/run-test.sh diff --git a/Makefile b/Makefile index a481dd92b..cd6179879 100644 --- a/Makefile +++ b/Makefile @@ -780,6 +780,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT) +cd tests/rpc && bash run-test.sh +cd tests/memfile && bash run-test.sh + +cd tests/verilog && bash run-test.sh @echo "" @echo " Passed \"make test\"." @echo "" diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore new file mode 100644 index 000000000..b48f808a1 --- /dev/null +++ b/tests/verilog/.gitignore @@ -0,0 +1,3 @@ +/*.log +/*.out +/run-test.mk diff --git a/tests/verilog/run-test.sh b/tests/verilog/run-test.sh new file mode 100755 index 000000000..ea56b70f0 --- /dev/null +++ b/tests/verilog/run-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../yosys -ql ${x%.ys}.log $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk From e5ce5a4fd532f35cf8dd625b97aa426e4661e119 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 11 May 2020 11:05:19 -0700 Subject: [PATCH 020/197] tests: add #2042 testcase --- tests/verilog/bug2042.ys | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/verilog/bug2042.ys diff --git a/tests/verilog/bug2042.ys b/tests/verilog/bug2042.ys new file mode 100644 index 000000000..009e2c20c --- /dev/null +++ b/tests/verilog/bug2042.ys @@ -0,0 +1,12 @@ +logger -expect error "Non-ANSI style task/function arguments not currently supported" 1 +read_verilog < Date: Mon, 11 May 2020 13:00:36 -0700 Subject: [PATCH 021/197] verilog: error out when non-ANSI task/func arguments --- frontends/verilog/verilog_parser.y | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index db9a130cf..b7c6af91e 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -853,7 +853,11 @@ task_func_port: } if (astbuf2 && astbuf2->children.size() != 2) frontend_verilog_yyerror("task/function argument range must be of the form: [:], [+:], or [-:]"); - } wire_name | wire_name; + } wire_name | + { + if (!astbuf1) + frontend_verilog_yyerror("Non-ANSI style task/function arguments not currently supported"); + } wire_name; task_func_body: task_func_body behavioral_stmt | From 95fb3cf487544068bc36207d5250a8bcd4386115 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 May 2020 21:12:26 +0100 Subject: [PATCH 022/197] ecp5: Add missing SERDES parameters Signed-off-by: David Shah --- techlibs/ecp5/cells_bb.v | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index ae124e7a3..756f05366 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -652,6 +652,10 @@ module DCUA( 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 *) From 4ecae8a6735f71e0dd9e3cc8eb0e7855299a78bc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 May 2020 15:40:13 -0700 Subject: [PATCH 023/197] ice40: fix whitespace --- techlibs/ice40/synth_ice40.cc | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 2b211572d..6e05ab0b2 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -225,10 +225,10 @@ struct SynthIce40Pass : public ScriptPass device_opt = args[++argidx]; continue; } - if (args[argidx] == "-flowmap") { - flowmap = true; - continue; - } + if (args[argidx] == "-flowmap") { + flowmap = true; + continue; + } break; } extra_args(args, argidx, design); @@ -240,13 +240,12 @@ struct SynthIce40Pass : public ScriptPass if (abc9 && retime) log_cmd_error("-retime option not currently compatible with -abc9!\n"); - - if (abc9 && noabc) - log_cmd_error("-abc9 is incompatible with -noabc!\n"); - if (abc9 && flowmap) - log_cmd_error("-abc9 is incompatible with -flowmap!\n"); - if (flowmap && noabc) - log_cmd_error("-flowmap is incompatible with -noabc!\n"); + if (abc9 && noabc) + log_cmd_error("-abc9 is incompatible with -noabc!\n"); + if (abc9 && flowmap) + log_cmd_error("-abc9 is incompatible with -flowmap!\n"); + if (flowmap && noabc) + log_cmd_error("-flowmap is incompatible with -noabc!\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -372,10 +371,10 @@ struct SynthIce40Pass : public ScriptPass run("techmap -map +/ice40/latches_map.v"); if (noabc || flowmap || help_mode) { run("simplemap", " (if -noabc or -flowmap)"); - if (noabc || help_mode) - run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); - if (flowmap || help_mode) - run("flowmap -maxlut 4", "(only if -flowmap)"); + if (noabc || help_mode) + run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); + if (flowmap || help_mode) + run("flowmap -maxlut 4", "(only if -flowmap)"); } if (!noabc) { if (abc9) { From 27b7ffc75444583bbecc70e2d7e2e84bc321f2cf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 12 May 2020 15:40:48 -0700 Subject: [PATCH 024/197] ice40: fix ICESTORM_LC process sensitivity --- techlibs/ice40/cells_sim.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 6a0e3031e..5d107989d 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -1908,7 +1908,7 @@ module ICESTORM_LC ( o_reg <= SR_pd ? SET_NORESET : lut_o; reg o_reg_async = 1'b0; - always @(posedge polarized_clk, posedge SR) + always @(posedge polarized_clk, posedge SR_pd) if (SR_pd) o_reg_async <= SET_NORESET; else if (CEN_pu) From 3988f935b8715ddeffc994472c146e62448c8749 Mon Sep 17 00:00:00 2001 From: Peter Crozier Date: Wed, 13 May 2020 13:09:08 +0100 Subject: [PATCH 025/197] Extend YS_DEBUGTRAP to MacOS. --- kernel/log.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/log.h b/kernel/log.h index dee5d44d7..4b60ffb0d 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -86,7 +86,7 @@ YOSYS_NAMESPACE_BEGIN # endif # if __has_builtin(__builtin_debugtrap) # define YS_DEBUGTRAP __builtin_debugtrap() -# elif defined(__unix__) +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) # define YS_DEBUGTRAP raise(SIGTRAP) # else # define YS_DEBUGTRAP do {} while(0) @@ -103,6 +103,9 @@ YOSYS_NAMESPACE_BEGIN # define YS_DEBUGTRAP_IF_DEBUGGING do { \ sighandler_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ } while(0) +#elif defined(__APPLE__) && defined(__MACH__) +// MacOS +#define YS_DEBUGTRAP_IF_DEBUGGING { sig_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); } #else # define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) #endif From 495dcfc812be0f990bee20fc1ac819c72b8b7e47 Mon Sep 17 00:00:00 2001 From: Peter Crozier Date: Wed, 13 May 2020 14:17:00 +0100 Subject: [PATCH 026/197] Consolidate Linux and Mac version of YS_DEBUGTRAP_IF_DEBUGGING. --- kernel/log.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/kernel/log.h b/kernel/log.h index 4b60ffb0d..6c5de78d7 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -97,15 +97,12 @@ YOSYS_NAMESPACE_BEGIN // if a debugger is attached, and does nothing otherwise. #if defined(_WIN32) # define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0) -#elif defined(__unix__) +# elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) // There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However, // debuggers will stop when SIGTRAP is raised, even if the action is set to ignore. # define YS_DEBUGTRAP_IF_DEBUGGING do { \ - sighandler_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ + auto old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ } while(0) -#elif defined(__APPLE__) && defined(__MACH__) -// MacOS -#define YS_DEBUGTRAP_IF_DEBUGGING { sig_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); } #else # define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) #endif From 0d2c33f9f4f8ca1bb507e3e688e0c7d372f0247b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 10:11:45 -0700 Subject: [PATCH 027/197] tests: update/extend task argument tests --- tests/verilog/bug2042-sv.ys | 34 ++++++++++++++++++++++++++++++++++ tests/verilog/bug2042.ys | 3 +-- 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 tests/verilog/bug2042-sv.ys diff --git a/tests/verilog/bug2042-sv.ys b/tests/verilog/bug2042-sv.ys new file mode 100644 index 000000000..9a0d419c8 --- /dev/null +++ b/tests/verilog/bug2042-sv.ys @@ -0,0 +1,34 @@ +read_verilog -sv < Date: Wed, 13 May 2020 13:33:37 -0700 Subject: [PATCH 028/197] verilog: default to input in sv mode if task/func has no dir ... otherwise error --- frontends/verilog/verilog_parser.y | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index b7c6af91e..f250d7685 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -855,8 +855,16 @@ task_func_port: frontend_verilog_yyerror("task/function argument range must be of the form: [:], [+:], or [-:]"); } wire_name | { - if (!astbuf1) - frontend_verilog_yyerror("Non-ANSI style task/function arguments not currently supported"); + if (!astbuf1) { + if (!sv_mode) + frontend_verilog_yyerror("task/function argument direction missing"); + albuf = new dict; + astbuf1 = new AstNode(AST_WIRE); + current_wire_rand = false; + current_wire_const = false; + astbuf1->is_input = true; + astbuf2 = NULL; + } } wire_name; task_func_body: From 68b31f5e99e25c6bbd77af3d51c44bef88026c2f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 00:19:58 -0700 Subject: [PATCH 029/197] opt_clean: really make 'clean' identical to 'opt_clean' by rminit too --- passes/opt/opt_clean.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 6271376f1..4e8492f7b 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -611,8 +611,7 @@ struct CleanPass : public Pass { } break; } - if (argidx < args.size()) - extra_args(args, argidx, design); + extra_args(args, argidx, design); keep_cache.reset(design); @@ -627,7 +626,7 @@ struct CleanPass : public Pass { for (auto module : design->selected_whole_modules()) { if (module->has_processes()) continue; - rmunused_module(module, purge_mode, ys_debug(), false); + rmunused_module(module, purge_mode, ys_debug(), true); } log_suppressed(); From fc9fb09a91220602538d99bfd08b1d8c34b69558 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 00:24:23 -0700 Subject: [PATCH 030/197] opt_clean: rminit without -purge; also remove if consistent with const.. warn otherwise --- passes/opt/opt_clean.cc | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 4e8492f7b..72ecc30e7 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -412,7 +412,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos return !del_wires_queue.empty(); } -bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) +bool rmunused_module_init(RTLIL::Module *module, bool verbose) { bool did_something = false; CellTypes fftypes; @@ -445,9 +445,6 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) for (auto wire : module->wires()) { - if (!purge_mode && wire->name[0] == '\\') - continue; - if (wire->attributes.count(ID::init) == 0) continue; @@ -464,11 +461,22 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) if (wire_bit == mapped_wire_bit) goto next_wire; - if (qbits.count(sigmap(SigBit(wire, i))) == 0) - goto next_wire; + if (mapped_wire_bit.wire) { + if (qbits.count(mapped_wire_bit) == 0) + goto next_wire; - if (qbits.at(sigmap(SigBit(wire, i))) != init[i]) - goto next_wire; + if (qbits.at(mapped_wire_bit) != init[i]) + goto next_wire; + } + else { + if (mapped_wire_bit == State::Sx || mapped_wire_bit == State::Sz) + goto next_wire; + + if (mapped_wire_bit != init[i]) { + log_warning("Initial value conflict for wire '%s' and value '%s'.\n", log_signal(wire_bit), log_signal(mapped_wire_bit)); + goto next_wire; + } + } } if (verbose) @@ -512,7 +520,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool rmunused_module_cells(module, verbose); while (rmunused_module_signals(module, purge_mode, verbose)) { } - if (rminit && rmunused_module_init(module, purge_mode, verbose)) + if (rminit && rmunused_module_init(module, verbose)) while (rmunused_module_signals(module, purge_mode, verbose)) { } } From aa4a69f89be9fcdcf20ca1c28d67444b994ec479 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 00:26:23 -0700 Subject: [PATCH 031/197] opt_clean: add init test --- tests/opt/opt_clean_init.ys | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/opt/opt_clean_init.ys diff --git a/tests/opt/opt_clean_init.ys b/tests/opt/opt_clean_init.ys new file mode 100644 index 000000000..bfc383955 --- /dev/null +++ b/tests/opt/opt_clean_init.ys @@ -0,0 +1,13 @@ +logger -expect warning "Initial value conflict for wire '\\y' and value '1'0'" 1 +logger -expect-no-warnings +read_verilog < Date: Thu, 14 May 2020 00:59:38 -0700 Subject: [PATCH 032/197] opt_clean: improve warning message --- passes/opt/opt_clean.cc | 2 +- tests/opt/opt_clean_init.ys | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 72ecc30e7..f7de02164 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -473,7 +473,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool verbose) goto next_wire; if (mapped_wire_bit != init[i]) { - log_warning("Initial value conflict for wire '%s' and value '%s'.\n", log_signal(wire_bit), log_signal(mapped_wire_bit)); + log_warning("Initial value conflict for %s resolving to %s but with init %s.\n", log_signal(wire_bit), log_signal(mapped_wire_bit), log_signal(init[i])); goto next_wire; } } diff --git a/tests/opt/opt_clean_init.ys b/tests/opt/opt_clean_init.ys index bfc383955..0d567608d 100644 --- a/tests/opt/opt_clean_init.ys +++ b/tests/opt/opt_clean_init.ys @@ -1,4 +1,4 @@ -logger -expect warning "Initial value conflict for wire '\\y' and value '1'0'" 1 +logger -expect warning "Initial value conflict for \\y resolving to 1'0 but with init 1'1" 1 logger -expect-no-warnings read_verilog < Date: Thu, 14 May 2020 11:11:47 +0200 Subject: [PATCH 033/197] Suppress warning during initial clone of ABC repo 9dedac50 introduced this harmless but disconcerting warning, which was emitted when abc/ did not yet exist and was about to be cloned: /bin/sh: line 0: cd: abc: No such file or directory --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a481dd92b..01821e00e 100644 --- a/Makefile +++ b/Makefile @@ -717,7 +717,7 @@ ifneq ($(ABCREV),default) echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \ fi # set a variable so the test fails if git fails to run - when comparing outputs directly, empty string would match empty string - $(Q) if ! (cd abc && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \ + $(Q) if ! (cd abc 2> /dev/null && rev="`git rev-parse $(ABCREV)`" && test "`git rev-parse HEAD`" == "$$rev"); then \ test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ echo "Pulling ABC from $(ABCURL):"; set -x; \ test -d abc || git clone $(ABCURL) abc; \ From 173aa27ca5ef6e7c0a9277e8da7765adcd63bfe9 Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Thu, 14 May 2020 14:38:13 +0200 Subject: [PATCH 034/197] Add support for non-power-of-two mem chunks in verific importer Signed-off-by: Claire Wolf --- frontends/verific/verific.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index fe4bda68e..5f8a78e48 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1265,7 +1265,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->OutputSize()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0) + if ((numchunks * memory->width) != int(inst->OutputSize())) log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); for (int i = 0; i < numchunks; i++) @@ -1273,6 +1273,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec data = operatorOutput(inst).extract(i * memory->width, memory->width); + if ((numchunks & (numchunks - 1)) != 0) { + addr = module->Mul(NEW_ID, operatorInput1(inst), RTLIL::Const(numchunks)); + addr = module->Add(NEW_ID, addr, RTLIL::Const(i)); + } + RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), ID($memrd)); cell->parameters[ID::MEMID] = memory->name.str(); @@ -1295,7 +1300,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->Input2Size()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0) + if ((numchunks * memory->width) != int(inst->Input2Size())) log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name()); for (int i = 0; i < numchunks; i++) @@ -1303,6 +1308,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width); + if ((numchunks & (numchunks - 1)) != 0) { + addr = module->Mul(NEW_ID, operatorInput1(inst), RTLIL::Const(numchunks)); + addr = module->Add(NEW_ID, addr, RTLIL::Const(i)); + } + RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), ID($memwr)); cell->parameters[ID::MEMID] = memory->name.str(); From 56a5b1d2daf1b244990d81f32183034071ebd185 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 08:36:36 -0700 Subject: [PATCH 035/197] test: add another testcase as per @nakengelhardt --- tests/verilog/bug2042-sv.ys | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/verilog/bug2042-sv.ys b/tests/verilog/bug2042-sv.ys index 9a0d419c8..e815d7fc5 100644 --- a/tests/verilog/bug2042-sv.ys +++ b/tests/verilog/bug2042-sv.ys @@ -20,6 +20,31 @@ proc sat -verify -prove-asserts +design -reset +read_verilog -sv < Date: Thu, 14 May 2020 09:51:17 -0700 Subject: [PATCH 036/197] Fix whitespace --- passes/opt/opt_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 9a8bc0869..b484b9776 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -2046,7 +2046,7 @@ struct OptExprPass : public Pass { design->scratchpad_set_bool("opt.did_something", true); } while (did_something); if (!keepdc) - replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv); + replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, clkinv); if (did_something) design->scratchpad_set_bool("opt.did_something", true); } while (did_something); From 299ab76a093f0cde95fdc0214b371140d7f339b9 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Thu, 14 May 2020 17:07:59 +0000 Subject: [PATCH 037/197] smtbmc: Fix return status handling. --- backends/smt2/smtbmc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index d3015b066..f1f55be1c 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1548,7 +1548,7 @@ else: # not tempind, covermode break smt_pop() - if not retstatus: + if retstatus == "FAILED" or retstatus == "PREUNSAT": break else: # gentrace @@ -1568,7 +1568,7 @@ else: # not tempind, covermode step += step_size - if gentrace and retstatus: + if gentrace and retstatus == "PASSED": print_anyconsts(0) write_trace(0, num_steps, '%') From 65395168a08c07eff4e49996f4eae4d5a422e586 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 11 May 2020 10:01:29 -0700 Subject: [PATCH 038/197] logger: fix for multiple calls with same pattern --- passes/cmds/logger.cc | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 9a27952d4..64f939525 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -158,12 +158,40 @@ struct LoggerPass : public Pass { log_cmd_error("Expected error message occurrences must be 1 !\n"); log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str()); try { - if (type=="error") - log_expect_error.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); - else if (type=="warning") - log_expect_warning.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); - else - log_expect_log.push_back(std::make_pair(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count))); + if (type=="error") { + auto it = log_expect_error.begin(); + auto ie = log_expect_error.end(); + for (; it != ie; it++) + if (it->second.pattern == pattern) { + it->second.expected_count = count; + break; + } + if (it == ie) + log_expect_error.emplace_back(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)); + } + else if (type=="warning") { + auto it = log_expect_warning.begin(); + auto ie = log_expect_warning.end(); + for (; it != ie; it++) + if (it->second.pattern == pattern) { + it->second.expected_count = count; + break; + } + if (it == ie) + log_expect_warning.emplace_back(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)); + } + else if (type=="log") { + auto it = log_expect_log.begin(); + auto ie = log_expect_log.end(); + for (; it != ie; it++) + if (it->second.pattern == pattern) { + it->second.expected_count = count; + break; + } + if (it == ie) + log_expect_log.emplace_back(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)); + } + else log_abort(); } catch (const YS_REGEX_NS::regex_error& e) { log_cmd_error("Error in regex expression '%s' !\n", pattern.c_str()); From ffa52738fba1264ef2eb37d5333babfa0758fe48 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 9 Apr 2020 14:26:52 -0700 Subject: [PATCH 039/197] xaiger: output $_DFF_[NP]_ with mergeability if -dff option --- backends/aiger/xaiger.cc | 86 ++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 1fb7210cb..d014c4ec6 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -137,7 +137,7 @@ struct XAigerWriter return a; } - XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module) + XAigerWriter(Module *module, bool dff_mode, bool holes_mode=false) : module(module), sigmap(module) { pool undriven_bits; pool unused_bits; @@ -212,10 +212,7 @@ struct XAigerWriter continue; } - if (cell->type == ID($__ABC9_FF_) && - // The presence of an abc9_mergeability attribute indicates - // that we do want to pass this flop to ABC - cell->attributes.count(ID::abc9_mergeability)) + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { SigBit D = sigmap(cell->getPort(ID::D).as_bit()); SigBit Q = sigmap(cell->getPort(ID::Q).as_bit()); @@ -233,7 +230,11 @@ struct XAigerWriter RTLIL::Module* inst_module = module->design->module(cell->type); if (inst_module) { - IdString derived_type = inst_module->derive(module->design, cell->parameters); + IdString derived_type; + if (cell->parameters.empty()) + derived_type = cell->type; + else + derived_type = inst_module->derive(module->design, cell->parameters); inst_module = module->design->module(derived_type); log_assert(inst_module); @@ -319,7 +320,7 @@ struct XAigerWriter RTLIL::Module* box_module = module->design->module(cell->type); log_assert(box_module); - log_assert(box_module->attributes.count(ID::abc9_box_id) || box_module->get_bool_attribute(ID::abc9_flop)); + log_assert(box_module->attributes.count(ID::abc9_box_id)); auto r = box_ports.insert(cell->type); if (r.second) { @@ -383,27 +384,6 @@ struct XAigerWriter undriven_bits.erase(O); } } - - // Connect .abc9_ff.Q (inserted by abc9_map.v) as the last input to the flop box - if (box_module->get_bool_attribute(ID::abc9_flop)) { - SigSpec rhs = module->wire(stringf("%s.abc9_ff.Q", cell->name.c_str())); - if (rhs.empty()) - log_error("'%s.abc9_ff.Q' is not a wire present in module '%s'.\n", log_id(cell), log_id(module)); - - for (auto b : rhs) { - SigBit I = sigmap(b); - if (b == RTLIL::Sx) - b = State::S0; - else if (I != b) { - if (I == RTLIL::Sx) - alias_map[b] = State::S0; - else - alias_map[b] = I; - } - co_bits.emplace_back(b); - unused_bits.erase(I); - } - } } for (auto bit : input_bits) @@ -593,7 +573,11 @@ struct XAigerWriter RTLIL::Module* box_module = module->design->module(cell->type); log_assert(box_module); - IdString derived_type = box_module->derive(box_module->design, cell->parameters); + IdString derived_type; + if (cell->parameters.empty()) + derived_type = cell->type; + else + derived_type = box_module->derive(module->design, cell->parameters); box_module = box_module->design->module(derived_type); log_assert(box_module); @@ -610,11 +594,6 @@ struct XAigerWriter box_outputs += GetSize(w); } - // For flops only, create an extra 1-bit input that drives a new wire - // called ".abc9_ff.Q" that is used below - if (box_module->get_bool_attribute(ID::abc9_flop)) - box_inputs++; - std::get<0>(v) = box_inputs; std::get<1>(v) = box_outputs; std::get<2>(v) = box_module->attributes.at(ID::abc9_box_id).as_int(); @@ -635,18 +614,34 @@ struct XAigerWriter auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1); write_s_buffer(ff_bits.size()); + dict clk_to_mergeability; + + bool nonzero_warned = false; for (const auto &i : ff_bits) { const SigBit &d = i.first; const Cell *cell = i.second; - int mergeability = cell->attributes.at(ID::abc9_mergeability).as_int(); + log_assert(cell->type.in(ID($_DFF_N_), ID($_DFF_P_))); + + SigBit clock = sigmap(cell->getPort(ID::C)); + auto r = clk_to_mergeability.insert(std::make_pair(clock, clk_to_mergeability.size() + 1)); + int mergeability = r.first->second; log_assert(mergeability > 0); - write_r_buffer(mergeability); + if (cell->type == ID($_DFF_N_)) + write_r_buffer(-mergeability); + else if (cell->type == ID($_DFF_P_)) + write_r_buffer(mergeability); + else log_abort(); Const init = cell->attributes.at(ID::abc9_init, State::Sx); log_assert(GetSize(init) == 1); - if (init == State::S1) + if (init == State::S1) { + if (!nonzero_warned) { + log_warning("Module '%s' contains $_DFF_[NP]_ cell with non-zero initial state -- unsupported by ABC9.\n", log_id(module)); + nonzero_warned = true; + } write_s_buffer(1); + } else if (init == State::S0) write_s_buffer(0); else { @@ -674,7 +669,7 @@ struct XAigerWriter RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); if (holes_module) { std::stringstream a_buffer; - XAigerWriter writer(holes_module, true /* holes_mode */); + XAigerWriter writer(holes_module, false /* dff_mode */, true /* holes_mode */); writer.write_aiger(a_buffer, false /*ascii_mode*/); f << "a"; @@ -761,8 +756,8 @@ struct XAigerBackend : public Backend { log(" write_xaiger [options] [filename]\n"); log("\n"); log("Write the top module (according to the (* top *) attribute or if only one module\n"); - log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, or"); - log("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n"); + log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_DFF_N_,\n"); + log(" $_DFF_P_, or non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n"); log("pseudo-outputs. Whitebox contents will be taken from the '$holes'\n"); log("module, if it exists.\n"); log("\n"); @@ -772,10 +767,13 @@ struct XAigerBackend : public Backend { log(" -map \n"); log(" write an extra file with port and box symbols\n"); log("\n"); + log(" -dff\n"); + log(" write $_DFF_[NP]_ cells\n"); + log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE { - bool ascii_mode = false; + bool ascii_mode = false, dff_mode = false; std::string map_filename; log_header(design, "Executing XAIGER backend.\n"); @@ -791,6 +789,10 @@ struct XAigerBackend : public Backend { map_filename = args[++argidx]; continue; } + if (args[argidx] == "-dff") { + dff_mode = true; + continue; + } break; } extra_args(f, filename, args, argidx, !ascii_mode); @@ -808,7 +810,7 @@ struct XAigerBackend : public Backend { if (!top_module->memories.empty()) log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module)); - XAigerWriter writer(top_module); + XAigerWriter writer(top_module, dff_mode); writer.write_aiger(*f, ascii_mode); if (!map_filename.empty()) { From 53fc3ed64563045949bcd52a03d2af586605d523 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 9 Apr 2020 14:31:14 -0700 Subject: [PATCH 040/197] aiger: -xaiger to read $_DFF_[NP]_ back with new clocks created according to mergeability class, and init state as cell attr --- frontends/aiger/aigerparse.cc | 25 +++++++++++++++++++++++-- frontends/aiger/aigerparse.h | 2 +- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 6fda92d73..7e5e6dd2d 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -454,6 +454,14 @@ void AigerReader::parse_xaiger() for (unsigned i = 0; i < flopNum; i++) mergeability.emplace_back(parse_xaiger_literal(f)); } + else if (c == 's') { + uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + flopNum = parse_xaiger_literal(f); + log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); + initial_state.reserve(flopNum); + for (unsigned i = 0; i < flopNum; i++) + initial_state.emplace_back(parse_xaiger_literal(f)); + } else if (c == 'n') { parse_xaiger_literal(f); f >> s; @@ -767,6 +775,7 @@ void AigerReader::post_process() } } + dict mergeability_to_clock; for (uint32_t i = 0; i < flopNum; i++) { RTLIL::Wire *d = outputs[outputs.size() - flopNum + i]; log_assert(d); @@ -778,10 +787,22 @@ void AigerReader::post_process() log_assert(q->port_input); q->port_input = false; - auto ff = module->addCell(NEW_ID, ID($__ABC9_FF_)); + Cell* ff; + int clock_index = mergeability[i]; + if (clock_index < 0) { + ff = module->addCell(NEW_ID, ID($_DFF_N_)); + clock_index = -clock_index; + } + else if (clock_index > 0) + ff = module->addCell(NEW_ID, ID($_DFF_P_)); + else log_abort(); + auto r = mergeability_to_clock.insert(clock_index); + if (r.second) + r.first->second = module->addWire(NEW_ID); + ff->setPort(ID::C, r.first->second); ff->setPort(ID::D, d); ff->setPort(ID::Q, q); - ff->attributes[ID::abc9_mergeability] = mergeability[i]; + ff->attributes[ID::abc9_init] = initial_state[i]; } dict> wideports_cache; diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h index 46ac81212..251a24977 100644 --- a/frontends/aiger/aigerparse.h +++ b/frontends/aiger/aigerparse.h @@ -45,7 +45,7 @@ struct AigerReader std::vector outputs; std::vector bad_properties; std::vector boxes; - std::vector mergeability; + std::vector mergeability, initial_state; AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); void parse_aiger(); From accfc70fc2bcfaa5f9f58e8a113a32e506f5081d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 9 Apr 2020 14:42:43 -0700 Subject: [PATCH 041/197] abc9: fix behaviour and help for -box option --- passes/techmap/abc9.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 1b3d5ff06..d8f2f0357 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -303,7 +303,7 @@ struct Abc9Pass : public ScriptPass if (help_mode) { run("foreach module in selection"); run(" abc9_ops -write_lut /input.lut", "(skip if '-lut' or '-luts')"); - run(" abc9_ops -write_box /input.box"); + run(" abc9_ops -write_box /input.box", "(skip if '-box')"); run(" write_xaiger -map /input.sym /input.xaig"); run(" abc9_exe [options] -cwd [-lut /input.lut] -box /input.box"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); @@ -333,7 +333,8 @@ struct Abc9Pass : public ScriptPass if (!lut_mode) run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str())); - run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); + if (box_file.empty()) + run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); @@ -349,7 +350,10 @@ struct Abc9Pass : public ScriptPass abc9_exe_cmd += stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str()); if (!lut_mode) abc9_exe_cmd += stringf(" -lut %s/input.lut", tempdir_name.c_str()); - abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); + if (box_file.empty()) + abc9_exe_cmd += stringf(" -box %s/input.box", tempdir_name.c_str()); + else + abc9_exe_cmd += stringf(" -box %s", box_file.c_str()); run_nocheck(abc9_exe_cmd); run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); run_nocheck("abc9_ops -reintegrate"); From 95763c8d18eec49de3acff5d38a82f54cc25cb1b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 09:38:07 -0700 Subject: [PATCH 042/197] abc9_ops: add 'dff' label for auto handling of (* abc9_flop *) boxes --- backends/aiger/xaiger.cc | 10 +- passes/hierarchy/submod.cc | 2 +- passes/techmap/abc9.cc | 89 ++++- passes/techmap/abc9_ops.cc | 568 ++++++++++++++++++-------------- techlibs/common/abc9_model.v | 3 - techlibs/xilinx/abc9_map.v | 354 -------------------- techlibs/xilinx/abc9_unmap.v | 4 - techlibs/xilinx/cells_sim.v | 8 +- techlibs/xilinx/synth_xilinx.cc | 5 +- 9 files changed, 403 insertions(+), 640 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index d014c4ec6..2e2ca7018 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -616,7 +616,6 @@ struct XAigerWriter dict clk_to_mergeability; - bool nonzero_warned = false; for (const auto &i : ff_bits) { const SigBit &d = i.first; const Cell *cell = i.second; @@ -633,15 +632,10 @@ struct XAigerWriter write_r_buffer(mergeability); else log_abort(); - Const init = cell->attributes.at(ID::abc9_init, State::Sx); + Const init = cell->attributes.at(ID::abc9_init); log_assert(GetSize(init) == 1); - if (init == State::S1) { - if (!nonzero_warned) { - log_warning("Module '%s' contains $_DFF_[NP]_ cell with non-zero initial state -- unsupported by ABC9.\n", log_id(module)); - nonzero_warned = true; - } + if (init == State::S1) write_s_buffer(1); - } else if (init == State::S0) write_s_buffer(0); else { diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc index 2db7cf26b..1f30a5160 100644 --- a/passes/hierarchy/submod.cc +++ b/passes/hierarchy/submod.cc @@ -389,7 +389,7 @@ struct SubmodPass : public Pass { while (did_something) { did_something = false; std::vector queued_modules; - for (auto mod : design->modules()) + for (auto mod : design->selected_modules()) if (handled_modules.count(mod->name) == 0 && design->selected_whole_module(mod->name)) queued_modules.push_back(mod->name); for (auto &modname : queued_modules) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index d8f2f0357..7f3e6abcc 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -151,8 +151,8 @@ struct Abc9Pass : public ScriptPass log(" specified).\n"); log("\n"); log(" -dff\n"); - log(" also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n"); - log(" domains are marked as such and automatically partitioned by ABC.\n"); + log(" also pass $_DFF_[NP]_ cells through to ABC. modules with many clock\n"); + log(" domains are supported and automatically partitioned by ABC.\n"); log("\n"); log(" -nocleanup\n"); log(" when this option is used, the temporary files created by this pass\n"); @@ -274,26 +274,74 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { - if (check_label("pre")) { + if (check_label("check")) { run("abc9_ops -check"); + } + + if (check_label("dff", "(only if -dff)")) { + if (dff_mode || help_mode) { + run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules + run("design -stash $abc9"); + run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in + run("proc"); + run("wbflip"); + run("techmap"); + run("opt"); + run("abc9_ops -prep_dff_map"); // rewrite specify + // TODO: Select fan-in cone $_DFF_[NP]_.Q + run("setattr -set submod \"$abc9_flop\" t:* t:$_DFF_N_ %d t:$_DFF_P_ %d"); + run("submod"); + run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out + run("delete *_$abc9_flop"); + if (help_mode) { + run("foreach module in design"); + run(" cd "); + run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + run(" cd"); + } + else { + // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs + for (auto module : active_design->selected_modules()) { + run(stringf("cd %s", log_id(module->name))); + run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); + run("cd"); + } + } + run("design -stash $abc9_map"); + run("design -load $abc9"); + run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design + run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); + if (!help_mode) { + // TODO: Need a way to delete saved designs? + auto it = saved_designs.find("$abc9_map"); + delete it->second; + saved_designs.erase(it); + // TODO: Need a way to delete selections + active_design->selection_vars.erase(ID($abc9_flops)); + active_design->selection_vars.erase(ID($abc9_cells)); + } + } + } + + if (check_label("pre")) { run("scc -set_attr abc9_scc_id {}"); if (help_mode) run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); else - run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); + run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : "")); if (help_mode) run("abc9_ops -prep_lut ", "(skip if -lut or -luts)"); else if (!lut_mode) run(stringf("abc9_ops -prep_lut %d", maxlut)); if (help_mode) - run("abc9_ops -prep_box [-dff]", "(skip if -box)"); - else if (box_file.empty()) - run(stringf("abc9_ops -prep_box %s", dff_mode ? "-dff" : "")); + run("abc9_ops -prep_box", "(skip if -box)"); + else if (box_file.empty()) { + run("abc9_ops -prep_box"); + } run("select -set abc9_holes A:abc9_holes"); run("flatten -wb @abc9_holes"); run("techmap @abc9_holes"); - if (dff_mode || help_mode) - run("abc9_ops -prep_dff", "(only if -dff)"); run("opt -purge @abc9_holes"); run("aigmap"); run("wbflip @abc9_holes"); @@ -304,10 +352,10 @@ struct Abc9Pass : public ScriptPass run("foreach module in selection"); run(" abc9_ops -write_lut /input.lut", "(skip if '-lut' or '-luts')"); run(" abc9_ops -write_box /input.box", "(skip if '-box')"); - run(" write_xaiger -map /input.sym /input.xaig"); - run(" abc9_exe [options] -cwd [-lut /input.lut] -box /input.box"); + run(" write_xaiger -map /input.sym [-dff] /input.xaig"); + run(" abc9_exe [options] -cwd -lut [/input.lut] -box [/input.box]"); run(" read_aiger -xaiger -wideports -module_name $abc9 -map /input.sym /output.aig"); - run(" abc9_ops -reintegrate"); + run(" abc9_ops -reintegrate [-dff]"); } else { auto selected_modules = active_design->selected_modules(); @@ -335,7 +383,7 @@ struct Abc9Pass : public ScriptPass run_nocheck(stringf("abc9_ops -write_lut %s/input.lut", tempdir_name.c_str())); if (box_file.empty()) run_nocheck(stringf("abc9_ops -write_box %s/input.box", tempdir_name.c_str())); - run_nocheck(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); + run_nocheck(stringf("write_xaiger -map %s/input.sym %s %s/input.xaig", tempdir_name.c_str(), dff_mode ? "-dff" : "", tempdir_name.c_str())); int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); @@ -356,7 +404,7 @@ struct Abc9Pass : public ScriptPass abc9_exe_cmd += stringf(" -box %s", box_file.c_str()); run_nocheck(abc9_exe_cmd); run_nocheck(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod), tempdir_name.c_str(), tempdir_name.c_str())); - run_nocheck("abc9_ops -reintegrate"); + run_nocheck(stringf("abc9_ops -reintegrate %s", dff_mode ? "-dff" : "")); } else log("Don't call ABC as there is nothing to map.\n"); @@ -373,6 +421,19 @@ struct Abc9Pass : public ScriptPass active_design->selection_stack.pop_back(); } } + + if (check_label("post")) { + if (dff_mode || help_mode) { + run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell + // ($_DFF_[NP]_ already shorted by -reintegrate) + if (!help_mode) { + // TODO: Need a way to delete saved designs? + auto it = saved_designs.find("$abc9_unmap"); + delete it->second; + saved_designs.erase(it); + } + } + } } } Abc9Pass; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 1345188a4..fe2e5c3ac 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -119,83 +119,129 @@ void mark_scc(RTLIL::Module *module) } } -void prep_dff(RTLIL::Module *module) + +void prep_dff_hier(RTLIL::Design *design) { - auto design = module->design; - log_assert(design); + pool seen; + dict selection_vars; + auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); + log_assert(r.second); + auto r2 YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_cells), RTLIL::Selection(false))); + log_assert(r2.second); + auto &modules_sel = design->selection_vars.at(ID($abc9_flops)); + auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); - SigMap assign_map(module); - - typedef SigSpec clkdomain_t; - dict clk_to_mergeability; - - for (auto cell : module->cells()) { - if (cell->type != ID($__ABC9_FF_)) - continue; - - Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str())); - if (abc9_clock_wire == NULL) - log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - SigSpec abc9_clock = assign_map(abc9_clock_wire); - - clkdomain_t key(abc9_clock); - - auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); - auto r2 = cell->attributes.insert(ID::abc9_mergeability); - log_assert(r2.second); - r2.first->second = r.first->second; - } - - RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); - if (holes_module) { - SigMap sigmap(holes_module); - - dict replace; - for (auto cell : holes_module->cells().to_vector()) { - if (!cell->type.in(ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), - ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1), ID($_DFF_PP0_), ID($_DFF_PP1_))) - continue; - SigBit D = cell->getPort(ID::D); - SigBit Q = cell->getPort(ID::Q); - // Emulate async control embedded inside $_DFF_* cell with mux in front of D - if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_PN0_))) - D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NN1_), ID($_DFF_PN1_))) - D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NP0_), ID($_DFF_PP0_))) - D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort(ID::R)); - else if (cell->type.in(ID($_DFF_NP1_), ID($_DFF_PP1_))) - D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort(ID::R)); - // Remove the $_DFF_* cell from what needs to be a combinatorial box - holes_module->remove(cell); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); - else - port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); - log_assert(port); - // Prepare to replace "assign = $_DFF_*.Q;" with "assign = $_DFF_*.D;" - // in order to extract just the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(Q,D)); - // Since `flatten` above would have created wires named ".Q", - // extract the pre-techmap cell name - auto pos = Q.wire->name.str().rfind("."); - log_assert(pos != std::string::npos); - IdString driver = Q.wire->name.substr(0, pos); - // And drive the signal that was previously driven by "DFF.Q" (typically - // used to implement clock-enable functionality) with the ".$abc9_currQ" - // wire (which itself is driven an by input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (inst_module && inst_module->get_bool_attribute(ID::abc9_flop)) { + modules_sel.select(inst_module); + // Derive modules for all instantiations of (* abc9_flop *) + auto derived_type = inst_module->derive(design, cell->parameters); + // And remember one representative cell (for its parameters) + if (modules_sel.selected_modules.insert(derived_type).second) + cells_sel.select(module, cell); + } } +} - for (auto &conn : holes_module->connections_) - conn.second = replace.at(sigmap(conn.second), conn.second); +void prep_dff_map(RTLIL::Design *design) +{ + for (auto module : design->modules()) { + vector specify_cells; + SigBit D, Q; + for (auto cell : module->cells()) + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + if (D != SigBit()) + log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + D = cell->getPort(ID::D); + Q = cell->getPort(ID::Q); + + // TODO: Can we avoid doing this? + // Convert (* init *) on $_DFF_[NP]_.Q to (* abc9_init *) attr on cell + log_assert(GetSize(Q.wire) == 1); + auto it = Q.wire->attributes.find(ID::init); + Const init; + if (it != Q.wire->attributes.end()) { + log_assert(GetSize(it->second) == 1); + init = it->second; + Q.wire->attributes.erase(it); + } + else + init = State::Sx; + auto r YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID::abc9_init, init)); + log_assert(r.second); + if (init == State::S1) { + log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); + + module->makeblackbox(); + + auto wire = module->addWire(ID(_TECHMAP_FAIL_)); + wire->set_bool_attribute(ID::keep); + module->connect(wire, State::S1); + + goto continue_outer_loop; + } + } + else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) + specify_cells.emplace_back(cell); + if (D == SigBit()) + log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); + } +continue_outer_loop: ; } } +void prep_dff_unmap(RTLIL::Design *design) +{ + dict derived_to_cell; + const auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); + for (auto &i : cells_sel.selected_members) { + auto module = design->module(i.first); + for (auto cell_name : i.second) { + auto cell = module->cell(cell_name); + log_assert(cell); + auto inst_module = design->module(cell->type); + log_assert(inst_module); + auto derived_type = inst_module->derive(design, cell->parameters); + derived_to_cell.insert(std::make_pair(derived_type, cell)); + } + } + + Design *unmap_design = new Design; + + // Create the reverse techmap rule -- (* abc9_box *) back to flop + for (const auto &i : derived_to_cell) { + auto module_name = i.first; + auto flop_module = design->module(module_name.str() + "_$abc9_flop"); + if (!flop_module) + continue; // May not exist if init = 1'b1 + + auto unmap_module = unmap_design->addModule(flop_module->name); + for (auto port : flop_module->ports) + unmap_module->addWire(port, flop_module->wire(port)); + unmap_module->ports = flop_module->ports; + unmap_module->check(); + + auto orig_cell = i.second; + auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, orig_cell->type); + for (const auto &conn : orig_cell->connections()) + unmap_cell->setPort(conn.first, unmap_module->wire(conn.first)); + unmap_cell->parameters = orig_cell->parameters; + } + + auto r YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); + log_assert(r.second); +} + void prep_xaiger(RTLIL::Module *module, bool dff) { auto design = module->design; @@ -208,17 +254,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff) dict> box_ports; for (auto cell : module->cells()) { - if (cell->type == ID($__ABC9_FF_)) + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) continue; if (cell->has_keep_attr()) continue; - auto inst_module = module->design->module(cell->type); + auto inst_module = design->module(cell->type); bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop); if (abc9_flop && !dff) continue; - if ((inst_module && inst_module->get_bool_attribute(ID::abc9_box)) || abc9_flop) { + if (inst_module && inst_module->get_bool_attribute(ID::abc9_box)) { auto r = box_ports.insert(cell->type); if (r.second) { // Make carry in the last PI, and carry out the last PO @@ -305,15 +351,16 @@ void prep_xaiger(RTLIL::Module *module, bool dff) cell->attributes[ID::abc9_box_seq] = box_count++; - IdString derived_type = box_module->derive(design, cell->parameters); + IdString derived_type; + if (cell->parameters.empty()) + derived_type = cell->type; + else + derived_type = box_module->derive(design, cell->parameters); box_module = design->module(derived_type); auto r = cell_cache.insert(derived_type); auto &holes_cell = r.first->second; if (r.second) { - if (box_module->has_processes()) - Pass::call_on_module(design, box_module, "proc"); - if (box_module->get_bool_attribute(ID::whitebox)) { holes_cell = holes_module->addCell(cell->name, derived_type); @@ -342,21 +389,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) else if (w->port_output) conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); } - - // For flops only, create an extra 1-bit input that drives a new wire - // called ".abc9_ff.Q" that is used below - if (box_module->get_bool_attribute(ID::abc9_flop)) { - box_inputs++; - Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); - if (!holes_wire) { - holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); - holes_wire->port_input = true; - holes_wire->port_id = port_id++; - holes_module->ports.push_back(holes_wire->name); - } - Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str())); - holes_module->connect(Q, holes_wire); - } } else // box_module is a blackbox log_assert(holes_cell == nullptr); @@ -394,7 +426,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) } for (auto cell : module->cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) continue; RTLIL::Module* inst_module = module->design->module(cell->type); @@ -540,7 +572,7 @@ void write_lut(RTLIL::Module *module, const std::string &dst) { ofs.close(); } -void prep_box(RTLIL::Design *design, bool dff_mode) +void prep_box(RTLIL::Design *design) { TimingInfo timing; @@ -555,165 +587,153 @@ void prep_box(RTLIL::Design *design, bool dff_mode) dict> box_ports; for (auto module : design->modules()) { - auto abc9_flop = module->get_bool_attribute(ID::abc9_flop); - if (abc9_flop) { - auto r = module->attributes.insert(ID::abc9_box_id); - if (!r.second) - continue; - r.first->second = abc9_box_id++; + if (!module->attributes.erase(ID::abc9_box)) + continue; - if (dff_mode) { - int num_inputs = 0, num_outputs = 0; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - log_assert(GetSize(wire) == 1); - if (wire->port_input) num_inputs++; - if (wire->port_output) num_outputs++; - } - log_assert(num_outputs == 1); + auto r = module->attributes.insert(ID::abc9_box_id); + if (!r.second) + continue; + r.first->second = abc9_box_id++; - ss << log_id(module) << " " << r.first->second.as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); - ss << " " << num_inputs+1 << " " << num_outputs << std::endl; + if (module->get_bool_attribute(ID::abc9_flop)) { + int num_inputs = 0, num_outputs = 0; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + log_assert(GetSize(wire) == 1); + if (wire->port_input) num_inputs++; + if (wire->port_output) num_outputs++; + } + log_assert(num_outputs == 1); - ss << "#"; - bool first = true; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - if (!wire->port_input) - continue; - if (first) - first = false; - else - ss << " "; - ss << log_id(wire); - } - ss << " abc9_ff.Q" << std::endl; + ss << log_id(module) << " " << r.first->second.as_int(); + ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + ss << " " << num_inputs << " " << num_outputs << std::endl; - auto &t = timing.setup_module(module).required; - first = true; - for (auto port_name : module->ports) { - auto wire = module->wire(port_name); - if (!wire->port_input) - continue; - if (first) - first = false; - else - ss << " "; - log_assert(GetSize(wire) == 1); - auto it = t.find(TimingInfo::NameBit(port_name,0)); - if (it == t.end()) - // Assume that no setup time means zero - ss << 0; - else { - ss << it->second; + ss << "#"; + bool first = true; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + ss << log_id(wire); + } + ss << std::endl; + + auto &t = timing.setup_module(module).required; + first = true; + for (auto port_name : module->ports) { + auto wire = module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + log_assert(GetSize(wire) == 1); + auto it = t.find(TimingInfo::NameBit(port_name,0)); + if (it == t.end()) + // Assume that no setup time means zero + ss << 0; + else { + ss << it->second; #ifndef NDEBUG - if (ys_debug(1)) { - static std::set> seen; - if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module), - log_id(port_name), it->second); - } -#endif + if (ys_debug(1)) { + static std::set> seen; + if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module), + log_id(port_name), it->second); } - +#endif } - // Last input is 'abc9_ff.Q' - ss << " 0" << std::endl << std::endl; - continue; } + ss << " # $_DFF_[NP]_.D" << std::endl; + ss << std::endl; } else { - if (!module->attributes.erase(ID::abc9_box)) - continue; - - auto r = module->attributes.insert(ID::abc9_box_id); - if (!r.second) - continue; - r.first->second = abc9_box_id++; - } - - auto r = box_ports.insert(module->name); - if (r.second) { - // Make carry in the last PI, and carry out the last PO - // since ABC requires it this way - IdString carry_in, carry_out; - for (const auto &port_name : module->ports) { - auto w = module->wire(port_name); - log_assert(w); - if (w->get_bool_attribute(ID::abc9_carry)) { - log_assert(w->port_input != w->port_output); - if (w->port_input) - carry_in = port_name; - else if (w->port_output) - carry_out = port_name; + auto r2 = box_ports.insert(module->name); + if (r2.second) { + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : module->ports) { + auto w = module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute(ID::abc9_carry)) { + log_assert(w->port_input != w->port_output); + if (w->port_input) + carry_in = port_name; + else if (w->port_output) + carry_out = port_name; + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); } - else - r.first->second.push_back(port_name); } - if (carry_in != IdString()) { - r.first->second.push_back(carry_in); - r.first->second.push_back(carry_out); + std::vector inputs, outputs; + for (auto port_name : r2.first->second) { + auto wire = module->wire(port_name); + if (wire->port_input) + for (int i = 0; i < GetSize(wire); i++) + inputs.emplace_back(wire, i); + if (wire->port_output) + for (int i = 0; i < GetSize(wire); i++) + outputs.emplace_back(wire, i); } - } - std::vector inputs; - std::vector outputs; - for (auto port_name : r.first->second) { - auto wire = module->wire(port_name); - if (wire->port_input) - for (int i = 0; i < GetSize(wire); i++) - inputs.emplace_back(wire, i); - if (wire->port_output) - for (int i = 0; i < GetSize(wire); i++) - outputs.emplace_back(wire, i); - } + ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int(); + ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl; - ss << log_id(module) << " " << module->attributes.at(ID::abc9_box_id).as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); - ss << " " << GetSize(inputs) << " " << GetSize(outputs) << std::endl; - - bool first = true; - ss << "#"; - for (const auto &i : inputs) { - if (first) - first = false; - else - ss << " "; - if (GetSize(i.wire) == 1) - ss << log_id(i.wire); - else - ss << log_id(i.wire) << "[" << i.offset << "]"; - } - ss << std::endl; - - auto &t = timing.setup_module(module).comb; - if (!abc9_flop && t.empty()) - log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module)); - - for (const auto &o : outputs) { - first = true; + bool first = true; + ss << "#"; for (const auto &i : inputs) { if (first) first = false; else ss << " "; - auto jt = t.find(TimingInfo::BitBit(i,o)); - if (jt == t.end()) - ss << "-"; + if (GetSize(i.wire) == 1) + ss << log_id(i.wire); else - ss << jt->second; + ss << log_id(i.wire) << "[" << i.offset << "]"; } - ss << " # "; - if (GetSize(o.wire) == 1) - ss << log_id(o.wire); - else - ss << log_id(o.wire) << "[" << o.offset << "]"; ss << std::endl; + auto &t = timing.setup_module(module).comb; + if (t.empty()) + log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module)); + + for (const auto &o : outputs) { + first = true; + for (const auto &i : inputs) { + if (first) + first = false; + else + ss << " "; + auto jt = t.find(TimingInfo::BitBit(i,o)); + if (jt == t.end()) + ss << "-"; + else + ss << jt->second; + } + ss << " # "; + if (GetSize(o.wire) == 1) + ss << log_id(o.wire); + else + ss << log_id(o.wire) << "[" << o.offset << "]"; + ss << std::endl; + } + ss << std::endl; } - ss << std::endl; } // ABC expects at least one box @@ -730,7 +750,7 @@ void write_box(RTLIL::Module *module, const std::string &dst) { ofs.close(); } -void reintegrate(RTLIL::Module *module) +void reintegrate(RTLIL::Module *module, bool dff_mode) { auto design = module->design; log_assert(design); @@ -783,7 +803,12 @@ void reintegrate(RTLIL::Module *module) for (auto cell : module->cells().to_vector()) { if (cell->has_keep_attr()) continue; - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); + module->remove(cell); + } + else if (cell->type.in(ID($_AND_), ID($_NOT_))) module->remove(cell); else if (cell->attributes.erase(ID::abc9_box_seq)) boxes.emplace_back(cell); @@ -797,6 +822,16 @@ void reintegrate(RTLIL::Module *module) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + SigBit D = mapped_cell->getPort(ID::D); + SigBit Q = mapped_cell->getPort(ID::Q); + if (D.wire) + D.wire = module->wires_.at(remap_name(D.wire->name)); + Q.wire = module->wires_.at(remap_name(Q.wire->name)); + module->connect(Q, D); + continue; + } + // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); @@ -846,7 +881,7 @@ void reintegrate(RTLIL::Module *module) continue; } - if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { + if (mapped_cell->type == ID($lut)) { RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = mapped_cell->parameters; cell->attributes = mapped_cell->attributes; @@ -893,7 +928,11 @@ void reintegrate(RTLIL::Module *module) } RTLIL::Module* box_module = design->module(existing_cell->type); - IdString derived_type = box_module->derive(design, existing_cell->parameters); + IdString derived_type; + if (existing_cell->parameters.empty()) + derived_type = existing_cell->type; + else + derived_type = box_module->derive(design, existing_cell->parameters); RTLIL::Module* derived_module = design->module(derived_type); log_assert(derived_module); log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int())); @@ -1116,6 +1155,21 @@ struct Abc9OpsPass : public Pass { log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n"); log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); log("\n"); + log(" -prep_dff_hier\n"); + log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); + log(" store such modules in named selection '$abc9_flops'.\n"); + log("\n"); + log(" -prep_dff_map\n"); + log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); + log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n"); + log(" the DFF's 'D' port. this is to prepare such specify cells to be moved into\n"); + log(" a submodule.\n"); + log("\n"); + log(" -prep_dff_unmap\n"); + log(" create a new design '$abc9_unmap' containing techmap rules that map\n"); + log(" *_$abc9_flop cells back into their original (* abc9_flop *) cells\n"); + log(" (including their original parameters).\n"); + log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); log(" certain required times.\n"); @@ -1136,10 +1190,6 @@ struct Abc9OpsPass : public Pass { log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n"); log(" during -prep_{delays,xaiger,box}.\n"); log("\n"); - log(" -prep_dff\n"); - log(" compute the clock domain and initial value of each flop in the design.\n"); - log(" process the '$holes' module to support clock-enable functionality.\n"); - log("\n"); log(" -prep_lut \n"); log(" pre-compute the lut library by analysing all modules marked with\n"); log(" (* abc9_lut= *).\n"); @@ -1167,7 +1217,7 @@ struct Abc9OpsPass : public Pass { bool check_mode = false; bool prep_delays_mode = false; bool mark_scc_mode = false; - bool prep_dff_mode = false; + bool prep_dff_hier_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; bool prep_xaiger_mode = false; bool prep_lut_mode = false; bool prep_box_mode = false; @@ -1177,53 +1227,71 @@ struct Abc9OpsPass : public Pass { int maxlut = 0; std::string write_box_dst; + bool valid = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-check") { check_mode = true; + valid = true; continue; } if (arg == "-mark_scc") { mark_scc_mode = true; + valid = true; continue; } - if (arg == "-prep_dff") { - prep_dff_mode = true; + if (arg == "-prep_dff_hier") { + prep_dff_hier_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff_map") { + prep_dff_map_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff_unmap") { + prep_dff_unmap_mode = true; + valid = true; continue; } if (arg == "-prep_xaiger") { prep_xaiger_mode = true; + valid = true; continue; } if (arg == "-prep_delays") { prep_delays_mode = true; + valid = true; continue; } if (arg == "-prep_lut" && argidx+1 < args.size()) { prep_lut_mode = true; maxlut = atoi(args[++argidx].c_str()); - continue; - } - if (arg == "-maxlut" && argidx+1 < args.size()) { + valid = true; continue; } if (arg == "-write_lut" && argidx+1 < args.size()) { write_lut_dst = args[++argidx]; rewrite_filename(write_lut_dst); + valid = true; continue; } if (arg == "-prep_box") { prep_box_mode = true; + valid = true; continue; } if (arg == "-write_box" && argidx+1 < args.size()) { write_box_dst = args[++argidx]; rewrite_filename(write_box_dst); + valid = true; continue; } if (arg == "-reintegrate") { reintegrate_mode = true; + valid = true; continue; } if (arg == "-dff") { @@ -1234,20 +1302,26 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); - if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || prep_lut_mode || prep_box_mode || !write_lut_dst.empty() || !write_box_dst.empty() || reintegrate_mode)) - log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff,lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); + if (!valid) + log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); - if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !prep_box_mode) - log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger,box}.\n"); + if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode) + log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger} or -reintegrate.\n"); if (check_mode) check(design); + if (prep_dff_hier_mode) + prep_dff_hier(design); + if (prep_dff_map_mode) + prep_dff_map(design); + if (prep_dff_unmap_mode) + prep_dff_unmap(design); if (prep_delays_mode) prep_delays(design, dff_mode); if (prep_lut_mode) prep_lut(design, maxlut); if (prep_box_mode) - prep_box(design, dff_mode); + prep_box(design); for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute(ID::abc9_holes)) @@ -1267,12 +1341,10 @@ struct Abc9OpsPass : public Pass { write_box(mod, write_box_dst); if (mark_scc_mode) mark_scc(mod); - if (prep_dff_mode) - prep_dff(mod); if (prep_xaiger_mode) prep_xaiger(mod, dff_mode); if (reintegrate_mode) - reintegrate(mod); + reintegrate(mod, dff_mode); } } } Abc9OpsPass; diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v index c0c5dc2fd..9e8048faf 100644 --- a/techlibs/common/abc9_model.v +++ b/techlibs/common/abc9_model.v @@ -1,6 +1,3 @@ -module \$__ABC9_FF_ (input D, output Q); -endmodule - (* abc9_box *) module \$__ABC9_DELAY (input I, output O); parameter DELAY = 0; diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v index 81f8a1d42..1d733a650 100644 --- a/techlibs/xilinx/abc9_map.v +++ b/techlibs/xilinx/abc9_map.v @@ -22,360 +22,6 @@ // before invoking the `abc9` pass in order to transform the design into // a format that it understands. -`ifdef DFF_MODE -// For example, (complex) flip-flops are expected to be described as an -// combinatorial box (containing all control logic such as clock enable -// or synchronous resets) followed by a basic D-Q flop. -// Yosys will automatically analyse the simulation model (described in -// cells_sim.v) and detach any $_DFF_P_ or $_DFF_N_ cells present in -// order to extract the combinatorial control logic left behind. -// Specifically, a simulation model similar to the one below: -// -// ++===================================++ -// || Sim model || -// || /\/\/\/\ || -// D -->>-----< > +------+ || -// R -->>-----< Comb. > |$_DFF_| || -// CE -->>-----< logic >-----| [NP]_|---+---->>-- Q -// || +--< > +------+ | || -// || | \/\/\/\/ | || -// || | | || -// || +----------------------------+ || -// || || -// ++===================================++ -// -// is transformed into: -// -// ++==================++ -// || Comb box || -// || || -// || /\/\/\/\ || -// D -->>-----< > || -// R -->>-----< Comb. > || +-----------+ -// CE -->>-----< logic >--->>-- $Q --|$__ABC9_FF_|--+-->> Q -// abc9_ff.Q +-->>-----< > || +-----------+ | -// | || \/\/\/\/ || | -// | || || | -// | ++==================++ | -// | | -// +-----------------------------------------------+ -// -// The purpose of the following FD* rules are to wrap the flop with: -// (a) a special $__ABC9_FF_ in front of the FD*'s output, indicating to abc9 -// the connectivity of its basic D-Q flop -// (b) an optional $__ABC9_ASYNC_ cell in front of $__ABC_FF_'s output to -// capture asynchronous behaviour -// (c) a special abc9_ff.clock wire to capture its clock domain and polarity -// (indicated to `abc9' so that it only performs sequential synthesis -// (with reachability analysis) correctly on one domain at a time) -// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its -// initial state -// NOTE: in order to perform sequential synthesis, `abc9' requires that -// the initial value of all flops be zero -// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback -// into the (combinatorial) FD* cell to facilitate clock-enable behaviour - -module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_R_INVERTED = 1'b0; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDSE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_S_INVERTED(IS_R_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .S(R) - ); - end - else begin - assign Q = QQ; - FDRE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_R_INVERTED(IS_R_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .R(R) - ); - end - endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule -module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R); - parameter [0:0] INIT = 1'b0; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDSE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .S(R) - ); - end - else begin - assign Q = QQ; - FDRE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .R(R) - ); - end - endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule - -module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S); - parameter [0:0] INIT = 1'b1; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_S_INVERTED = 1'b0; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDRE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_R_INVERTED(IS_S_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .R(S) - ); - end - else begin - assign Q = QQ; - FDSE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_S_INVERTED(IS_S_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .S(S) - ); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule -module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S); - parameter [0:0] INIT = 1'b1; - wire QQ, $Q; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDRE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .R(S) - ); - end - else begin - assign Q = QQ; - FDSE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .S(S) - ); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; -endmodule - -module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_CLR_INVERTED = 1'b0; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDPE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_PRE_INVERTED(IS_CLR_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - // Since this is an async flop, async behaviour is dealt with here - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ)); - end - else begin - assign Q = QQ; - FDCE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_CLR_INVERTED(IS_CLR_INVERTED) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - // Since this is an async flop, async behaviour is dealt with here - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule -module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR); - parameter [0:0] INIT = 1'b0; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDPE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR), .Y(QQ)); - end - else begin - assign Q = QQ; - FDCE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule - -module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE); - parameter [0:0] INIT = 1'b1; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_PRE_INVERTED = 1'b0; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDCE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_CLR_INVERTED(IS_PRE_INVERTED), - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ)); - end - else begin - assign Q = QQ; - FDPE #( - .INIT(1'b0), - .IS_C_INVERTED(IS_C_INVERTED), - .IS_D_INVERTED(IS_D_INVERTED), - .IS_PRE_INVERTED(IS_PRE_INVERTED), - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule -module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE); - parameter [0:0] INIT = 1'b1; - wire QQ, $Q, $QQ; - generate if (INIT == 1'b1) begin - assign Q = ~QQ; - FDCE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC0 below - ); - $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE), .Y(QQ)); - end - else begin - assign Q = QQ; - FDPE_1 #( - .INIT(1'b0) - ) _TECHMAP_REPLACE_ ( - .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE) - // ^^^ Note that async - // control is not directly - // supported by abc9 but its - // behaviour is captured by - // $__ABC9_ASYNC1 below - ); - $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ)); - end endgenerate - (* abc9_init = 1'b0 *) - $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); - - // Special signals - wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; - wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; -endmodule -`endif - // Attach a (combinatorial) black-box onto the output // of thes LUTRAM primitives to capture their // asynchronous read behaviour diff --git a/techlibs/xilinx/abc9_unmap.v b/techlibs/xilinx/abc9_unmap.v index 5604ceb0a..49a7bd88c 100644 --- a/techlibs/xilinx/abc9_unmap.v +++ b/techlibs/xilinx/abc9_unmap.v @@ -25,10 +25,6 @@ module $__ABC9_ASYNC01(input A, S, output Y); assign Y = A; endmodule -module $__ABC9_FF_(input D, output Q); - assign Q = D; -endmodule - module $__ABC9_RAM6(input A, input [5:0] S, output Y); assign Y = A; endmodule diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 63223afbf..93d080ffd 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -640,7 +640,7 @@ module FDRSE ( Q <= d; endmodule -(* abc9_flop, lib_whitebox *) +(* lib_whitebox *) module FDCE ( output reg Q, (* clkbuf_sink *) @@ -683,7 +683,7 @@ module FDCE ( endspecify endmodule -(* abc9_flop, lib_whitebox *) +(* lib_whitebox *) module FDCE_1 ( output reg Q, (* clkbuf_sink *) @@ -708,7 +708,7 @@ module FDCE_1 ( endspecify endmodule -(* abc9_flop, lib_whitebox *) +(* lib_whitebox *) module FDPE ( output reg Q, (* clkbuf_sink *) @@ -750,7 +750,7 @@ module FDPE ( endspecify endmodule -(* abc9_flop, lib_whitebox *) +(* lib_whitebox *) module FDPE_1 ( output reg Q, (* clkbuf_sink *) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 229ffcb3d..173bdcb91 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -613,10 +613,7 @@ struct SynthXilinxPass : public ScriptPass if (family != "xc7") log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, " "will use timing for 'xc7' instead.\n", family.c_str()); - std::string techmap_args = "-map +/xilinx/abc9_map.v -max_iter 1"; - if (dff_mode) - techmap_args += " -D DFF_MODE"; - run("techmap " + techmap_args); + run("techmap -map +/xilinx/abc9_map.v -max_iter 1"); run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v"); std::string abc9_opts; std::string k = "synth_xilinx.abc9.W"; From 77f3abcdc30e21b4359c2b07c20b63bdac5993bf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 13:10:57 -0700 Subject: [PATCH 043/197] xaiger: when -dff use (* init *) for initial state --- backends/aiger/xaiger.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 2e2ca7018..5d15df310 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -79,6 +79,7 @@ struct XAigerWriter Module *module; SigMap sigmap; + dict init_map; pool input_bits, output_bits; dict not_map, alias_map; dict> and_map; @@ -157,7 +158,8 @@ struct XAigerWriter if (wire->get_bool_attribute(ID::keep)) sigmap.add(wire); - for (auto wire : module->wires()) + for (auto wire : module->wires()) { + auto it = wire->attributes.find(ID::init); for (int i = 0; i < GetSize(wire); i++) { SigBit wirebit(wire, i); @@ -184,7 +186,17 @@ struct XAigerWriter alias_map[wirebit] = bit; output_bits.insert(wirebit); } + + if (it != wire->attributes.end()) { + auto s = it->second[i]; + if (s != State::Sx) { + auto r = init_map.insert(std::make_pair(bit, it->second[i])); + if (!r.second && r.first->second != it->second[i]) + log_error("Bit '%s' has a conflicting (* init *) value.\n", log_signal(bit)); + } + } } + } TimingInfo timing; @@ -632,8 +644,8 @@ struct XAigerWriter write_r_buffer(mergeability); else log_abort(); - Const init = cell->attributes.at(ID::abc9_init); - log_assert(GetSize(init) == 1); + SigBit Q = sigmap(cell->getPort(ID::Q)); + State init = init_map.at(Q, State::Sx); if (init == State::S1) write_s_buffer(1); else if (init == State::S0) From 483a190c1b468b2a22fe7f2b92075953c6095f7d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 13:11:25 -0700 Subject: [PATCH 044/197] aiger: -xaiger to parse initial state back into (* init *) on Q wire --- frontends/aiger/aigerparse.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 7e5e6dd2d..ed3a926c6 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -802,7 +802,8 @@ void AigerReader::post_process() ff->setPort(ID::C, r.first->second); ff->setPort(ID::D, d); ff->setPort(ID::Q, q); - ff->attributes[ID::abc9_init] = initial_state[i]; + log_assert(GetSize(q) == 1); + q->attributes[ID::init] = initial_state[i]; } dict> wideports_cache; From edacb8f437bd1d3c61a12dfa35214e3a1d47af99 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 13:12:37 -0700 Subject: [PATCH 045/197] abc9_ops: do not use (* abc9_init *) --- passes/techmap/abc9_ops.cc | 47 +++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index fe2e5c3ac..2ad082d38 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -157,20 +157,11 @@ void prep_dff_map(RTLIL::Design *design) D = cell->getPort(ID::D); Q = cell->getPort(ID::Q); - // TODO: Can we avoid doing this? - // Convert (* init *) on $_DFF_[NP]_.Q to (* abc9_init *) attr on cell + // Block sequential synthesis on cells with (* init = 1 *) + // because ABC9 doesn't support them log_assert(GetSize(Q.wire) == 1); - auto it = Q.wire->attributes.find(ID::init); - Const init; - if (it != Q.wire->attributes.end()) { - log_assert(GetSize(it->second) == 1); - init = it->second; - Q.wire->attributes.erase(it); - } - else - init = State::Sx; - auto r YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID::abc9_init, init)); - log_assert(r.second); + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); if (init == State::S1) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); @@ -226,8 +217,10 @@ void prep_dff_unmap(RTLIL::Design *design) continue; // May not exist if init = 1'b1 auto unmap_module = unmap_design->addModule(flop_module->name); - for (auto port : flop_module->ports) - unmap_module->addWire(port, flop_module->wire(port)); + for (auto port : flop_module->ports) { + auto w = unmap_module->addWire(port, flop_module->wire(port)); + w->attributes.erase(ID::init); + } unmap_module->ports = flop_module->ports; unmap_module->check(); @@ -757,6 +750,17 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) map_autoidx = autoidx++; + // TODO: Get rid of this expensive lookup + dict> sig2inits; + SigMap sigmap(module); + for (auto w : module->wires()) { + auto it = w->attributes.find(ID::init); + if (it == w->attributes.end()) + continue; + for (const auto &b : SigSpec(w)) + sig2inits[sigmap(b)].emplace_back(b); + } + RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str())); if (mapped_mod == NULL) log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module)); @@ -764,6 +768,8 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) for (auto w : mapped_mod->wires()) { auto nw = module->addWire(remap_name(w->name), GetSize(w)); nw->start_offset = w->start_offset; + // Remove all (* init *) since they only existon $_DFF_[NP]_ + w->attributes.erase(ID::init); } dict> box_ports; @@ -804,8 +810,15 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) if (cell->has_keep_attr()) continue; + // Short out $_DFF_[NP]_ cells since the flop box already has + // all the information we need to reconstruct cell if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); + SigBit Q = cell->getPort(ID::Q); + auto it = sig2inits.find(Q); + if (it != sig2inits.end()) + for (const auto &b : it->second) + b.wire->attributes.at(ID::init)[b.offset] = State::Sx; + module->connect(Q, cell->getPort(ID::D)); module->remove(cell); } else if (cell->type.in(ID($_AND_), ID($_NOT_))) @@ -822,6 +835,8 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + // Short out $_DFF_[NP]_ cells since the flop box already has + // all the information we need to reconstruct cell if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { SigBit D = mapped_cell->getPort(ID::D); SigBit Q = mapped_cell->getPort(ID::Q); From 6b3aa91a2a1f717ebf4ce7155b134e9d556ac1ab Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 13:12:45 -0700 Subject: [PATCH 046/197] abc9: cleanup --- passes/techmap/abc9.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7f3e6abcc..97ee57aaa 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -295,16 +295,13 @@ struct Abc9Pass : public ScriptPass run("delete *_$abc9_flop"); if (help_mode) { run("foreach module in design"); - run(" cd "); run(" rename _$abc9_flop _TECHMAP_REPLACE_"); - run(" cd"); } else { // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs for (auto module : active_design->selected_modules()) { - run(stringf("cd %s", log_id(module->name))); + active_design->selected_active_module = module->name.str(); run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); - run("cd"); } } run("design -stash $abc9_map"); From 90cd49995b9bf18c4b6e7e7bbea237617753b29b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 16:20:15 -0700 Subject: [PATCH 047/197] xaiger: do not treat (* init=1'bx *) as 1'b0 --- backends/aiger/xaiger.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 5d15df310..1006d56c6 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -652,7 +652,7 @@ struct XAigerWriter write_s_buffer(0); else { log_assert(init == State::Sx); - write_s_buffer(0); + write_s_buffer(2); } // Use arrival time from output of flop box From c10757a8ea5d6052d7a06690fb7411b5e4c7d772 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 16:21:08 -0700 Subject: [PATCH 048/197] synth_xilinx: rename dff_mode -> dff --- techlibs/xilinx/synth_xilinx.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 173bdcb91..c45d389ef 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -143,7 +143,7 @@ struct SynthXilinxPass : public ScriptPass std::string top_opt, edif_file, blif_file, family; bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram; - bool abc9, dff_mode; + bool abc9, dff; bool flatten_before_abc; int widemux; int lut_size; @@ -170,7 +170,7 @@ struct SynthXilinxPass : public ScriptPass nodsp = false; uram = false; abc9 = false; - dff_mode = false; + dff = false; flatten_before_abc = false; widemux = 0; lut_size = 6; @@ -217,7 +217,7 @@ struct SynthXilinxPass : public ScriptPass continue; } if (args[argidx] == "-retime") { - dff_mode = true; + dff = true; retime = true; continue; } @@ -281,7 +281,7 @@ struct SynthXilinxPass : public ScriptPass continue; } if (args[argidx] == "-dff") { - dff_mode = true; + dff = true; continue; } break; @@ -595,9 +595,11 @@ struct SynthXilinxPass : public ScriptPass run("clean"); } - if (check_label("map_ffs")) { + if (check_label("map_ffs", "('-abc9' only)")) { if (abc9 || help_mode) { - run("techmap -map " + ff_map_file, "('-abc9' only)"); + if (dff || help_mode) + run("zinit -all", "('-dff' only)"); + run("techmap -map " + ff_map_file); } } @@ -625,7 +627,7 @@ struct SynthXilinxPass : public ScriptPass } if (nowidelut) abc9_opts += stringf(" -maxlut %d", lut_size); - if (dff_mode) + if (dff) abc9_opts += " -dff"; run("abc9" + abc9_opts); run("techmap -map +/xilinx/abc9_unmap.v"); @@ -645,7 +647,7 @@ struct SynthXilinxPass : public ScriptPass else abc_opts += " -luts 2:2,3,6:5,10,20,40"; } - if (dff_mode) + if (dff) abc_opts += " -dff"; if (retime) abc_opts += " -D 1"; From a1ae5845f83f12f2893c48c23c377aea25c1b280 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 17:30:29 -0700 Subject: [PATCH 049/197] abc9_ops: -prep_dff_map to cope with plain $_DFF_[NP]_ flops --- passes/techmap/abc9_ops.cc | 51 +++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2ad082d38..cf3bd689e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -134,13 +134,22 @@ void prep_dff_hier(RTLIL::Design *design) for (auto module : design->selected_modules()) for (auto cell : module->cells()) { auto inst_module = design->module(cell->type); - if (inst_module && inst_module->get_bool_attribute(ID::abc9_flop)) { - modules_sel.select(inst_module); + if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { + if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + log_error("Module '%s' with (* abc9_flop *) is not a whitebox.\n", log_id(inst_module)); // Derive modules for all instantiations of (* abc9_flop *) auto derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + if (!derived_module->get_bool_attribute(ID::abc9_flop)) + continue; // And remember one representative cell (for its parameters) - if (modules_sel.selected_modules.insert(derived_type).second) + if (!modules_sel.selected_whole_module(derived_type)) { + if (derived_type != cell->type) + modules_sel.select(inst_module); + + modules_sel.select(derived_module); cells_sel.select(module, cell); + } } } } @@ -150,19 +159,20 @@ void prep_dff_map(RTLIL::Design *design) for (auto module : design->modules()) { vector specify_cells; SigBit D, Q; + Cell* dff_cell = nullptr; for (auto cell : module->cells()) if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - if (D != SigBit()) + if (dff_cell) log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module)); - D = cell->getPort(ID::D); - Q = cell->getPort(ID::Q); + dff_cell = cell; - // Block sequential synthesis on cells with (* init = 1 *) + // Block sequential synthesis on cells with (* init *) != 1'b0 // because ABC9 doesn't support them + Q = cell->getPort(ID::Q); log_assert(GetSize(Q.wire) == 1); Const init = Q.wire->attributes.at(ID::init, State::Sx); log_assert(GetSize(init) == 1); - if (init == State::S1) { + if (init != State::S0) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); module->makeblackbox(); @@ -176,9 +186,26 @@ void prep_dff_map(RTLIL::Design *design) } else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) specify_cells.emplace_back(cell); - if (D == SigBit()) + if (!dff_cell) log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + D = dff_cell->getPort(ID::D); + + // Add a dummy enable mux feeding DFF.D to ensure that: + // (i) a driving cell exists, so that 'submod' will have + // an output port + // (ii) DFF.Q will exist in this submodule + { + auto c = module->addCell(NEW_ID, ID($_MUX_)); + auto w = module->addWire(NEW_ID); + c->setPort(ID::A, D); + c->setPort(ID::B, Q); + c->setPort(ID::S, State::S0); + c->setPort(ID::Y, w); + dff_cell->setPort(ID::D, w); + D = w; + } + // Rewrite $specify cells that end with $_DFF_[NP]_.Q // to $_DFF_[NP]_.D since it will be moved into // the submodule @@ -253,7 +280,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; auto inst_module = design->module(cell->type); - bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop); + bool abc9_flop = inst_module && inst_module->attributes.count(ID::abc9_flop); if (abc9_flop && !dff) continue; @@ -339,7 +366,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || (!box_module->get_bool_attribute(ID::abc9_box) && !box_module->get_bool_attribute(ID::abc9_flop))) + if (!box_module || !box_module->get_bool_attribute(ID::abc9_box)) continue; cell->attributes[ID::abc9_box_seq] = box_count++; @@ -967,7 +994,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) SigSpec outputs = std::move(jt->second); mapped_cell->connections_.erase(jt); - auto abc9_flop = box_module->attributes.count(ID::abc9_flop); + auto abc9_flop = box_module->get_bool_attribute(ID::abc9_flop); if (!abc9_flop) { for (const auto &i : inputs) bit_users[i].insert(mapped_cell->name); From 4a10c87ae1916fb1d19b7bb0adebd54a5b15cf30 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 17:31:44 -0700 Subject: [PATCH 050/197] ice40: split out cells_map.v into ff_map.v --- techlibs/ice40/Makefile.inc | 1 + techlibs/ice40/cells_map.v | 31 ------------------------------- techlibs/ice40/ff_map.v | 28 ++++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 31 deletions(-) create mode 100644 techlibs/ice40/ff_map.v diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index b9e504a9d..1a8caf9a9 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -23,6 +23,7 @@ techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk $(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/ff_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v index d5362eb83..e9ccca239 100644 --- a/techlibs/ice40/cells_map.v +++ b/techlibs/ice40/cells_map.v @@ -1,33 +1,3 @@ -module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule -module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule - -module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule - -module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule - -module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule - -module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule - -module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule - -module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule -module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule - -`ifndef NO_LUT module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; @@ -59,4 +29,3 @@ module \$lut (A, Y); end endgenerate endmodule -`endif diff --git a/techlibs/ice40/ff_map.v b/techlibs/ice40/ff_map.v new file mode 100644 index 000000000..e8807e0bd --- /dev/null +++ b/techlibs/ice40/ff_map.v @@ -0,0 +1,28 @@ +module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule +module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule +module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule + +module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule +module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule +module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule +module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule + +module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule +module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule +module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule +module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule From fe7965e0eeb7dacf1453ff6cfc1783c8c39c8201 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 17:32:21 -0700 Subject: [PATCH 051/197] ice40: add synth_ice40 -dff option, support with -abc9 --- techlibs/ice40/cells_sim.v | 13 +++++++++++++ techlibs/ice40/synth_ice40.cc | 36 +++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 5d107989d..1b759a28f 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -245,6 +245,7 @@ endmodule // Positive Edge SiliconBlue FF Cells +(* abc9_flop, lib_whitebox *) module SB_DFF ( output `SB_DFF_REG, input C, D @@ -280,6 +281,7 @@ module SB_DFF ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFE ( output `SB_DFF_REG, input C, E, D @@ -322,6 +324,7 @@ module SB_DFFE ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFSR ( output `SB_DFF_REG, input C, R, D @@ -419,6 +422,7 @@ module SB_DFFR ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFSS ( output `SB_DFF_REG, input C, S, D @@ -516,6 +520,7 @@ module SB_DFFS ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFESR ( output `SB_DFF_REG, input C, E, R, D @@ -627,6 +632,7 @@ module SB_DFFER ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFESS ( output `SB_DFF_REG, input C, E, S, D @@ -740,6 +746,7 @@ endmodule // Negative Edge SiliconBlue FF Cells +(* abc9_flop, lib_whitebox *) module SB_DFFN ( output `SB_DFF_REG, input C, D @@ -775,6 +782,7 @@ module SB_DFFN ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNE ( output `SB_DFF_REG, input C, E, D @@ -817,6 +825,7 @@ module SB_DFFNE ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNSR ( output `SB_DFF_REG, input C, R, D @@ -864,6 +873,7 @@ module SB_DFFNSR ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNR ( output `SB_DFF_REG, input C, R, D @@ -914,6 +924,7 @@ module SB_DFFNR ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNSS ( output `SB_DFF_REG, input C, S, D @@ -1011,6 +1022,7 @@ module SB_DFFNS ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNESR ( output `SB_DFF_REG, input C, E, R, D @@ -1122,6 +1134,7 @@ module SB_DFFNER ( `endif endmodule +(* abc9_flop, lib_whitebox *) module SB_DFFNESS ( output `SB_DFF_REG, input C, E, S, D diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 6e05ab0b2..a8bf93db5 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -71,6 +71,9 @@ struct SynthIce40Pass : public ScriptPass 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"); @@ -113,7 +116,7 @@ struct SynthIce40Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file, device_opt; - bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9, flowmap; + bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9, dff, flowmap; int min_ce_use; void clear_flags() YS_OVERRIDE @@ -221,6 +224,10 @@ struct SynthIce40Pass : public ScriptPass abc9 = true; continue; } + if (args[argidx] == "-dff") { + dff = true; + continue; + } if (args[argidx] == "-device" && argidx+1 < args.size()) { device_opt = args[++argidx]; continue; @@ -354,7 +361,9 @@ struct SynthIce40Pass : public ScriptPass run(stringf("dff2dffe -unmap-mince %d", min_ce_use)); run("simplemap t:$dff"); } - run("techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v"); + if ((abc9 && dff) || help_mode) + run("zinit -all", "(-abc9 and -dff only)"); + run("techmap -map +/ice40/ff_map.v"); run("opt_expr -mux_undef"); run("simplemap"); run("ice40_ffinit"); @@ -387,23 +396,34 @@ struct SynthIce40Pass : public ScriptPass k = stringf("synth_ice40.abc9.%s.W", device_opt.c_str()); abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); } + if (dff) + abc9_opts += " -dff"; run("abc9 " + abc9_opts); } else - run("abc -dress -lut 4", "(skip if -noabc)"); + run(stringf("abc -dress -lut 4 %s", dff ? "-dff" : ""), "(skip if -noabc)"); } run("ice40_wrapcarry -unwrap"); - run("techmap -D NO_LUT -map +/ice40/cells_map.v"); + run("techmap -map +/ice40/ff_map.v"); run("clean"); run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0"); } if (check_label("map_cells")) { - if (vpr) - run("techmap -D NO_LUT -map +/ice40/cells_map.v"); - else - run("techmap -map +/ice40/cells_map.v", "(with -D NO_LUT in vpr mode)"); + if (help_mode) + run("techmap [-map +/ice40/ff_map.v] [-map +/ice40/cells_map.v]", "(skip if -abc9; skip if -vpr)"); + else if (vpr) + run("techmap -map +/ice40/ff_map.v"); + else { + std::string techmap_args; + if (!abc9) + techmap_args += " -map +/ice40/ff_map.v"; + if (!vpr) + techmap_args += " -map +/ice40/cells_map.v"; + if (!techmap_args.empty()) + run("techmap " + techmap_args); + } run("clean"); } From 039c3a59826de4410dd9257262430729fb0b4000 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Apr 2020 19:08:46 -0700 Subject: [PATCH 052/197] kernel: Module::makeblackbox() to clear connections + delete wires last --- kernel/rtlil.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 196e301b6..3e5896813 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -776,6 +776,7 @@ void RTLIL::Module::makeblackbox() connections_.clear(); remove(delwires); + set_bool_attribute(ID::blackbox); } From 5d5029fa75b8cb37c07fc15a0429e28fe317b472 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 07:31:07 -0700 Subject: [PATCH 053/197] ecp5: replace ecp5_ffinit with techmap rules + dff2dffs -match-init --- techlibs/ecp5/Makefile.inc | 3 +- techlibs/ecp5/cells_map.v | 264 ++++++++++++++++++++++++++++-------- techlibs/ecp5/synth_ecp5.cc | 3 +- 3 files changed, 213 insertions(+), 57 deletions(-) diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 217151e96..6bc9c854e 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -1,6 +1,5 @@ -OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \ - techlibs/ecp5/ecp5_gsr.o +OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_gsr.o GENFILES += techlibs/ecp5/bram_init_1_2_4.vh GENFILES += techlibs/ecp5/bram_init_9_18_36.vh diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index c031703a9..f8df08eab 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -1,65 +1,223 @@ -module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule -module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule +(* techmap_celltype = "$_DFF_N_ $_DFF_P_" *) +module \$_DFF_x_ (input D, C, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") + localparam CLKMUX = "INV"; + else + localparam CLKMUX = "CLK"; + if (_TECHMAP_WIREINIT_Q_ === 1'b1) + localparam REGSET = "SET"; + else + localparam REGSET = "RESET"; + endgenerate + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET)) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); +endmodule -module \$_DFFE_NN_ (input D, C, E, output Q); 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)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); 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)); endmodule +(* techmap_celltype = "$_DFFE_NN_ $_DFFE_PN_ $_DFFE_NP_ $_DFFE_PP_" *) +module \$_DFFE_xx_ (input D, C, E, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") + localparam CLKMUX = "INV"; + else + localparam CLKMUX = "CLK"; + if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") + localparam CEMUX = "INV"; + else + localparam CEMUX = "CE"; + if (_TECHMAP_WIREINIT_Q_ === 1'b1) + localparam REGSET = "SET"; + else + localparam REGSET = "RESET"; + endgenerate + TRELLIS_FF #(.GSR("AUTO"), .CEMUX(CEMUX), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET)) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); +endmodule -module \$_DFFE_NP_ (input D, C, E, output Q); 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)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); 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)); endmodule +(* techmap_celltype = "$_DFF_NN0_ $_DFF_NN1_ $_DFF_PN0_ $_DFF_PN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PP0_ $_DFF_PP1_" *) +module \$_DFF_xxx_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") + localparam CLKMUX = "INV"; + else + localparam CLKMUX = "CLK"; + // TODO: Why not use LSRMUX param? + if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") + wire LSR_ = !R; + else + wire LSR_ = R; + if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin + localparam REGSET = "SET"; + if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("ECP5 doesn't support FFs with asynchronous set initialized to 0"); + end + else begin + localparam REGSET = "RESET"; + if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("ECP5 doesn't support FFs with asynchronous reset initialized to 1"); + end + endgenerate + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(LSR_), .DI(D), .Q(Q)); +endmodule -module \$_DFF_NN0_ (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)); endmodule -module \$_DFF_NN1_ (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)); endmodule -module \$_DFF_PN0_ (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)); endmodule -module \$_DFF_PN1_ (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)); endmodule +(* techmap_celltype = "$__DFFS_NN0_ $__DFFS_NN1_ $__DFFS_PN0_ $__DFFS_PN1_ $__DFFS_NP0_ $__DFFS_NP1_ $__DFFS_PP0_ $__DFFS_PP1_" *) +module \$__DFFS_xxx_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") + localparam CLKMUX = "INV"; + else + localparam CLKMUX = "CLK"; + // TODO: Why not use LSRMUX param? + if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") + wire LSR_ = !R; + else + wire LSR_ = R; + if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin + localparam REGSET = "SET"; + if (_TECHMAP_WIREINIT_Q_ === 1'b0) + // init is 0, reset to 1 + wire D_ = D || LSR_; + else + wire D_ = D; + end + else begin + localparam REGSET = "RESET"; + if (_TECHMAP_WIREINIT_Q_ === 1'b1) + // init is 1, reset to 0 + wire D_ = !(D && LSR_); + else + wire D_ = D; + end + endgenerate + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(LSR_), .DI(D_), .Q(Q)); +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)); 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)); 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)); 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)); endmodule +(* techmap_celltype = "$__DFFE_NN0 $__DFFE_NN1 $__DFFE_PN0 $__DFFE_PN1 $__DFFE_NP0 $__DFFE_NP1 $__DFFE_PP0 $__DFFE_PP1" *) +module \$__DFFE_xxx_ (input D, C, E, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") + localparam CLKMUX = "INV"; + else + localparam CLKMUX = "CLK"; + // TODO: Why not use LSRMUX param? + if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") + wire LSR_ = !R; + else + wire LSR_ = R; + if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin + if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("ECP5 doesn't support FFs with asynchronous set initialized to 0"); + else + localparam REGSET = "SET"; + end + else begin + if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("ECP5 doesn't support FFs with asynchronous reset initialized to 1"); + else + localparam REGSET = "RESET"; + end + endgenerate + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(LSR_), .DI(D), .Q(Q)); +endmodule -module \$__DFFS_NN0_ (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)); endmodule -module \$__DFFS_NN1_ (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)); endmodule -module \$__DFFS_PN0_ (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)); endmodule -module \$__DFFS_PN1_ (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)); endmodule - -module \$__DFFS_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)); endmodule -module \$__DFFS_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)); endmodule -module \$__DFFS_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)); endmodule -module \$__DFFS_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)); endmodule - -module \$__DFFE_NN0 (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)); endmodule -module \$__DFFE_NN1 (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)); endmodule -module \$__DFFE_PN0 (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)); endmodule -module \$__DFFE_PN1 (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)); endmodule - -module \$__DFFE_NP0 (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)); endmodule -module \$__DFFE_NP1 (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)); endmodule -module \$__DFFE_PP0 (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)); endmodule -module \$__DFFE_PP1 (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)); endmodule - -module \$__DFFSE_NN0 (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)); endmodule -module \$__DFFSE_NN1 (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)); endmodule -module \$__DFFSE_PN0 (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)); endmodule -module \$__DFFSE_PN1 (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)); endmodule - -module \$__DFFSE_NP0 (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)); endmodule -module \$__DFFSE_NP1 (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)); endmodule -module \$__DFFSE_PP0 (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)); endmodule -module \$__DFFSE_PP1 (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)); endmodule +(* techmap_celltype = "$__DFFSE_NN0 $__DFFSE_NN1 $__DFFSE_PN0 $__DFFSE_PN1 $__DFFSE_NP0 $__DFFSE_NP1 $__DFFSE_PP0 $__DFFSE_PP1" *) +module \$__DFFSE_xxx_ (input D, C, E, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") + localparam CLKMUX = "INV"; + else + localparam CLKMUX = "CLK"; + // TODO: Why not use LSRMUX param? + if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") + wire LSR_ = !R; + else + wire LSR_ = R; + if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin + localparam REGSET = "SET"; + if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin + // init is 0, reset to 1 + wire D_ = D || LSR_; + wire E_ = E || LSR_; + end + else begin + wire D_ = D; + wire E_ = E; + end + end + else begin + localparam REGSET = "RESET"; + if (_TECHMAP_WIREINIT_Q_ === 1'b1) begin + // init is 1, reset to 0 + wire D_ = !(D && LSR_); + wire E_ = !(E && LSR_); + end + else begin + wire D_ = D; + wire E_ = E; + end + end + endgenerate + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E_), .LSR(LSR_), .DI(D_), .Q(Q)); +endmodule `ifdef ASYNC_PRLD -module \$_DLATCH_N_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(!E), .DI(1'b0), .M(D), .Q(Q)); endmodule -module \$_DLATCH_P_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(E), .DI(1'b0), .M(D), .Q(Q)); endmodule +(* techmap_celltype = "$_DLATCH_N_ $_DLATCH_P_" *) +module \$_DLATCH_x_ (input E, input D, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + // TODO: Why not use LSRMUX param? + if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") + wire LSR_ = !E; + else + wire LSR_ = E; + if (_TECHMAP_WIREINIT_Q_ !== 1'bx) + $error("ECP5 doesn't support latches with initial values"); // TODO: Check + endgenerate + TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(LSR_), .DI(1'b0), .M(D), .Q(Q)); +endmodule -module \$_DFFSR_NNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule -module \$_DFFSR_NNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule -module \$_DFFSR_NPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule -module \$_DFFSR_NPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule +(* techmap_celltype = "$_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_PNN_ $_DFFSR_PNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PPN_ $_DFFSR_PPP_" *) +module \$_DFFSR_xxx_ (input C, S, R, D, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + generate + if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") + localparam CLKMUX = "INV"; + else + localparam CLKMUX = "CLK"; + if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") + wire S_ = !S; + else + wire S_ = S; + if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") + wire R_ = !R; + else + wire R_ = R; + if (_TECHMAP_WIREINIT_Q_ !== 1'bx) + $error("ECP5 doesn't support FFs with asynchronous set and reset with initial values"); + endgenerate -module \$_DFFSR_PNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule -module \$_DFFSR_PNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule -module \$_DFFSR_PPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule -module \$_DFFSR_PPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule + TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX(CLKINV), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S_ || R_), .DI(D), .M(!R_), .Q(Q)); +endmodule `endif `include "cells_ff.vh" diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index b9b236a0c..5f00d3d4e 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -303,14 +303,13 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("map_ffs")) { - run("dff2dffs"); + run("dff2dffs -match-init"); run("opt_clean"); if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); - run("ecp5_ffinit"); run("ecp5_gsr"); run("attrmvcp -copy -attr syn_useioff"); run("opt_clean"); From 23c53a6bdde645ef475752e24e7751beb20a3121 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 07:48:37 -0700 Subject: [PATCH 054/197] ice40: synth_ice40 cleanup --- techlibs/ice40/synth_ice40.cc | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index a8bf93db5..376cb7dbd 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -412,19 +412,9 @@ struct SynthIce40Pass : public ScriptPass if (check_label("map_cells")) { if (help_mode) - run("techmap [-map +/ice40/ff_map.v] [-map +/ice40/cells_map.v]", "(skip if -abc9; skip if -vpr)"); - else if (vpr) - run("techmap -map +/ice40/ff_map.v"); - else { - std::string techmap_args; - if (!abc9) - techmap_args += " -map +/ice40/ff_map.v"; - if (!vpr) - techmap_args += " -map +/ice40/cells_map.v"; - if (!techmap_args.empty()) - run("techmap " + techmap_args); - } - + run("techmap -map +/ice40/cells_map.v", "(skip if -vpr)"); + else if (!vpr) + run("techmap -map +/ice40/cells_map.v"); run("clean"); } From e38b1280f9752d22c6d2a5803bec6a6cedf12a10 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 07:49:55 -0700 Subject: [PATCH 055/197] abc9_ops: -prep_dff_map to warn if no specify cells --- passes/techmap/abc9_ops.cc | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index cf3bd689e..c640d06f8 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -206,13 +206,18 @@ void prep_dff_map(RTLIL::Design *design) D = w; } - // Rewrite $specify cells that end with $_DFF_[NP]_.Q - // to $_DFF_[NP]_.D since it will be moved into - // the submodule - for (auto cell : specify_cells) { - auto DST = cell->getPort(ID::DST); - DST.replace(Q, D); - cell->setPort(ID::DST, DST); + if (GetSize(specify_cells) == 0) { + log_warning("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); + } + else { + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); + } } continue_outer_loop: ; } From 34c77326420e4f906544e26499683869c47d09aa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 07:51:23 -0700 Subject: [PATCH 056/197] ecp5: add synth_ecp5 -dff to work with -abc9 --- techlibs/ecp5/cells_sim.v | 21 ++++++++++++++++++++ techlibs/ecp5/synth_ecp5.cc | 38 +++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 12b33e925..69685683f 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -294,6 +294,7 @@ endmodule // --------------------------------------- +(* abc9_flop=(SRMODE != "ASYNC"), lib_whitebox=(SRMODE != "ASYNC") *) module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); parameter GSR = "ENABLED"; parameter [127:0] CEMUX = "1"; @@ -340,6 +341,26 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); Q <= DI; end endgenerate + + generate + // TODO + if (CLKMUX == "INV") + specify + $setup(DI, negedge CLK, 0); + $setup(CE, negedge CLK, 0); + $setup(LSR, negedge CLK, 0); + if (muxlsr) (negedge CLK => (Q : DI)) = 0; + if (!muxlsr && muxce) (negedge CLK => (Q : srval)) = 0; + endspecify + else + specify + $setup(DI, posedge CLK, 0); + $setup(CE, posedge CLK, 0); + $setup(LSR, posedge CLK, 0); + if (muxlsr) (posedge CLK => (Q : srval)) = 0; + if (!muxlsr && muxce) (posedge CLK => (Q : DI)) = 0; + endspecify + endgenerate endmodule // --------------------------------------- diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 5f00d3d4e..ecc5039e6 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -66,6 +66,9 @@ struct SynthEcp5Pass : public ScriptPass 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"); @@ -107,7 +110,7 @@ struct SynthEcp5Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file; - bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, retime, abc2, abc9, nodsp, vpr; + bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, retime, abc2, abc9, nodsp, vpr; void clear_flags() YS_OVERRIDE { @@ -122,6 +125,7 @@ struct SynthEcp5Pass : public ScriptPass nowidelut = false; asyncprld = false; flatten = true; + dff = false; retime = false; abc2 = false; vpr = false; @@ -169,6 +173,10 @@ struct SynthEcp5Pass : public ScriptPass flatten = false; continue; } + if (args[argidx] == "-dff") { + dff = true; + continue; + } if (args[argidx] == "-retime") { retime = true; continue; @@ -307,6 +315,8 @@ struct SynthEcp5Pass : public ScriptPass run("opt_clean"); if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); + if ((abc9 && dff) || help_mode) + run("zinit -all", "(-abc9 and -dff only)"); run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); @@ -323,7 +333,7 @@ struct SynthEcp5Pass : public ScriptPass std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v"; if (abc9) techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1"; - if (!asyncprld || abc9) + if (!techmap_args.empty()) run("techmap " + techmap_args); if (abc9) { @@ -337,26 +347,30 @@ struct SynthEcp5Pass : public ScriptPass else abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); if (nowidelut) - run("abc9 -maxlut 4 -W 200"); - else - run("abc9 -W 200"); + abc9_args += " -maxlut 4"; + if (dff) + abc9_args += " -dff"; + run("abc9" + abc9_args); run("techmap -map +/ecp5/abc9_unmap.v"); } else { + std::string abc_args = " -dress"; if (nowidelut) - run("abc -lut 4 -dress"); + abc_args += " -lut 4"; else - run("abc -lut 4:7 -dress"); + abc_args += " -lut 4:7"; + if (dff) + abc_args += " -dff"; + run("abc" + abc_args); } run("clean"); } if (check_label("map_cells")) { - if (vpr) - run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); - else - run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)"); - + 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 ecp5"); run("clean"); } From f975cf39cbedbca0482109b7aa625570a3857ee6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 08:03:58 -0700 Subject: [PATCH 057/197] xaiger: update help text --- backends/aiger/xaiger.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 1006d56c6..b8d65de4e 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -762,10 +762,10 @@ struct XAigerBackend : public Backend { log(" write_xaiger [options] [filename]\n"); log("\n"); log("Write the top module (according to the (* top *) attribute or if only one module\n"); - log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_DFF_N_,\n"); - log(" $_DFF_P_, or non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n"); - log("pseudo-outputs. Whitebox contents will be taken from the '$holes'\n"); - log("module, if it exists.\n"); + log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, (optionally\n"); + log("$_DFF_N_, $_DFF_P_), or non (* abc9_box *) cells will be converted into psuedo-\n"); + log("inputs and pseudo-outputs. Whitebox contents will be taken from the\n"); + log("'$holes' module, if it exists.\n"); log("\n"); log(" -ascii\n"); log(" write ASCII version of AIGER format\n"); From b66904e9cdef8cd0e0019f9a1a3a7a13abdcc10c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 08:18:04 -0700 Subject: [PATCH 058/197] Revert "Merge branch 'eddie/kernel_makeblackbox' into eddie/abc9_auto_dff" This reverts commit e08497c7c9d8a6f7a3eccddf2149c45d9ecff207, reversing changes made to e366fd55122236a21c6daee6765724add840a1f9. --- kernel/rtlil.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 3e5896813..196e301b6 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -776,7 +776,6 @@ void RTLIL::Module::makeblackbox() connections_.clear(); remove(delwires); - set_bool_attribute(ID::blackbox); } From 509de98468973838aa3b3ff958084693434c8c83 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 08:53:07 -0700 Subject: [PATCH 059/197] submod: revert accidental change --- passes/hierarchy/submod.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc index 1f30a5160..2db7cf26b 100644 --- a/passes/hierarchy/submod.cc +++ b/passes/hierarchy/submod.cc @@ -389,7 +389,7 @@ struct SubmodPass : public Pass { while (did_something) { did_something = false; std::vector queued_modules; - for (auto mod : design->selected_modules()) + for (auto mod : design->modules()) if (handled_modules.count(mod->name) == 0 && design->selected_whole_module(mod->name)) queued_modules.push_back(mod->name); for (auto &modname : queued_modules) From a52f779ecae79be5ea79bd27f04837e7031f8415 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 10:36:07 -0700 Subject: [PATCH 060/197] ecp5: (* abc9_flop *) gated behind YOSYS --- techlibs/ecp5/cells_sim.v | 2 ++ 1 file changed, 2 insertions(+) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 69685683f..563592218 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -294,7 +294,9 @@ endmodule // --------------------------------------- +`ifdef YOSYS (* abc9_flop=(SRMODE != "ASYNC"), lib_whitebox=(SRMODE != "ASYNC") *) +`endif module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); parameter GSR = "ENABLED"; parameter [127:0] CEMUX = "1"; From 043ad8e76cd45bb573c804ffddb4a478cd4a99d4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 11:10:48 -0700 Subject: [PATCH 061/197] abc9_ops: use new 'design -delete' and 'select -unset' --- passes/techmap/abc9.cc | 20 +++++--------------- passes/techmap/abc9_ops.cc | 3 ++- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 97ee57aaa..adb28189e 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -309,15 +309,10 @@ struct Abc9Pass : public ScriptPass run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); - if (!help_mode) { - // TODO: Need a way to delete saved designs? - auto it = saved_designs.find("$abc9_map"); - delete it->second; - saved_designs.erase(it); - // TODO: Need a way to delete selections - active_design->selection_vars.erase(ID($abc9_flops)); - active_design->selection_vars.erase(ID($abc9_cells)); - } + run("design -delete $abc9"); + run("design -delete $abc9_map"); + run("select -unset $abc9_flops"); + run("select -unset $abc9_cells"); } } @@ -423,12 +418,7 @@ struct Abc9Pass : public ScriptPass if (dff_mode || help_mode) { run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell // ($_DFF_[NP]_ already shorted by -reintegrate) - if (!help_mode) { - // TODO: Need a way to delete saved designs? - auto it = saved_designs.find("$abc9_unmap"); - delete it->second; - saved_designs.erase(it); - } + run("design -delete $abc9_unmap"); } } } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index c640d06f8..57f51503c 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1204,7 +1204,8 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" -prep_dff_hier\n"); log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); - log(" store such modules in named selection '$abc9_flops'.\n"); + log(" store such modules in named selection '$abc9_flops'. store one cell\n"); + log(" instantiating each derived module into named selection '$abc9_cells'.\n"); log("\n"); log(" -prep_dff_map\n"); log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); From 489e83fc1ea7051cc400b043f75ce1ad359038f0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 11:38:44 -0700 Subject: [PATCH 062/197] abc9_ops: do away with '$abc9_cells' selection --- passes/techmap/abc9.cc | 1 - passes/techmap/abc9_ops.cc | 69 +++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index adb28189e..bddf9d2d9 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -312,7 +312,6 @@ struct Abc9Pass : public ScriptPass run("design -delete $abc9"); run("design -delete $abc9_map"); run("select -unset $abc9_flops"); - run("select -unset $abc9_cells"); } } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 57f51503c..d15da348a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -122,14 +122,11 @@ void mark_scc(RTLIL::Module *module) void prep_dff_hier(RTLIL::Design *design) { - pool seen; - dict selection_vars; auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); log_assert(r.second); - auto r2 YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_cells), RTLIL::Selection(false))); - log_assert(r2.second); auto &modules_sel = design->selection_vars.at(ID($abc9_flops)); - auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); + + Design *unmap_design = new Design; for (auto module : design->selected_modules()) for (auto cell : module->cells()) { @@ -142,16 +139,24 @@ void prep_dff_hier(RTLIL::Design *design) auto derived_module = design->module(derived_type); if (!derived_module->get_bool_attribute(ID::abc9_flop)) continue; - // And remember one representative cell (for its parameters) + // And create the stub in the $abc9_unmap design if (!modules_sel.selected_whole_module(derived_type)) { if (derived_type != cell->type) modules_sel.select(inst_module); modules_sel.select(derived_module); - cells_sel.select(module, cell); + + auto unmap_module = unmap_design->addModule(derived_type.str() + "_$abc9_flop"); + auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + for (const auto &conn : cell->connections()) + unmap_cell->setPort(conn.first, SigSpec()); + unmap_cell->parameters = cell->parameters; } } } + + auto r2 YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); + log_assert(r2.second); } void prep_dff_map(RTLIL::Design *design) @@ -225,46 +230,32 @@ continue_outer_loop: ; void prep_dff_unmap(RTLIL::Design *design) { - dict derived_to_cell; - const auto &cells_sel = design->selection_vars.at(ID($abc9_cells)); - for (auto &i : cells_sel.selected_members) { - auto module = design->module(i.first); - for (auto cell_name : i.second) { - auto cell = module->cell(cell_name); - log_assert(cell); - auto inst_module = design->module(cell->type); - log_assert(inst_module); - auto derived_type = inst_module->derive(design, cell->parameters); - derived_to_cell.insert(std::make_pair(derived_type, cell)); - } - } - - Design *unmap_design = new Design; + Design *unmap_design = saved_designs.at("$abc9_unmap"); // Create the reverse techmap rule -- (* abc9_box *) back to flop - for (const auto &i : derived_to_cell) { - auto module_name = i.first; - auto flop_module = design->module(module_name.str() + "_$abc9_flop"); + for (auto module : unmap_design->modules()) { + auto flop_module = design->module(module->name.str()); if (!flop_module) continue; // May not exist if init = 1'b1 - auto unmap_module = unmap_design->addModule(flop_module->name); + auto unmap_module = unmap_design->module(flop_module->name); + log_assert(unmap_module); for (auto port : flop_module->ports) { auto w = unmap_module->addWire(port, flop_module->wire(port)); + // Do not propagate (* init *) values inside the box w->attributes.erase(ID::init); } unmap_module->ports = flop_module->ports; unmap_module->check(); - auto orig_cell = i.second; - auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, orig_cell->type); - for (const auto &conn : orig_cell->connections()) - unmap_cell->setPort(conn.first, unmap_module->wire(conn.first)); - unmap_cell->parameters = orig_cell->parameters; + auto unmap_cell = unmap_module->cell(ID::_TECHMAP_REPLACE_); + log_assert(unmap_cell); + for (const auto &conn : unmap_cell->connections()) { + auto rhs = unmap_module->wire(conn.first); + log_assert(rhs); + unmap_cell->setPort(conn.first, rhs); + } } - - auto r YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); - log_assert(r.second); } void prep_xaiger(RTLIL::Module *module, bool dff) @@ -1204,8 +1195,8 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" -prep_dff_hier\n"); log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); - log(" store such modules in named selection '$abc9_flops'. store one cell\n"); - log(" instantiating each derived module into named selection '$abc9_cells'.\n"); + log(" store such modules in named selection '$abc9_flops'. create stubs within\n"); + log(" a new '$abc9_unmap' design to be used by -prep_dff_unmap.\n"); log("\n"); log(" -prep_dff_map\n"); log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); @@ -1214,9 +1205,9 @@ struct Abc9OpsPass : public Pass { log(" a submodule.\n"); log("\n"); log(" -prep_dff_unmap\n"); - log(" create a new design '$abc9_unmap' containing techmap rules that map\n"); - log(" *_$abc9_flop cells back into their original (* abc9_flop *) cells\n"); - log(" (including their original parameters).\n"); + log(" fill in previously created '$abc9_unmap' design to contain techmap rules\n"); + log(" for mapping *_$abc9_flop cells back into their original (* abc9_flop *)\n"); + log(" cells(including their original parameters).\n"); log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); From 8bad885e782181837c710f738f6184bd473d88ae Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 12:35:12 -0700 Subject: [PATCH 063/197] abc9_ops: -prep_dff_map to check $_DFF_[NP]_.Q drives module output --- passes/techmap/abc9_ops.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d15da348a..2f1b531e2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -175,6 +175,10 @@ void prep_dff_map(RTLIL::Design *design) // because ABC9 doesn't support them Q = cell->getPort(ID::Q); log_assert(GetSize(Q.wire) == 1); + + if (!Q.wire->port_output) + log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(module), log_id(cell->type)); + Const init = Q.wire->attributes.at(ID::init, State::Sx); log_assert(GetSize(init) == 1); if (init != State::S0) { @@ -1207,7 +1211,7 @@ struct Abc9OpsPass : public Pass { log(" -prep_dff_unmap\n"); log(" fill in previously created '$abc9_unmap' design to contain techmap rules\n"); log(" for mapping *_$abc9_flop cells back into their original (* abc9_flop *)\n"); - log(" cells(including their original parameters).\n"); + log(" cells (including their original parameters).\n"); log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); From 0d84ff3fc47fbc17184e706ea3ef1ee801f19790 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Apr 2020 12:56:28 -0700 Subject: [PATCH 064/197] Revert "ecp5: replace ecp5_ffinit with techmap rules + dff2dffs -match-init" This reverts commit 8c702b6cc0221a00021a3e4661c883bb591c924b. --- techlibs/ecp5/Makefile.inc | 3 +- techlibs/ecp5/cells_map.v | 264 ++++++++---------------------------- techlibs/ecp5/synth_ecp5.cc | 3 +- 3 files changed, 57 insertions(+), 213 deletions(-) diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 6bc9c854e..217151e96 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -1,5 +1,6 @@ -OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_gsr.o +OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \ + techlibs/ecp5/ecp5_gsr.o GENFILES += techlibs/ecp5/bram_init_1_2_4.vh GENFILES += techlibs/ecp5/bram_init_9_18_36.vh diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index f8df08eab..c031703a9 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -1,223 +1,65 @@ -(* techmap_celltype = "$_DFF_N_ $_DFF_P_" *) -module \$_DFF_x_ (input D, C, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") - localparam CLKMUX = "INV"; - else - localparam CLKMUX = "CLK"; - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - localparam REGSET = "SET"; - else - localparam REGSET = "RESET"; - endgenerate - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET)) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); -endmodule +module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule +module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule -(* techmap_celltype = "$_DFFE_NN_ $_DFFE_PN_ $_DFFE_NP_ $_DFFE_PP_" *) -module \$_DFFE_xx_ (input D, C, E, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") - localparam CLKMUX = "INV"; - else - localparam CLKMUX = "CLK"; - if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") - localparam CEMUX = "INV"; - else - localparam CEMUX = "CE"; - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - localparam REGSET = "SET"; - else - localparam REGSET = "RESET"; - endgenerate - TRELLIS_FF #(.GSR("AUTO"), .CEMUX(CEMUX), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET)) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); -endmodule +module \$_DFFE_NN_ (input D, C, E, output Q); 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)); endmodule +module \$_DFFE_PN_ (input D, C, E, output Q); 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)); endmodule -(* techmap_celltype = "$_DFF_NN0_ $_DFF_NN1_ $_DFF_PN0_ $_DFF_PN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PP0_ $_DFF_PP1_" *) -module \$_DFF_xxx_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") - localparam CLKMUX = "INV"; - else - localparam CLKMUX = "CLK"; - // TODO: Why not use LSRMUX param? - if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") - wire LSR_ = !R; - else - wire LSR_ = R; - if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin - localparam REGSET = "SET"; - if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("ECP5 doesn't support FFs with asynchronous set initialized to 0"); - end - else begin - localparam REGSET = "RESET"; - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("ECP5 doesn't support FFs with asynchronous reset initialized to 1"); - end - endgenerate - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(LSR_), .DI(D), .Q(Q)); -endmodule +module \$_DFFE_NP_ (input D, C, E, output Q); 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)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); 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)); endmodule -(* techmap_celltype = "$__DFFS_NN0_ $__DFFS_NN1_ $__DFFS_PN0_ $__DFFS_PN1_ $__DFFS_NP0_ $__DFFS_NP1_ $__DFFS_PP0_ $__DFFS_PP1_" *) -module \$__DFFS_xxx_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") - localparam CLKMUX = "INV"; - else - localparam CLKMUX = "CLK"; - // TODO: Why not use LSRMUX param? - if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") - wire LSR_ = !R; - else - wire LSR_ = R; - if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin - localparam REGSET = "SET"; - if (_TECHMAP_WIREINIT_Q_ === 1'b0) - // init is 0, reset to 1 - wire D_ = D || LSR_; - else - wire D_ = D; - end - else begin - localparam REGSET = "RESET"; - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - // init is 1, reset to 0 - wire D_ = !(D && LSR_); - else - wire D_ = D; - end - endgenerate - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(LSR_), .DI(D_), .Q(Q)); -endmodule +module \$_DFF_NN0_ (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)); endmodule +module \$_DFF_NN1_ (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)); endmodule +module \$_DFF_PN0_ (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)); endmodule +module \$_DFF_PN1_ (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)); endmodule -(* techmap_celltype = "$__DFFE_NN0 $__DFFE_NN1 $__DFFE_PN0 $__DFFE_PN1 $__DFFE_NP0 $__DFFE_NP1 $__DFFE_PP0 $__DFFE_PP1" *) -module \$__DFFE_xxx_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") - localparam CLKMUX = "INV"; - else - localparam CLKMUX = "CLK"; - // TODO: Why not use LSRMUX param? - if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") - wire LSR_ = !R; - else - wire LSR_ = R; - if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin - if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("ECP5 doesn't support FFs with asynchronous set initialized to 0"); - else - localparam REGSET = "SET"; - end - else begin - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("ECP5 doesn't support FFs with asynchronous reset initialized to 1"); - else - localparam REGSET = "RESET"; - end - endgenerate - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(LSR_), .DI(D), .Q(Q)); -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)); 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)); 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)); 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)); endmodule -(* techmap_celltype = "$__DFFSE_NN0 $__DFFSE_NN1 $__DFFSE_PN0 $__DFFSE_PN1 $__DFFSE_NP0 $__DFFSE_NP1 $__DFFSE_PP0 $__DFFSE_PP1" *) -module \$__DFFSE_xxx_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") - localparam CLKMUX = "INV"; - else - localparam CLKMUX = "CLK"; - // TODO: Why not use LSRMUX param? - if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") - wire LSR_ = !R; - else - wire LSR_ = R; - if (_TECHMAP_CELLTYPE_[1*8+:8] == "1") begin - localparam REGSET = "SET"; - if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin - // init is 0, reset to 1 - wire D_ = D || LSR_; - wire E_ = E || LSR_; - end - else begin - wire D_ = D; - wire E_ = E; - end - end - else begin - localparam REGSET = "RESET"; - if (_TECHMAP_WIREINIT_Q_ === 1'b1) begin - // init is 1, reset to 0 - wire D_ = !(D && LSR_); - wire E_ = !(E && LSR_); - end - else begin - wire D_ = D; - wire E_ = E; - end - end - endgenerate - TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX(CLKMUX), .LSRMUX("LSR"), .REGSET(REGSET), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E_), .LSR(LSR_), .DI(D_), .Q(Q)); -endmodule +module \$__DFFS_NN0_ (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)); endmodule +module \$__DFFS_NN1_ (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)); endmodule +module \$__DFFS_PN0_ (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)); endmodule +module \$__DFFS_PN1_ (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)); endmodule + +module \$__DFFS_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)); endmodule +module \$__DFFS_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)); endmodule +module \$__DFFS_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)); endmodule +module \$__DFFS_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)); endmodule + +module \$__DFFE_NN0 (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)); endmodule +module \$__DFFE_NN1 (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)); endmodule +module \$__DFFE_PN0 (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)); endmodule +module \$__DFFE_PN1 (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)); endmodule + +module \$__DFFE_NP0 (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)); endmodule +module \$__DFFE_NP1 (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)); endmodule +module \$__DFFE_PP0 (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)); endmodule +module \$__DFFE_PP1 (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)); endmodule + +module \$__DFFSE_NN0 (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)); endmodule +module \$__DFFSE_NN1 (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)); endmodule +module \$__DFFSE_PN0 (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)); endmodule +module \$__DFFSE_PN1 (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)); endmodule + +module \$__DFFSE_NP0 (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)); endmodule +module \$__DFFSE_NP1 (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)); endmodule +module \$__DFFSE_PP0 (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)); endmodule +module \$__DFFSE_PP1 (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)); endmodule `ifdef ASYNC_PRLD -(* techmap_celltype = "$_DLATCH_N_ $_DLATCH_P_" *) -module \$_DLATCH_x_ (input E, input D, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - // TODO: Why not use LSRMUX param? - if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") - wire LSR_ = !E; - else - wire LSR_ = E; - if (_TECHMAP_WIREINIT_Q_ !== 1'bx) - $error("ECP5 doesn't support latches with initial values"); // TODO: Check - endgenerate - TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(LSR_), .DI(1'b0), .M(D), .Q(Q)); -endmodule +module \$_DLATCH_N_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(!E), .DI(1'b0), .M(D), .Q(Q)); endmodule +module \$_DLATCH_P_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(E), .DI(1'b0), .M(D), .Q(Q)); endmodule -(* techmap_celltype = "$_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_PNN_ $_DFFSR_PNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PPN_ $_DFFSR_PPP_" *) -module \$_DFFSR_xxx_ (input C, S, R, D, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - parameter _TECHMAP_CELLTYPE_ = ""; - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - generate - if (_TECHMAP_CELLTYPE_[3*8+:8] == "N") - localparam CLKMUX = "INV"; - else - localparam CLKMUX = "CLK"; - if (_TECHMAP_CELLTYPE_[2*8+:8] == "N") - wire S_ = !S; - else - wire S_ = S; - if (_TECHMAP_CELLTYPE_[1*8+:8] == "N") - wire R_ = !R; - else - wire R_ = R; - if (_TECHMAP_WIREINIT_Q_ !== 1'bx) - $error("ECP5 doesn't support FFs with asynchronous set and reset with initial values"); - endgenerate +module \$_DFFSR_NNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_NNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule +module \$_DFFSR_NPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_NPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule - TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX(CLKINV), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S_ || R_), .DI(D), .M(!R_), .Q(Q)); -endmodule +module \$_DFFSR_PNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_PNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule +module \$_DFFSR_PPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_PPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule `endif `include "cells_ff.vh" diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index ecc5039e6..8039531ae 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -311,7 +311,7 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("map_ffs")) { - run("dff2dffs -match-init"); + run("dff2dffs"); run("opt_clean"); if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); @@ -320,6 +320,7 @@ struct SynthEcp5Pass : public ScriptPass run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); + run("ecp5_ffinit"); run("ecp5_gsr"); run("attrmvcp -copy -attr syn_useioff"); run("opt_clean"); From fb447951be5ac481106f06a911234614b576b40f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 09:38:29 -0700 Subject: [PATCH 065/197] abc9: cleanup --- passes/techmap/abc9.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index bddf9d2d9..b57ea3cf7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -280,7 +280,8 @@ struct Abc9Pass : public ScriptPass if (check_label("dff", "(only if -dff)")) { if (dff_mode || help_mode) { - run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules + run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules, + // create stubs in $abc9_unmap design run("design -stash $abc9"); run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in run("proc"); @@ -288,8 +289,11 @@ struct Abc9Pass : public ScriptPass run("techmap"); run("opt"); run("abc9_ops -prep_dff_map"); // rewrite specify - // TODO: Select fan-in cone $_DFF_[NP]_.Q - run("setattr -set submod \"$abc9_flop\" t:* t:$_DFF_N_ %d t:$_DFF_P_ %d"); + // select all $_DFF_[NP]_ + // then select all its fanins + // then select all fanouts of all that + // lastly remove $_DFF_[NP]_ cells + run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); run("submod"); run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out run("delete *_$abc9_flop"); @@ -306,12 +310,12 @@ struct Abc9Pass : public ScriptPass } run("design -stash $abc9_map"); run("design -load $abc9"); - run("abc9_ops -prep_dff_unmap"); // create $abc9_unmap design - run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); run("design -delete $abc9"); - run("design -delete $abc9_map"); run("select -unset $abc9_flops"); + run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design + run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + run("design -delete $abc9_map"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); } } From 6f4f795953b2a38ec77984c7e1b50f579b59272e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 12:15:36 -0700 Subject: [PATCH 066/197] aiger/xaiger: use odd for negedge clk, even for posedge Since abc9 doesn't like negative mergeability values --- backends/aiger/xaiger.cc | 16 ++++++++++------ frontends/aiger/aigerparse.cc | 7 +++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index b8d65de4e..e2d8e1e7f 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -627,21 +627,25 @@ struct XAigerWriter write_s_buffer(ff_bits.size()); dict clk_to_mergeability; + for (const auto &i : ff_bits) { + const Cell *cell = i.second; + log_assert(cell->type.in(ID($_DFF_N_), ID($_DFF_P_))); + + SigBit clock = sigmap(cell->getPort(ID::C)); + clk_to_mergeability.insert(std::make_pair(clock, clk_to_mergeability.size()*2+1)); + } for (const auto &i : ff_bits) { const SigBit &d = i.first; const Cell *cell = i.second; - log_assert(cell->type.in(ID($_DFF_N_), ID($_DFF_P_))); - SigBit clock = sigmap(cell->getPort(ID::C)); - auto r = clk_to_mergeability.insert(std::make_pair(clock, clk_to_mergeability.size() + 1)); - int mergeability = r.first->second; + int mergeability = clk_to_mergeability.at(clock); log_assert(mergeability > 0); if (cell->type == ID($_DFF_N_)) - write_r_buffer(-mergeability); - else if (cell->type == ID($_DFF_P_)) write_r_buffer(mergeability); + else if (cell->type == ID($_DFF_P_)) + write_r_buffer(mergeability+1); else log_abort(); SigBit Q = sigmap(cell->getPort(ID::Q)); diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index ed3a926c6..16e94c394 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -789,13 +789,12 @@ void AigerReader::post_process() Cell* ff; int clock_index = mergeability[i]; - if (clock_index < 0) { + if (clock_index & 1) { ff = module->addCell(NEW_ID, ID($_DFF_N_)); - clock_index = -clock_index; + clock_index--; } - else if (clock_index > 0) + else ff = module->addCell(NEW_ID, ID($_DFF_P_)); - else log_abort(); auto r = mergeability_to_clock.insert(clock_index); if (r.second) r.first->second = module->addWire(NEW_ID); From 762b6ad74a49f125ef1999794cba7ece9ca3839f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 12:27:26 -0700 Subject: [PATCH 067/197] xilinx: remove no-longer-relevant test --- tests/arch/xilinx/abc9_map.ys | 91 ----------------------------------- 1 file changed, 91 deletions(-) delete mode 100644 tests/arch/xilinx/abc9_map.ys diff --git a/tests/arch/xilinx/abc9_map.ys b/tests/arch/xilinx/abc9_map.ys deleted file mode 100644 index 4a7b9384a..000000000 --- a/tests/arch/xilinx/abc9_map.ys +++ /dev/null @@ -1,91 +0,0 @@ -read_verilog < Date: Wed, 15 Apr 2020 12:28:03 -0700 Subject: [PATCH 068/197] xilinx: update abc9_dff tests --- tests/arch/xilinx/abc9_dff.ys | 63 +++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/tests/arch/xilinx/abc9_dff.ys b/tests/arch/xilinx/abc9_dff.ys index b457cefce..abe597e2c 100644 --- a/tests/arch/xilinx/abc9_dff.ys +++ b/tests/arch/xilinx/abc9_dff.ys @@ -1,32 +1,59 @@ +logger -nowarn "Yosys has only limited support for tri-state logic at the moment\. .*" + read_verilog < Date: Wed, 15 Apr 2020 15:41:55 -0700 Subject: [PATCH 069/197] abc9: suppress warnings when no compatible + used flop boxes formed --- passes/techmap/abc9.cc | 61 +++++++++++++++++++++-------------- passes/techmap/abc9_ops.cc | 39 +++++++++++++++------- tests/arch/xilinx/abc9_dff.ys | 4 ++- 3 files changed, 66 insertions(+), 38 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index b57ea3cf7..1a5604f7d 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -281,41 +281,52 @@ struct Abc9Pass : public ScriptPass if (check_label("dff", "(only if -dff)")) { if (dff_mode || help_mode) { run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules, - // create stubs in $abc9_unmap design + // create stubs in $abc9_unmap design run("design -stash $abc9"); run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in run("proc"); run("wbflip"); run("techmap"); run("opt"); + if (!help_mode) + active_design->scratchpad_unset("abc9_ops.prep_dff_map.did_something"); run("abc9_ops -prep_dff_map"); // rewrite specify - // select all $_DFF_[NP]_ - // then select all its fanins - // then select all fanouts of all that - // lastly remove $_DFF_[NP]_ cells - run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); - run("submod"); - run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out - run("delete *_$abc9_flop"); - if (help_mode) { - run("foreach module in design"); - run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_map.did_something"); + if (did_something) { + // select all $_DFF_[NP]_ + // then select all its fanins + // then select all fanouts of all that + // lastly remove $_DFF_[NP]_ cells + run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); + run("submod"); + run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out + run("delete *_$abc9_flop"); + if (help_mode) { + run("foreach module in design"); + run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + } + else { + // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs + for (auto module : active_design->selected_modules()) { + active_design->selected_active_module = module->name.str(); + if (module->cell(stringf("%s_$abc9_flop", module->name.c_str()))) + run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); + } + } + run("design -stash $abc9_map"); + run("design -load $abc9"); + run("design -delete $abc9"); + run("select -unset $abc9_flops"); + run("techmap -wb -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + run("design -delete $abc9_map"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); + run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design } else { - // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs - for (auto module : active_design->selected_modules()) { - active_design->selected_active_module = module->name.str(); - run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); - } + run("design -load $abc9"); + run("design -delete $abc9"); + run("select -unset $abc9_flops"); } - run("design -stash $abc9_map"); - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design - run("techmap -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ - run("design -delete $abc9_map"); - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); } } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2f1b531e2..e00a4dc81 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -161,10 +161,23 @@ void prep_dff_hier(RTLIL::Design *design) void prep_dff_map(RTLIL::Design *design) { + Design *unmap_design = saved_designs.at("$abc9_unmap"); + for (auto module : design->modules()) { vector specify_cells; SigBit D, Q; Cell* dff_cell = nullptr; + + // If module has a public name (i.e. not $paramod) and it doesn't exist + // in the $abc9_unmap then it means only derived modules were + // instantiated, so make this a blackbox + if (module->name[0] == '\\' && !unmap_design->module(module->name.str() + "_$abc9_flop")) { + module->makeblackbox(); + module->set_bool_attribute(ID::blackbox, false); + module->set_bool_attribute(ID::whitebox, true); + continue; + } + for (auto cell : module->cells()) if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { if (dff_cell) @@ -185,6 +198,7 @@ void prep_dff_map(RTLIL::Design *design) log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); module->makeblackbox(); + module->set_bool_attribute(ID::blackbox, false); auto wire = module->addWire(ID(_TECHMAP_FAIL_)); wire->set_bool_attribute(ID::keep); @@ -215,19 +229,20 @@ void prep_dff_map(RTLIL::Design *design) D = w; } - if (GetSize(specify_cells) == 0) { - log_warning("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); - } - else { - // Rewrite $specify cells that end with $_DFF_[NP]_.Q - // to $_DFF_[NP]_.D since it will be moved into - // the submodule - for (auto cell : specify_cells) { - auto DST = cell->getPort(ID::DST); - DST.replace(Q, D); - cell->setPort(ID::DST, DST); - } + if (GetSize(specify_cells) == 0) + log_error("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); + + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); } + + design->scratchpad_set_bool("abc9_ops.prep_dff_map.did_something", true); + continue_outer_loop: ; } } diff --git a/tests/arch/xilinx/abc9_dff.ys b/tests/arch/xilinx/abc9_dff.ys index abe597e2c..15343970f 100644 --- a/tests/arch/xilinx/abc9_dff.ys +++ b/tests/arch/xilinx/abc9_dff.ys @@ -14,6 +14,7 @@ endmodule EOT equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf design -load postopt +select -assert-count 6 t:FD* select -assert-count 6 c:fd2 c:fd3 c:fd4 c:fd6 c:fd7 c:fd8 @@ -32,6 +33,7 @@ endmodule EOT equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf design -load postopt +select -assert-count 4 t:FD* select -assert-count 4 c:fd3 c:fd4 c:fd7 c:fd8 @@ -54,6 +56,6 @@ logger -expect warning "Module 'FDSE' contains a \$_DFF_P_ cell .*" 1 logger -expect warning "Module '\$paramod\\FDSE_1\\INIT=1' contains a \$_DFF_N_ cell .*" 1 equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf design -load postopt -#select -assert-count 4 c:fd3 c:fd4 c:fd7 c:fd8 +select -assert-count 8 t:FD* logger -expect-no-warnings From c52bb11fb6a4a34ba702e35c2950efb978b953ad Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 15:50:57 -0700 Subject: [PATCH 070/197] abc9_ops: more robust --- passes/techmap/abc9_ops.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index e00a4dc81..544fefdfb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -641,7 +641,8 @@ void prep_box(RTLIL::Design *design) log_assert(num_outputs == 1); ss << log_id(module) << " " << r.first->second.as_int(); - ss << " " << (module->get_bool_attribute(ID::whitebox) ? "1" : "0"); + log_assert(module->get_bool_attribute(ID::whitebox)); + ss << " " << "1"; ss << " " << num_inputs << " " << num_outputs << std::endl; ss << "#"; @@ -659,6 +660,9 @@ void prep_box(RTLIL::Design *design) ss << std::endl; auto &t = timing.setup_module(module).required; + if (t.empty()) + log_error("Module '%s' with (* abc9_flop *) has no clk-to-q timing (and thus no connectivity) information.\n", log_id(module)); + first = true; for (auto port_name : module->ports) { auto wire = module->wire(port_name); @@ -671,8 +675,8 @@ void prep_box(RTLIL::Design *design) log_assert(GetSize(wire) == 1); auto it = t.find(TimingInfo::NameBit(port_name,0)); if (it == t.end()) - // Assume that no setup time means zero - ss << 0; + // Assume no connectivity if no setup time + ss << "-"; else { ss << it->second; @@ -743,9 +747,11 @@ void prep_box(RTLIL::Design *design) } ss << std::endl; - auto &t = timing.setup_module(module).comb; - if (t.empty()) - log_warning("(* abc9_box *) module '%s' has no timing (and thus no connectivity) information.\n", log_id(module)); + auto &t = timing.setup_module(module); + if (t.comb.empty()) + log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module)); + if (!t.arrival.empty() || !t.required.empty()) + log_error("Module '%s' with (* abc9_box *) has setup and/or edge-sensitive timing information.\n", log_id(module)); for (const auto &o : outputs) { first = true; @@ -754,8 +760,8 @@ void prep_box(RTLIL::Design *design) first = false; else ss << " "; - auto jt = t.find(TimingInfo::BitBit(i,o)); - if (jt == t.end()) + auto jt = t.comb.find(TimingInfo::BitBit(i,o)); + if (jt == t.comb.end()) ss << "-"; else ss << jt->second; From ec4bbb1444b24d36c03a6635738e34b652e5aa1b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 16:13:57 -0700 Subject: [PATCH 071/197] abc9: generate $abc9_holes design instead of $holes --- backends/aiger/xaiger.cc | 12 +++++++++--- passes/techmap/abc9.cc | 18 +++++++++++------- passes/techmap/abc9_ops.cc | 16 ++++++++-------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index e2d8e1e7f..17a2748dc 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -676,7 +676,13 @@ struct XAigerWriter f.write(reinterpret_cast(&buffer_size_be), sizeof(buffer_size_be)); f.write(buffer_str.data(), buffer_str.size()); - RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); + RTLIL::Design *holes_design; + auto it = saved_designs.find("$abc9_holes"); + if (it != saved_designs.end()) + holes_design = it->second; + else + holes_design = nullptr; + RTLIL::Module *holes_module = holes_design ? holes_design->module(module->name) : nullptr; if (holes_module) { std::stringstream a_buffer; XAigerWriter writer(holes_module, false /* dff_mode */, true /* holes_mode */); @@ -768,8 +774,8 @@ struct XAigerBackend : public Backend { log("Write the top module (according to the (* top *) attribute or if only one module\n"); log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, (optionally\n"); log("$_DFF_N_, $_DFF_P_), or non (* abc9_box *) cells will be converted into psuedo-\n"); - log("inputs and pseudo-outputs. Whitebox contents will be taken from the\n"); - log("'$holes' module, if it exists.\n"); + log("inputs and pseudo-outputs. Whitebox contents will be taken from the equivalent\n"); + log("module in the '$abc9_holes' design, if it exists.\n"); log("\n"); log(" -ascii\n"); log(" write ASCII version of AIGER format\n"); diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 1a5604f7d..dc96a765f 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -345,15 +345,18 @@ struct Abc9Pass : public ScriptPass else if (box_file.empty()) { run("abc9_ops -prep_box"); } - run("select -set abc9_holes A:abc9_holes"); - run("flatten -wb @abc9_holes"); - run("techmap @abc9_holes"); - run("opt -purge @abc9_holes"); + run("design -stash $abc9"); + run("design -load $abc9_holes"); + run("techmap -wb -map %$abc9 -map +/techmap.v"); + run("opt -purge"); run("aigmap"); - run("wbflip @abc9_holes"); + run("wbflip"); + run("design -stash $abc9_holes"); + run("design -load $abc9"); } if (check_label("map")) { + run("aigmap"); if (help_mode) { run("foreach module in selection"); run(" abc9_ops -write_lut /input.lut", "(skip if '-lut' or '-luts')"); @@ -372,7 +375,6 @@ struct Abc9Pass : public ScriptPass log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } - log_assert(!mod->attributes.count(ID::abc9_box_id)); log_push(); active_design->selection().select(mod); @@ -432,8 +434,10 @@ struct Abc9Pass : public ScriptPass if (dff_mode || help_mode) { run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell // ($_DFF_[NP]_ already shorted by -reintegrate) - run("design -delete $abc9_unmap"); + run("design -delete $abc9_unmap", " (only if -dff)"); } + if (saved_designs.count("$abc9_holes") || help_mode) + run("design -delete $abc9_holes"); } } } Abc9Pass; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 544fefdfb..ee25866c3 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -368,9 +368,13 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(no_loops); - RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); + auto r = saved_designs.emplace("$abc9_holes", nullptr); + if (r.second) + r.first->second = new Design; + RTLIL::Design *holes_design = r.first->second; + log_assert(holes_design); + RTLIL::Module *holes_module = holes_design->addModule(module->name); log_assert(holes_module); - holes_module->set_bool_attribute(ID::abc9_holes); dict cell_cache; TimingInfo timing; @@ -1246,9 +1250,8 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" -prep_xaiger\n"); log(" prepare the design for XAIGER output. this includes computing the\n"); - log(" topological ordering of ABC9 boxes, as well as preparing the\n"); - log(" '$holes' module that contains the logic behaviour of ABC9\n"); - log(" whiteboxes.\n"); + log(" topological ordering of ABC9 boxes, as well as preparing the '$abc9_holes'\n"); + log(" design that contains the logic behaviour of ABC9 whiteboxes.\n"); log("\n"); log(" -dff\n"); log(" consider flop cells (those instantiating modules marked with (* abc9_flop *))\n"); @@ -1388,9 +1391,6 @@ struct Abc9OpsPass : public Pass { prep_box(design); for (auto mod : design->selected_modules()) { - if (mod->get_bool_attribute(ID::abc9_holes)) - continue; - if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; From 4c6647a4693838978354183d5553717fa2d97a48 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 16:16:30 -0700 Subject: [PATCH 072/197] xaiger: always sort input/output bits by port id redundant for normal design, but necessary for holes --- backends/aiger/xaiger.cc | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 17a2748dc..6f0ed6e89 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -138,7 +138,7 @@ struct XAigerWriter return a; } - XAigerWriter(Module *module, bool dff_mode, bool holes_mode=false) : module(module), sigmap(module) + XAigerWriter(Module *module, bool dff_mode) : module(module), sigmap(module) { pool undriven_bits; pool unused_bits; @@ -411,16 +411,14 @@ struct XAigerWriter undriven_bits.erase(bit); } - if (holes_mode) { - struct sort_by_port_id { - bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { - return a.wire->port_id < b.wire->port_id || - (a.wire->port_id == b.wire->port_id && a.offset < b.offset); - } - }; - input_bits.sort(sort_by_port_id()); - output_bits.sort(sort_by_port_id()); - } + struct sort_by_port_id { + bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { + return a.wire->port_id < b.wire->port_id || + (a.wire->port_id == b.wire->port_id && a.offset < b.offset); + } + }; + input_bits.sort(sort_by_port_id()); + output_bits.sort(sort_by_port_id()); aig_map[State::S0] = 0; aig_map[State::S1] = 1; @@ -685,7 +683,7 @@ struct XAigerWriter RTLIL::Module *holes_module = holes_design ? holes_design->module(module->name) : nullptr; if (holes_module) { std::stringstream a_buffer; - XAigerWriter writer(holes_module, false /* dff_mode */, true /* holes_mode */); + XAigerWriter writer(holes_module, false /* dff_mode */); writer.write_aiger(a_buffer, false /*ascii_mode*/); f << "a"; From c41c180f68b161cfeb8b82efe06c56d02394a831 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 16:18:37 -0700 Subject: [PATCH 073/197] abc9: remove redundant wbflip --- passes/techmap/abc9.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index dc96a765f..fbb8356a5 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -350,7 +350,6 @@ struct Abc9Pass : public ScriptPass run("techmap -wb -map %$abc9 -map +/techmap.v"); run("opt -purge"); run("aigmap"); - run("wbflip"); run("design -stash $abc9_holes"); run("design -load $abc9"); } From 6c66030dfbcd93024f5f5bb602b9fcc58cb80a88 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 18 Feb 2020 17:59:33 -0800 Subject: [PATCH 074/197] Uncomment negative setup times; clamp to zero for connectivity --- techlibs/xilinx/cells_sim.v | 42 +++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 93d080ffd..5143f87da 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -36,6 +36,9 @@ module IBUF( parameter IOSTANDARD = "default"; parameter IBUF_LOW_PWR = 0; assign O = I; + specify + (I => O) = 0; + endspecify endmodule module IBUFG( @@ -57,6 +60,9 @@ module OBUF( parameter DRIVE = 12; parameter SLEW = "SLOW"; assign O = I; + specify + (I => O) = 0; + endspecify endmodule module IOBUF ( @@ -72,6 +78,10 @@ module IOBUF ( parameter SLEW = "SLOW"; assign IO = T ? 1'bz : I; assign O = IO; + specify + (I => IO) = 0; + (IO => O) = 0; + endspecify endmodule module OBUFT ( @@ -85,14 +95,20 @@ module OBUFT ( parameter IOSTANDARD = "DEFAULT"; parameter SLEW = "SLOW"; assign O = T ? 1'bz : I; + specify + (I => O) = 0; + endspecify endmodule module BUFG( (* clkbuf_driver *) output O, input I); - assign O = I; + specify + // https://github.com/SymbiFlow/prjxray-db/blob/4bc6385ab300b1819848371f508185f57b649a0e/artix7/timings/CLK_BUFG_TOP_R.sdf#L11 + (I => O) = 96; + endspecify endmodule module BUFGCTRL( @@ -499,8 +515,8 @@ module FDRE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& CE && !IS_C_INVERTED , -46); // Negative times not currently supported - //$setup(D , negedge C &&& CE && IS_C_INVERTED , -46); // Negative times not currently supported + $setup(D , posedge C &&& CE && !IS_C_INVERTED , /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& CE && IS_C_INVERTED , /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, posedge C &&& !IS_C_INVERTED, 109); $setup(CE, negedge C &&& IS_C_INVERTED, 109); @@ -529,7 +545,7 @@ module FDRE_1 ( always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 @@ -564,8 +580,8 @@ module FDSE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported - //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported + $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, posedge C &&& !IS_C_INVERTED, 109); $setup(CE, negedge C &&& IS_C_INVERTED, 109); @@ -594,7 +610,7 @@ module FDSE_1 ( always @(negedge C) if (S) Q <= 1'b1; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE, negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 @@ -667,8 +683,8 @@ module FDCE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported - //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported + $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , posedge C &&& !IS_C_INVERTED, 109); $setup(CE , negedge C &&& IS_C_INVERTED, 109); @@ -697,7 +713,7 @@ module FDCE_1 ( always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 @@ -734,8 +750,8 @@ module FDPE ( endgenerate specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , posedge C &&& !IS_C_INVERTED && CE, -46); // Negative times not currently supported - //$setup(D , negedge C &&& IS_C_INVERTED && CE, -46); // Negative times not currently supported + $setup(D , posedge C &&& !IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported + $setup(D , negedge C &&& IS_C_INVERTED && CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , posedge C &&& !IS_C_INVERTED, 109); $setup(CE , negedge C &&& IS_C_INVERTED, 109); @@ -764,7 +780,7 @@ module FDPE_1 ( always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; specify // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L249 - //$setup(D , negedge C &&& CE, -46); // Negative times not currently supported + $setup(D , negedge C &&& CE, /*-46*/ 0); // Negative times not currently supported // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 $setup(CE , negedge C, 109); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 From 4cec21b93e62e9c43a0ab9618c0111ee65e520c1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Apr 2020 16:29:11 -0700 Subject: [PATCH 075/197] abc9_ops: -prep_dff_map to error if async flop found --- passes/techmap/abc9_ops.cc | 12 +++++++----- techlibs/xilinx/cells_sim.v | 4 ---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index ee25866c3..62007c61e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -181,7 +181,7 @@ void prep_dff_map(RTLIL::Design *design) for (auto cell : module->cells()) if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { if (dff_cell) - log_error("More than one $_DFF_[NP]_ cell found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(module)); dff_cell = cell; // Block sequential synthesis on cells with (* init *) != 1'b0 @@ -207,10 +207,15 @@ void prep_dff_map(RTLIL::Design *design) goto continue_outer_loop; } } + else if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1), + ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1))) + log_error("Module '%s' with (* abc9_flop *) contains an asynchronous $_DFFE?_[NP][NP][01]_? cell, which is not supported for sequential synthesis.\n", log_id(module)); else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) specify_cells.emplace_back(cell); if (!dff_cell) - log_error("$_DFF_[NP]_ cell not found in module '%s' marked (* abc9_flop *)\n", log_id(module)); + log_error("Module '%s' with (* abc9_flop *) does not any contain $_DFF_[NP]_ cells.\n", log_id(module)); D = dff_cell->getPort(ID::D); @@ -229,9 +234,6 @@ void prep_dff_map(RTLIL::Design *design) D = w; } - if (GetSize(specify_cells) == 0) - log_error("Module '%s' marked (* abc9_flop *) contains no specify timing information.\n", log_id(module)); - // Rewrite $specify cells that end with $_DFF_[NP]_.Q // to $_DFF_[NP]_.D since it will be moved into // the submodule diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 5143f87da..25df3a865 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -656,7 +656,6 @@ module FDRSE ( Q <= d; endmodule -(* lib_whitebox *) module FDCE ( output reg Q, (* clkbuf_sink *) @@ -699,7 +698,6 @@ module FDCE ( endspecify endmodule -(* lib_whitebox *) module FDCE_1 ( output reg Q, (* clkbuf_sink *) @@ -724,7 +722,6 @@ module FDCE_1 ( endspecify endmodule -(* lib_whitebox *) module FDPE ( output reg Q, (* clkbuf_sink *) @@ -766,7 +763,6 @@ module FDPE ( endspecify endmodule -(* lib_whitebox *) module FDPE_1 ( output reg Q, (* clkbuf_sink *) From 7812a2959b9b23b44e8144f9edb139f282d623e1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 10:21:08 -0700 Subject: [PATCH 076/197] kernel: TimingInfo to clamp -ve setup/edge-sensitive delays to zero --- kernel/timinginfo.h | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index fb4e0930d..36908868c 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -128,11 +128,9 @@ struct TimingInfo int rise_max = cell->getParam(ID::T_RISE_MAX).as_int(); int fall_max = cell->getParam(ID::T_FALL_MAX).as_int(); int max = std::max(rise_max,fall_max); - if (max < 0) - log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - if (max <= 0) { - log_debug("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - continue; + if (max < 0) { + log_warning("Module '%s' contains specify cell '%s' with T_{RISE,FALL}_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); + max = 0; } for (const auto &d : dst) { auto &v = t.arrival[NameBit(d)]; @@ -152,11 +150,9 @@ struct TimingInfo if (!c.wire->port_input) log_error("Module '%s' contains specify cell '%s' where DST '%s' is not a module input.\n", log_id(module), log_id(cell), log_signal(dst)); int max = cell->getParam(ID::T_LIMIT_MAX).as_int(); - if (max < 0) - log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - if (max <= 0) { - log_debug("Module '%s' contains specify cell '%s' with T_LIMIT_MAX <= 0 which is currently unsupported. Ignoring.\n", log_id(module), log_id(cell)); - continue; + if (max < 0) { + log_warning("Module '%s' contains specify cell '%s' with T_LIMIT_MAX < 0 which is currently unsupported. Clamping to 0.\n", log_id(module), log_id(cell)); + max = 0; } for (const auto &s : src) { auto &v = t.required[NameBit(s)]; From 48052ad813db3561a959a1921466d571bafa354c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 10:24:02 -0700 Subject: [PATCH 077/197] abc9: add flop boxes to basic $_DFF_P_ and $_DFF_N_ too --- passes/techmap/abc9.cc | 19 ++++++++++--------- passes/techmap/abc9_ops.cc | 26 ++++++++++++++++---------- techlibs/common/Makefile.inc | 2 ++ techlibs/common/abc9_map.v | 21 +++++++++++++++++++++ techlibs/common/abc9_model.v | 20 ++++++++++++++++++++ techlibs/common/abc9_unmap.v | 12 ++++++++++++ tests/various/abc9.ys | 12 +++++++----- 7 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 techlibs/common/abc9_map.v create mode 100644 techlibs/common/abc9_unmap.v diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index fbb8356a5..911254aa6 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -314,23 +314,24 @@ struct Abc9Pass : public ScriptPass } } run("design -stash $abc9_map"); - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - run("techmap -wb -map %$abc9_map"); // techmap user design into submod + $_DFF_[NP]_ + } + run("design -load $abc9"); + run("design -delete $abc9"); + run("select -unset $abc9_flops"); + if (did_something) { // techmap user design into submod + $_DFF_[NP]_ + run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); run("design -delete $abc9_map"); run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design } - else { - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - } + else + run("techmap -wb -max_iter 1 -map +/abc9_map.v"); + } } if (check_label("pre")) { + run("read_verilog -icells -lib -specify +/abc9_model.v"); run("scc -set_attr abc9_scc_id {}"); if (help_mode) run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 62007c61e..976b6462e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -128,7 +128,7 @@ void prep_dff_hier(RTLIL::Design *design) Design *unmap_design = new Design; - for (auto module : design->selected_modules()) + for (auto module : design->modules()) for (auto cell : module->cells()) { auto inst_module = design->module(cell->type); if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { @@ -219,17 +219,23 @@ void prep_dff_map(RTLIL::Design *design) D = dff_cell->getPort(ID::D); - // Add a dummy enable mux feeding DFF.D to ensure that: - // (i) a driving cell exists, so that 'submod' will have - // an output port - // (ii) DFF.Q will exist in this submodule { - auto c = module->addCell(NEW_ID, ID($_MUX_)); + // Add dummy buffers for all module inputs/outputs + // to ensure that these ports exists in the flop box + // created by later submod pass + for (auto port_name : module->ports) { + auto port = module->wire(port_name); + log_assert(GetSize(port) == 1); + auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); + // Need to set (* keep *) otherwise opt_clean + // inside submod will blow it away + c->set_bool_attribute(ID::keep); + } + // Add an additional buffer that drives $_DFF_[NP]_.D + // so that the flop box will have an output auto w = module->addWire(NEW_ID); - c->setPort(ID::A, D); - c->setPort(ID::B, Q); - c->setPort(ID::S, State::S0); - c->setPort(ID::Y, w); + auto c = module->addBufGate(NEW_ID, D, w); + c->set_bool_attribute(ID::keep); dff_cell->setPort(ID::D, w); D = w; } diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 7b1e4b430..607e772a2 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -30,4 +30,6 @@ $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) $(eval $(call add_share_file,share,techlibs/common/cells.lib)) $(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) $(eval $(call add_share_file,share,techlibs/common/abc9_model.v)) +$(eval $(call add_share_file,share,techlibs/common/abc9_map.v)) +$(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v)) $(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v)) diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v new file mode 100644 index 000000000..b04a5b64f --- /dev/null +++ b/techlibs/common/abc9_map.v @@ -0,0 +1,21 @@ +(* techmap_celltype = "$_DFF_N_ $_DFF_P_" *) +module $_DFF_x_(input C, D, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + wire _TECHMAP_FAIL_ = 1; + else if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin + wire D_; + $__DFF_N__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $_DFF_N_ ff (.C(C), .D(D_), .Q(Q)); + end + else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin + wire D_; + $__DFF_P__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $_DFF_P_ ff (.C(C), .D(D_), .Q(Q)); + end + else if (_TECHMAP_CELLTYPE_ != "") + $error("Unrecognised _TECHMAP_CELLTYPE_"); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v index 9e8048faf..41acf4d97 100644 --- a/techlibs/common/abc9_model.v +++ b/techlibs/common/abc9_model.v @@ -5,3 +5,23 @@ module \$__ABC9_DELAY (input I, output O); (I => O) = DELAY; endspecify endmodule + +(* abc9_flop, abc9_box, lib_whitebox *) +module $__DFF_N__$abc9_flop(input C, D, Q, (* init=INIT *) output n1); + parameter [0:0] INIT = 1'bx; + assign n1 = D; + specify + $setup(D, posedge C, 0); + (posedge C => (n1:D)) = 0; + endspecify +endmodule + +(* abc9_flop, abc9_box, lib_whitebox *) +module $__DFF_P__$abc9_flop(input C, D, Q, (* init=INIT *) output n1); + parameter [0:0] INIT = 1'bx; + assign n1 = D; + specify + $setup(D, posedge C, 0); + (posedge C => (n1:D)) = 0; + endspecify +endmodule diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v new file mode 100644 index 000000000..0fd07207d --- /dev/null +++ b/techlibs/common/abc9_unmap.v @@ -0,0 +1,12 @@ +(* techmap_celltype = "$__DFF_N__$abc9_flop $__DFF_P__$abc9_flop" *) +module $__DFF_x__$abc9_flop (input C, D, Q, (* init = INIT *) output n1); + parameter [0:0] INIT = 1'bx; + parameter _TECHMAP_CELLTYPE_ = ""; + generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N__$abc9_flop") + $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else if (_TECHMAP_CELLTYPE_ == "$__DFF_P__$abc9_flop") + $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else if (_TECHMAP_CELLTYPE_ != "") + $error("Unrecognised _TECHMAP_CELLTYPE_"); + endgenerate +endmodule diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys index 6e2415ad7..7a3a503e4 100644 --- a/tests/various/abc9.ys +++ b/tests/various/abc9.ys @@ -45,14 +45,16 @@ sat -seq 10 -verify -prove-asserts -show-ports miter design -reset read_verilog -icells < Date: Thu, 16 Apr 2020 10:25:22 -0700 Subject: [PATCH 078/197] Revert "Merge pull request #1917 from YosysHQ/eddie/abc9_delay_check" This reverts commit 759283fa65b1195ebe3a5bc6890ec622febca0eb, reversing changes made to f41c7ccfff4bf104c646ca4b85e079a0f91c9151. --- backends/aiger/xaiger.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 6f0ed6e89..ddda1bd5a 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -293,10 +293,6 @@ struct XAigerWriter if (abc9_flop) continue; } - else { - if (cell->type == ID($__ABC9_DELAY)) - log_error("Cell type '%s' not recognised. Check that '+/abc9_model.v' has been read.\n", cell->type.c_str()); - } bool cell_known = inst_module || cell->known(); for (const auto &c : cell->connections()) { From 8fbb55f4aba9ccb850680dc9c7ab582e8c964a4a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 10:25:41 -0700 Subject: [PATCH 079/197] synth_*: no need to explicitly read +/abc9_model.v --- techlibs/ecp5/synth_ecp5.cc | 2 +- techlibs/ice40/synth_ice40.cc | 2 +- techlibs/intel_alm/synth_intel_alm.cc | 1 - techlibs/xilinx/synth_xilinx.cc | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 8039531ae..c1545cbb5 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -338,7 +338,7 @@ struct SynthEcp5Pass : public ScriptPass run("techmap " + techmap_args); if (abc9) { - run("read_verilog -icells -lib -specify +/abc9_model.v +/ecp5/abc9_model.v"); + run("read_verilog -icells -lib -specify +/ecp5/abc9_model.v"); std::string abc9_opts; if (nowidelut) abc9_opts += " -maxlut 4"; diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 376cb7dbd..f780832e6 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -387,7 +387,7 @@ struct SynthIce40Pass : public ScriptPass } if (!noabc) { if (abc9) { - run("read_verilog " + define + " -icells -lib -specify +/abc9_model.v +/ice40/abc9_model.v"); + run("read_verilog " + define + " -icells -lib -specify +/ice40/abc9_model.v"); std::string abc9_opts; std::string k = "synth_ice40.abc9.W"; if (active_design && active_design->scratchpad.count(k)) diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index bf9e746b8..0f844961e 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -209,7 +209,6 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("map_luts")) { - run("read_verilog -icells -specify -lib +/abc9_model.v"); run("abc9 -maxlut 6 -W 200"); run("techmap -map +/intel_alm/common/alm_map.v"); run("opt -fast"); diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index c45d389ef..d6ca9e57e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -616,7 +616,7 @@ struct SynthXilinxPass : public ScriptPass log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, " "will use timing for 'xc7' instead.\n", family.c_str()); run("techmap -map +/xilinx/abc9_map.v -max_iter 1"); - run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v"); + run("read_verilog -icells -lib -specify +/xilinx/abc9_model.v"); std::string abc9_opts; std::string k = "synth_xilinx.abc9.W"; if (active_design && active_design->scratchpad.count(k)) From c50601e35e9444e9fb77fd89622b3263d85d1fd0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 10:40:33 -0700 Subject: [PATCH 080/197] abc9: restore selected_modules() --- passes/techmap/abc9_ops.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 976b6462e..4843200d8 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -128,7 +128,7 @@ void prep_dff_hier(RTLIL::Design *design) Design *unmap_design = new Design; - for (auto module : design->modules()) + for (auto module : design->selected_modules()) for (auto cell : module->cells()) { auto inst_module = design->module(cell->type); if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { From 5ad3a8528896a2e2539f2de98194eb0a6cce36c9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 10:49:33 -0700 Subject: [PATCH 081/197] abc9: test to use box file instead of auto --- tests/simple_abc9/abc9.box | 3 +++ tests/simple_abc9/abc9.v | 2 +- tests/simple_abc9/run-test.sh | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 tests/simple_abc9/abc9.box diff --git a/tests/simple_abc9/abc9.box b/tests/simple_abc9/abc9.box new file mode 100644 index 000000000..b3c88437c --- /dev/null +++ b/tests/simple_abc9/abc9.box @@ -0,0 +1,3 @@ +MUXF8 1 0 3 1 +#I0 I1 S +0 0 0 # O diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v index 688b47586..5e969c614 100644 --- a/tests/simple_abc9/abc9.v +++ b/tests/simple_abc9/abc9.v @@ -213,7 +213,7 @@ module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encode input rst; endmodule -(* abc9_box, blackbox *) +(* abc9_box_id=1, blackbox *) module MUXF8(input I0, I1, S, output O); specify (I0 => O) = 0; diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh index 424d8f417..650e42fca 100755 --- a/tests/simple_abc9/run-test.sh +++ b/tests/simple_abc9/run-test.sh @@ -25,7 +25,7 @@ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p synth -run coarse; \ opt -full; \ techmap; \ - abc9 -lut 4; \ + abc9 -lut 4 -box ../abc9.box; \ clean; \ check -assert; \ select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%; \ From 722540dbf942d2b8acbaf7372001c7d982eb2845 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 12:08:59 -0700 Subject: [PATCH 082/197] abc9: not enough to techmap_fail on (* init=1 *), hide them using $__ --- backends/aiger/xaiger.cc | 1 + techlibs/common/abc9_map.v | 24 ++++++++++++++---------- techlibs/common/abc9_unmap.v | 12 ++++++++++++ tests/various/abc9.ys | 23 +++++++++++++++++++++-- 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index ddda1bd5a..abb9ae30f 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -644,6 +644,7 @@ struct XAigerWriter SigBit Q = sigmap(cell->getPort(ID::Q)); State init = init_map.at(Q, State::Sx); + log_debug("Cell '%s' (type %s) has (* init *) value '%s'.\n", log_id(cell), log_id(cell->type), log_signal(init)); if (init == State::S1) write_s_buffer(1); else if (init == State::S0) diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v index b04a5b64f..5f1822485 100644 --- a/techlibs/common/abc9_map.v +++ b/techlibs/common/abc9_map.v @@ -2,20 +2,24 @@ module $_DFF_x_(input C, D, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter _TECHMAP_CELLTYPE_ = ""; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - wire _TECHMAP_FAIL_ = 1; - else if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin - wire D_; - $__DFF_N__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); - $_DFF_N_ ff (.C(C), .D(D_), .Q(Q)); + wire D_; + generate if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin + if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin + $__DFF_N__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $_DFF_N_ ff (.C(C), .D(D_), .Q(Q)); + end + else + $__DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));// hide from abc9 using $__ prefix end else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin - wire D_; - $__DFF_P__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); - $_DFF_P_ ff (.C(C), .D(D_), .Q(Q)); + if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin + $__DFF_P__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $_DFF_P_ ff (.C(C), .D(D_), .Q(Q)); + end + else + $__DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); // hide from abc9 using $__ prefix end else if (_TECHMAP_CELLTYPE_ != "") $error("Unrecognised _TECHMAP_CELLTYPE_"); endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v index 0fd07207d..4dfac0cbb 100644 --- a/techlibs/common/abc9_unmap.v +++ b/techlibs/common/abc9_unmap.v @@ -10,3 +10,15 @@ module $__DFF_x__$abc9_flop (input C, D, Q, (* init = INIT *) output n1); $error("Unrecognised _TECHMAP_CELLTYPE_"); endgenerate endmodule + +(* techmap_celltype = "$__DFF_N_ $__DFF_P_" *) +module $__DFF_N__$abc9_flop(input C, D, output Q); + parameter _TECHMAP_CELLTYPE_ = ""; + generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N_") + $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else if (_TECHMAP_CELLTYPE_ == "$__DFF_P_") + $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else if (_TECHMAP_CELLTYPE_ != "") + $error("Unrecognised _TECHMAP_CELLTYPE_"); + endgenerate +endmodule diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys index 7a3a503e4..9586091c4 100644 --- a/tests/various/abc9.ys +++ b/tests/various/abc9.ys @@ -50,7 +50,7 @@ $_DFF_P_ ff(.C(clk), .D(d), .Q(w)); assign q = w; endmodule EOT -equiv_opt abc9 -lut 4 -dff +equiv_opt -assert abc9 -lut 4 -dff design -load postopt cd abc9_test036 select -assert-count 1 t:$_DFF_P_ @@ -69,8 +69,27 @@ specify endspecify endmodule -module top(input [1:0] i, output o); +module abc9_test037(input [1:0] i, output o); LUT2 #(.mask(4'b0)) lut (.i(i), .o(o)); endmodule EOT abc9 + + +design -reset +read_verilog -icells < Date: Thu, 16 Apr 2020 14:01:54 -0700 Subject: [PATCH 083/197] aiger: -xaiger to return $_FF_ flops --- frontends/aiger/aigerparse.cc | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 16e94c394..d25587e48 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -787,21 +787,8 @@ void AigerReader::post_process() log_assert(q->port_input); q->port_input = false; - Cell* ff; - int clock_index = mergeability[i]; - if (clock_index & 1) { - ff = module->addCell(NEW_ID, ID($_DFF_N_)); - clock_index--; - } - else - ff = module->addCell(NEW_ID, ID($_DFF_P_)); - auto r = mergeability_to_clock.insert(clock_index); - if (r.second) - r.first->second = module->addWire(NEW_ID); - ff->setPort(ID::C, r.first->second); - ff->setPort(ID::D, d); - ff->setPort(ID::Q, q); - log_assert(GetSize(q) == 1); + Cell* ff = module->addFfGate(NEW_ID, d, q); + ff->attributes[ID::abc9_mergeability] = mergeability[i]; q->attributes[ID::init] = initial_state[i]; } From e357b40e7ae8a907ef38b2d32c920aada3f1ed5a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 14:02:42 -0700 Subject: [PATCH 084/197] xaiger: no longer use nonstandard even/odd to designate +ve/-ve polarity --- backends/aiger/xaiger.cc | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index abb9ae30f..e1962119c 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -620,27 +620,16 @@ struct XAigerWriter auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1); write_s_buffer(ff_bits.size()); - dict clk_to_mergeability; - for (const auto &i : ff_bits) { - const Cell *cell = i.second; - log_assert(cell->type.in(ID($_DFF_N_), ID($_DFF_P_))); - - SigBit clock = sigmap(cell->getPort(ID::C)); - clk_to_mergeability.insert(std::make_pair(clock, clk_to_mergeability.size()*2+1)); - } - + dict clk_to_mergeability; for (const auto &i : ff_bits) { const SigBit &d = i.first; const Cell *cell = i.second; - SigBit clock = sigmap(cell->getPort(ID::C)); - int mergeability = clk_to_mergeability.at(clock); + SigSpec clk_and_pol{sigmap(cell->getPort(ID::C)), cell->type[6] == 'P' ? State::S1 : State::S0}; + auto r = clk_to_mergeability.insert(std::make_pair(clk_and_pol, clk_to_mergeability.size()+1)); + int mergeability = r.first->second; log_assert(mergeability > 0); - if (cell->type == ID($_DFF_N_)) - write_r_buffer(mergeability); - else if (cell->type == ID($_DFF_P_)) - write_r_buffer(mergeability+1); - else log_abort(); + write_r_buffer(mergeability); SigBit Q = sigmap(cell->getPort(ID::Q)); State init = init_map.at(Q, State::Sx); From bb840cca9cd62ad59b2054049e979263325ba664 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 16 Apr 2020 14:03:54 -0700 Subject: [PATCH 085/197] abc9_ops: -reintegrate to handle $_FF_; cleanup --- passes/techmap/abc9_ops.cc | 40 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4843200d8..8fc56b773 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -166,6 +166,7 @@ void prep_dff_map(RTLIL::Design *design) for (auto module : design->modules()) { vector specify_cells; SigBit D, Q; + Cell *c; Cell* dff_cell = nullptr; // If module has a public name (i.e. not $paramod) and it doesn't exist @@ -217,28 +218,23 @@ void prep_dff_map(RTLIL::Design *design) if (!dff_cell) log_error("Module '%s' with (* abc9_flop *) does not any contain $_DFF_[NP]_ cells.\n", log_id(module)); - D = dff_cell->getPort(ID::D); - - { - // Add dummy buffers for all module inputs/outputs - // to ensure that these ports exists in the flop box - // created by later submod pass - for (auto port_name : module->ports) { - auto port = module->wire(port_name); - log_assert(GetSize(port) == 1); - auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); - // Need to set (* keep *) otherwise opt_clean - // inside submod will blow it away - c->set_bool_attribute(ID::keep); - } - // Add an additional buffer that drives $_DFF_[NP]_.D - // so that the flop box will have an output - auto w = module->addWire(NEW_ID); - auto c = module->addBufGate(NEW_ID, D, w); + // Add dummy buffers for all module inputs/outputs + // to ensure that these ports exists in the flop box + // created by later submod pass + for (auto port_name : module->ports) { + auto port = module->wire(port_name); + log_assert(GetSize(port) == 1); + auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); + // Need to set (* keep *) otherwise opt_clean + // inside submod will blow it away c->set_bool_attribute(ID::keep); - dff_cell->setPort(ID::D, w); - D = w; } + // Add an additional buffer that drives $_DFF_[NP]_.D + // so that the flop box will have an output + D = module->addWire(NEW_ID); + c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); + c->set_bool_attribute(ID::keep); + dff_cell->setPort(ID::D, D); // Rewrite $specify cells that end with $_DFF_[NP]_.Q // to $_DFF_[NP]_.D since it will be moved into @@ -895,9 +891,9 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { - // Short out $_DFF_[NP]_ cells since the flop box already has + // Short out $_FF_ cells since the flop box already has // all the information we need to reconstruct cell - if (dff_mode && mapped_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + if (dff_mode && mapped_cell->type == ID($_FF_)) { SigBit D = mapped_cell->getPort(ID::D); SigBit Q = mapped_cell->getPort(ID::Q); if (D.wire) From 7cd3f4a79bde6dbe2cd7f90d0a4996aebe70fd10 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 12:22:39 -0700 Subject: [PATCH 086/197] abc9_ops: add -prep_bypass for auto bypass boxes; refactor Eliminate need for abc9_{,un}map.v in xilinx -prep_dff_{hier,unmap} -> -prep_hier --- passes/techmap/abc9.cc | 64 +-- passes/techmap/abc9_ops.cc | 712 +++++++++++++++++++++++--------- techlibs/ecp5/synth_ecp5.cc | 2 +- techlibs/ice40/synth_ice40.cc | 2 +- techlibs/xilinx/Makefile.inc | 2 - techlibs/xilinx/abc9_map.v | 432 ------------------- techlibs/xilinx/abc9_model.v | 171 -------- techlibs/xilinx/abc9_unmap.v | 57 --- techlibs/xilinx/cells_sim.v | 222 +++++----- techlibs/xilinx/synth_xilinx.cc | 4 +- tests/arch/xilinx/abc9_dff.ys | 34 +- 11 files changed, 714 insertions(+), 988 deletions(-) delete mode 100644 techlibs/xilinx/abc9_map.v delete mode 100644 techlibs/xilinx/abc9_unmap.v diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 911254aa6..ff9b46b5f 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -275,22 +275,31 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { if (check_label("check")) { - run("abc9_ops -check"); + if (help_mode) + run("abc9_ops -check [-dff]", "(option if -dff)"); + else + run(stringf("abc9_ops -check %s", dff_mode ? "-dff" : "")); } - if (check_label("dff", "(only if -dff)")) { - if (dff_mode || help_mode) { - run("abc9_ops -prep_dff_hier"); // derive all used (* abc9_flop *) modules, - // create stubs in $abc9_unmap design - run("design -stash $abc9"); - run("design -copy-from $abc9 @$abc9_flops"); // copy derived modules in - run("proc"); - run("wbflip"); - run("techmap"); - run("opt"); + if (check_label("map")) { + if (help_mode) + run("abc9_ops -prep_hier -prep_bypass [-prep_dff -dff]", "(option if -dff)"); + else + run(stringf("abc9_ops -prep_hier -prep_bypass %s", dff_mode ? "-prep_dff -dff" : "")); + if (dff_mode) { + run("design -copy-to $abc9_map @$abc9_flops", "(only if -dff)"); + run("select -unset $abc9_flops", " (only if -dff)"); + } + run("design -stash $abc9"); + run("design -load $abc9_map"); + run("proc"); + run("wbflip"); + run("techmap"); + run("opt"); + if (dff_mode) { if (!help_mode) active_design->scratchpad_unset("abc9_ops.prep_dff_map.did_something"); - run("abc9_ops -prep_dff_map"); // rewrite specify + run("abc9_ops -prep_dff_map", "(only if -dff)"); // rewrite specify bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_map.did_something"); if (did_something) { // select all $_DFF_[NP]_ @@ -299,6 +308,8 @@ struct Abc9Pass : public ScriptPass // lastly remove $_DFF_[NP]_ cells run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); run("submod"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); + run("abc9_ops -prep_dff_unmap"); run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out run("delete *_$abc9_flop"); if (help_mode) { @@ -313,21 +324,13 @@ struct Abc9Pass : public ScriptPass run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); } } - run("design -stash $abc9_map"); } - run("design -load $abc9"); - run("design -delete $abc9"); - run("select -unset $abc9_flops"); - if (did_something) { // techmap user design into submod + $_DFF_[NP]_ - run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); - run("design -delete $abc9_map"); - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); - run("abc9_ops -prep_dff_unmap"); // implement $abc9_unmap design - } - else - run("techmap -wb -max_iter 1 -map +/abc9_map.v"); - } + run("design -stash $abc9_map"); + run("design -load $abc9"); + run("design -delete $abc9"); + run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); + run("design -delete $abc9_map"); } if (check_label("pre")) { @@ -353,9 +356,10 @@ struct Abc9Pass : public ScriptPass run("aigmap"); run("design -stash $abc9_holes"); run("design -load $abc9"); + run("design -delete $abc9"); } - if (check_label("map")) { + if (check_label("exe")) { run("aigmap"); if (help_mode) { run("foreach module in selection"); @@ -430,12 +434,10 @@ struct Abc9Pass : public ScriptPass } } - if (check_label("post")) { - if (dff_mode || help_mode) { - run("techmap -wb -map %$abc9_unmap", "(only if -dff)"); // techmap user design from submod back to original cell + if (check_label("unmap")) { + run("techmap -wb -map %$abc9_unmap -map +/abc9_unmap.v"); // techmap user design from submod back to original cell // ($_DFF_[NP]_ already shorted by -reintegrate) - run("design -delete $abc9_unmap", " (only if -dff)"); - } + run("design -delete $abc9_unmap"); if (saved_designs.count("$abc9_holes") || help_mode) run("design -delete $abc9_holes"); } diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 8fc56b773..25ac5c340 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -34,13 +34,10 @@ inline std::string remap_name(RTLIL::IdString abc9_name) return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); } -void check(RTLIL::Design *design) +void check(RTLIL::Design *design, bool dff_mode) { dict box_lookup; for (auto m : design->modules()) { - if (m->name.begins_with("$paramod")) - continue; - auto flop = m->get_bool_attribute(ID::abc9_flop); auto it = m->attributes.find(ID::abc9_box_id); if (!flop) { @@ -88,6 +85,469 @@ void check(RTLIL::Design *design) log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); } } + + if (dff_mode) { + pool unsupported{ + ID($adff), ID($dlatch), ID($dlatchsr), ID($sr), + ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($_DLATCH_N_), ID($_DLATCH_P_), + ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), + ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), + ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_) + }; + pool processed; + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->attributes.count(ID::abc9_flop)) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + if (!processed.insert(derived_type).second) + continue; + if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type)); + + auto derived_module = design->module(derived_type); + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); + + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + bool found = false; + for (auto derived_cell : derived_module->cells()) + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + if (found) + log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module)); + found = true; + + SigBit Q = derived_cell->getPort(ID::Q); + log_assert(GetSize(Q.wire) == 1); + + if (!Q.wire->port_output) + log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type)); + + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + } + else if (unsupported.count(derived_cell->type)) { + log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type)); + } + } + } + } +} + +void prep_hier(RTLIL::Design *design, bool dff_mode) +{ + auto r = saved_designs.emplace("$abc9_unmap", nullptr); + if (r.second) + r.first->second = new Design; + Design *unmap_design = r.first->second; + + pool seq_types{ + ID($dff), ID($dffsr), ID($adff), + ID($dlatch), ID($dlatchsr), ID($sr), + ID($mem), + ID($_DFF_N_), ID($_DFF_P_), + ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), + ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), + ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($_DLATCH_N_), ID($_DLATCH_P_), + ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), + ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), + ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_) + }; + + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) + continue; + + if (inst_module->attributes.count(ID::abc9_flop) && !dff_mode) + continue; + if (!inst_module->attributes.count(ID::abc9_box) && !inst_module->attributes.count(ID::abc9_flop)) + continue; + + if (!unmap_design->module(derived_type)) { + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); + + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + for (auto derived_cell : derived_module->cells()) + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + SigBit Q = derived_cell->getPort(ID::Q); + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + + // Block sequential synthesis on cells with (* init *) != 1'b0 + // because ABC9 doesn't support them + if (init != State::S0) { + log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type)); + // TODO: still necessary? + // Do not use set_bool_attribute() as it will unset the value + // and (attributes.count(ID::abc9_flop) will fail) + derived_module->attributes[ID::abc9_flop] = false; + goto skip_cell; + } + break; + } + } + else if (derived_module->get_bool_attribute(ID::abc9_box)) { + bool found = false; + for (auto derived_cell : derived_module->cells()) + if (seq_types.count(derived_cell->type)) { + found = true; + break; + } + + if (!found) { + derived_module->set_bool_attribute(ID::abc9_box, false); + log_assert(!derived_module->attributes.count(ID::abc9_box)); + goto skip_cell; + } + + // TODO: still necessary? + // Do not use set_bool_attribute() as it will unset the value + // and (attributes.count(ID::abc9_box) will fail) + derived_module->attributes[ID::abc9_box] = false; + } + + if (derived_type != cell->type) { + auto unmap_module = unmap_design->addModule(derived_type); + for (auto port : derived_module->ports) { + auto w = unmap_module->addWire(port, derived_module->wire(port)); + // Do not propagate (* init *) values inside the box + if (w->port_output) + w->attributes.erase(ID::init); + } + unmap_module->ports = derived_module->ports; + unmap_module->check(); + + auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + for (const auto &conn : cell->connections()) { + auto w = unmap_module->wire(conn.first); + log_assert(w); + replace_cell->setPort(conn.first, w); + } + replace_cell->parameters = cell->parameters; + } + } + + cell->type = derived_type; + cell->parameters.clear(); + +skip_cell: ; + } +} + +void prep_bypass(RTLIL::Design *design) +{ + auto r = saved_designs.emplace("$abc9_map", nullptr); + if (r.second) + r.first->second = new Design; + Design *map_design = r.first->second; + + r = saved_designs.emplace("$abc9_unmap", nullptr); + if (r.second) + r.first->second = new Design; + Design *unmap_design = r.first->second; + + pool processed; + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + if (!processed.insert(cell->type).second) + continue; + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + inst_module = design->module(derived_type); + log_assert(inst_module); + if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + continue; + // Skip if (* abc9_box *) exists or is true + auto it = inst_module->attributes.find(ID::abc9_box); + if (it == inst_module->attributes.end() || it->second.as_bool()) + continue; + + + // The idea is to create two techmap designs, one which maps: + // + // box u0 (.i(i), .o(o)); + // + // to + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o)); + // + // the purpose being to move the (* abc9_box *) status from 'box' + // (which is stateful) to 'box_$abc9_byp' (which becomes a new + // combinatorial black- (not white-) box with all state elements + // removed). This has the effect of preserving any combinatorial + // paths through an otherwise sequential primitive -- e.g. LUTRAMs. + // + // The unmap design performs the reverse: + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // box_$abc9_byp (.i(i), .$abc9_byp$o($abc9_byp$o), .o(o)); + // + // to: + // + // wire $abc9$o; + // box u0 (.i(i), .o($abc9_byp$o)); + // assign o = $abc9_byp$o; + + + // Copy derived_module into map_design, with the same interface + // and duplicate $abc9$* wires for its output ports + auto map_module = map_design->addModule(cell->type); + for (auto port_name : inst_module->ports) { + auto w = map_module->addWire(port_name, inst_module->wire(port_name)); + if (w->port_output) + w->attributes.erase(ID::init); + } + map_module->ports = inst_module->ports; + map_module->check(); + map_module->set_bool_attribute(ID::whitebox); + + // Create the bypass module in the user design, which has the same + // interface as the derived module but with additional input + // ports driven by the outputs of the replaced cell + auto bypass_module = design->addModule(cell->type.str() + "_$abc9_byp"); + for (auto port_name : inst_module->ports) { + auto port = inst_module->wire(port_name); + if (!port->port_output) + continue; + auto dst = bypass_module->addWire(port_name, port); + auto src = bypass_module->addWire("$abc9byp$" + port_name.str(), GetSize(port)); + src->port_input = true; + // For these new input ports driven by the replaced + // cell, then create a new simple-path specify entry: + // (input => output) = 0 + auto specify = bypass_module->addCell(NEW_ID, ID($specify2)); + specify->setPort(ID::EN, State::S1); + specify->setPort(ID::SRC, src); + specify->setPort(ID::DST, dst); + specify->setParam(ID::FULL, 0); + specify->setParam(ID::SRC_WIDTH, GetSize(src)); + specify->setParam(ID::DST_WIDTH, GetSize(dst)); + specify->setParam(ID::SRC_DST_PEN, 0); + specify->setParam(ID::SRC_DST_POL, 0); + specify->setParam(ID::T_RISE_MIN, 0); + specify->setParam(ID::T_RISE_TYP, 0); + specify->setParam(ID::T_RISE_MAX, 0); + specify->setParam(ID::T_FALL_MIN, 0); + specify->setParam(ID::T_FALL_TYP, 0); + specify->setParam(ID::T_FALL_MAX, 0); + } + bypass_module->set_bool_attribute(ID::blackbox); + bypass_module->set_bool_attribute(ID::abc9_box); + + // Copy any 'simple' (combinatorial) specify paths from + // the derived module into the bypass module, if EN + // is not false and SRC/DST are driven only by + // module ports; create new input port if one doesn't + // already exist + for (auto cell : inst_module->cells()) { + if (cell->type != ID($specify2)) + continue; + auto EN = cell->getPort(ID::EN).as_bit(); + SigBit newEN; + if (!EN.wire && EN != State::S1) + continue; + auto SRC = cell->getPort(ID::SRC); + for (const auto &c : SRC.chunks()) + if (c.wire && !c.wire->port_input) { + SRC = SigSpec(); + break; + } + if (SRC.empty()) + continue; + auto DST = cell->getPort(ID::DST); + for (const auto &c : DST.chunks()) + if (c.wire && !c.wire->port_output) { + DST = SigSpec(); + break; + } + if (DST.empty()) + continue; + auto rw = [bypass_module](RTLIL::SigSpec &sig) + { + SigSpec new_sig; + for (auto c : sig.chunks()) { + if (c.wire) { + auto port = bypass_module->wire(c.wire->name); + if (!port) + port = bypass_module->addWire(c.wire->name, c.wire); + c.wire = port; + } + new_sig.append(std::move(c)); + } + sig = std::move(new_sig); + }; + auto specify = bypass_module->addCell(NEW_ID, cell); + specify->rewrite_sigspecs(rw); + } + bypass_module->fixup_ports(); + + // Create an _TECHMAP_REPLACE_ cell identical to the original cell, + // and a bypass cell that has the same inputs/outputs as the + // original cell, but with additional inputs taken from the + // replaced cell + auto replace_cell = map_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); + auto bypass_cell = map_module->addCell(NEW_ID, cell->type.str() + "_$abc9_byp"); + for (const auto &conn : cell->connections()) { + auto port = map_module->wire(conn.first); + if (cell->input(conn.first)) { + replace_cell->setPort(conn.first, port); + if (bypass_module->wire(conn.first)) + bypass_cell->setPort(conn.first, port); + } + if (cell->output(conn.first)) { + bypass_cell->setPort(conn.first, port); + auto n = "$abc9byp$" + conn.first.str(); + auto w = map_module->addWire(n, GetSize(conn.second)); + replace_cell->setPort(conn.first, w); + bypass_cell->setPort(n, w); + } + } + + + // Lastly, create a new module in the unmap_design that shorts + // out the bypass cell back to leave the replace cell behind + // driving the outputs + auto unmap_module = unmap_design->addModule(cell->type.str() + "_$abc9_byp"); + for (auto port_name : inst_module->ports) { + auto w = unmap_module->addWire(port_name, inst_module->wire(port_name)); + if (w->port_output) { + w->attributes.erase(ID::init); + auto w2 = unmap_module->addWire("$abc9byp$" + port_name.str(), GetSize(w)); + w2->port_input = true; + unmap_module->connect(w, w2); + } + } + unmap_module->fixup_ports(); + } +} + +void prep_dff(RTLIL::Design *design) +{ + auto r = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); + auto &modules_sel = r.first->second; + + for (auto module : design->selected_modules()) + for (auto cell : module->cells()) { + if (modules_sel.selected_whole_module(cell->type)) + continue; + auto inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->attributes.count(ID::abc9_flop)) + continue; + auto derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + log_assert(derived_module); + if (!derived_module->get_bool_attribute(ID::abc9_flop)) + continue; + log_assert(!derived_module->get_blackbox_attribute(true /* ignore_wb */)); + modules_sel.select(derived_module); + } +} + +void prep_dff_map(RTLIL::Design *design) +{ + for (auto module : design->modules()) { + vector specify_cells; + SigBit Q; + Cell* dff_cell = nullptr; + + if (!module->get_bool_attribute(ID::abc9_flop)) + continue; + + for (auto cell : module->cells()) + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + log_assert(!dff_cell); + dff_cell = cell; + Q = cell->getPort(ID::Q); + log_assert(GetSize(Q.wire) == 1); + } + else if (cell->type.in(ID($specify3), ID($specrule))) + specify_cells.emplace_back(cell); + log_assert(dff_cell); + + // Add dummy buffers for all module inputs/outputs + // to ensure that these ports exists in the flop box + // created by later submod pass + for (auto port_name : module->ports) { + auto port = module->wire(port_name); + log_assert(GetSize(port) == 1); + auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); + // Need to set (* keep *) otherwise opt_clean + // inside submod will blow it away + c->set_bool_attribute(ID::keep); + } + // Add an additional buffer that drives $_DFF_[NP]_.D + // so that the flop box will have an output + SigBit D = module->addWire(NEW_ID); + Cell *c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); + c->set_bool_attribute(ID::keep); + dff_cell->setPort(ID::D, D); + + // Rewrite $specify cells that end with $_DFF_[NP]_.Q + // to $_DFF_[NP]_.D since it will be moved into + // the submodule + for (auto cell : specify_cells) { + auto DST = cell->getPort(ID::DST); + DST.replace(Q, D); + cell->setPort(ID::DST, DST); + } + + design->scratchpad_set_bool("abc9_ops.prep_dff_map.did_something", true); + } +} + +void prep_dff_unmap(RTLIL::Design *design) +{ + Design *unmap_design = saved_designs.at("$abc9_unmap"); + + for (auto module : design->modules()) { + if (!module->get_bool_attribute(ID::abc9_flop) || module->get_bool_attribute(ID::abc9_box)) + continue; + + auto unmap_module = unmap_design->addModule(module->name.str() + "_$abc9_flop"); + auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name); + for (auto port_name : module->ports) { + auto w = unmap_module->addWire(port_name, module->wire(port_name)); + // Do not propagate (* init *) values inside the box + if (w->port_output) + w->attributes.erase(ID::init); + replace_cell->setPort(port_name, w); + } + + // Add new ports appearing in "_$abc9_flop" + auto box_module = design->module(unmap_module->name); + log_assert(box_module); + for (auto port_name : box_module->ports) { + auto port = box_module->wire(port_name); + auto unmap_port = unmap_module->wire(port_name); + if (!unmap_port) + unmap_port = unmap_module->addWire(port_name, port); + else + unmap_port->port_id = port->port_id; + } + unmap_module->ports = box_module->ports; + unmap_module->check(); + } } void mark_scc(RTLIL::Module *module) @@ -119,168 +579,6 @@ void mark_scc(RTLIL::Module *module) } } - -void prep_dff_hier(RTLIL::Design *design) -{ - auto r YS_ATTRIBUTE(unused) = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false))); - log_assert(r.second); - auto &modules_sel = design->selection_vars.at(ID($abc9_flops)); - - Design *unmap_design = new Design; - - for (auto module : design->selected_modules()) - for (auto cell : module->cells()) { - auto inst_module = design->module(cell->type); - if (inst_module && inst_module->attributes.count(ID::abc9_flop)) { - if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) - log_error("Module '%s' with (* abc9_flop *) is not a whitebox.\n", log_id(inst_module)); - // Derive modules for all instantiations of (* abc9_flop *) - auto derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - if (!derived_module->get_bool_attribute(ID::abc9_flop)) - continue; - // And create the stub in the $abc9_unmap design - if (!modules_sel.selected_whole_module(derived_type)) { - if (derived_type != cell->type) - modules_sel.select(inst_module); - - modules_sel.select(derived_module); - - auto unmap_module = unmap_design->addModule(derived_type.str() + "_$abc9_flop"); - auto unmap_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, cell->type); - for (const auto &conn : cell->connections()) - unmap_cell->setPort(conn.first, SigSpec()); - unmap_cell->parameters = cell->parameters; - } - } - } - - auto r2 YS_ATTRIBUTE(unused) = saved_designs.emplace("$abc9_unmap", unmap_design); - log_assert(r2.second); -} - -void prep_dff_map(RTLIL::Design *design) -{ - Design *unmap_design = saved_designs.at("$abc9_unmap"); - - for (auto module : design->modules()) { - vector specify_cells; - SigBit D, Q; - Cell *c; - Cell* dff_cell = nullptr; - - // If module has a public name (i.e. not $paramod) and it doesn't exist - // in the $abc9_unmap then it means only derived modules were - // instantiated, so make this a blackbox - if (module->name[0] == '\\' && !unmap_design->module(module->name.str() + "_$abc9_flop")) { - module->makeblackbox(); - module->set_bool_attribute(ID::blackbox, false); - module->set_bool_attribute(ID::whitebox, true); - continue; - } - - for (auto cell : module->cells()) - if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - if (dff_cell) - log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(module)); - dff_cell = cell; - - // Block sequential synthesis on cells with (* init *) != 1'b0 - // because ABC9 doesn't support them - Q = cell->getPort(ID::Q); - log_assert(GetSize(Q.wire) == 1); - - if (!Q.wire->port_output) - log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(module), log_id(cell->type)); - - Const init = Q.wire->attributes.at(ID::init, State::Sx); - log_assert(GetSize(init) == 1); - if (init != State::S0) { - log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(module), log_id(cell->type)); - - module->makeblackbox(); - module->set_bool_attribute(ID::blackbox, false); - - auto wire = module->addWire(ID(_TECHMAP_FAIL_)); - wire->set_bool_attribute(ID::keep); - module->connect(wire, State::S1); - - goto continue_outer_loop; - } - } - else if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), - ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), - ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1), - ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1))) - log_error("Module '%s' with (* abc9_flop *) contains an asynchronous $_DFFE?_[NP][NP][01]_? cell, which is not supported for sequential synthesis.\n", log_id(module)); - else if (cell->type.in(ID($specify2), ID($specify3), ID($specrule))) - specify_cells.emplace_back(cell); - if (!dff_cell) - log_error("Module '%s' with (* abc9_flop *) does not any contain $_DFF_[NP]_ cells.\n", log_id(module)); - - // Add dummy buffers for all module inputs/outputs - // to ensure that these ports exists in the flop box - // created by later submod pass - for (auto port_name : module->ports) { - auto port = module->wire(port_name); - log_assert(GetSize(port) == 1); - auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); - // Need to set (* keep *) otherwise opt_clean - // inside submod will blow it away - c->set_bool_attribute(ID::keep); - } - // Add an additional buffer that drives $_DFF_[NP]_.D - // so that the flop box will have an output - D = module->addWire(NEW_ID); - c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); - c->set_bool_attribute(ID::keep); - dff_cell->setPort(ID::D, D); - - // Rewrite $specify cells that end with $_DFF_[NP]_.Q - // to $_DFF_[NP]_.D since it will be moved into - // the submodule - for (auto cell : specify_cells) { - auto DST = cell->getPort(ID::DST); - DST.replace(Q, D); - cell->setPort(ID::DST, DST); - } - - design->scratchpad_set_bool("abc9_ops.prep_dff_map.did_something", true); - -continue_outer_loop: ; - } -} - -void prep_dff_unmap(RTLIL::Design *design) -{ - Design *unmap_design = saved_designs.at("$abc9_unmap"); - - // Create the reverse techmap rule -- (* abc9_box *) back to flop - for (auto module : unmap_design->modules()) { - auto flop_module = design->module(module->name.str()); - if (!flop_module) - continue; // May not exist if init = 1'b1 - - auto unmap_module = unmap_design->module(flop_module->name); - log_assert(unmap_module); - for (auto port : flop_module->ports) { - auto w = unmap_module->addWire(port, flop_module->wire(port)); - // Do not propagate (* init *) values inside the box - w->attributes.erase(ID::init); - } - unmap_module->ports = flop_module->ports; - unmap_module->check(); - - auto unmap_cell = unmap_module->cell(ID::_TECHMAP_REPLACE_); - log_assert(unmap_cell); - for (const auto &conn : unmap_cell->connections()) { - auto rhs = unmap_module->wire(conn.first); - log_assert(rhs); - unmap_cell->setPort(conn.first, rhs); - } - } -} - void prep_xaiger(RTLIL::Module *module, bool dff) { auto design = module->design; @@ -477,7 +775,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) continue; if (!inst_module->get_blackbox_attribute()) continue; - if (inst_module->attributes.count(ID::abc9_box)) + if (inst_module->get_bool_attribute(ID::abc9_box)) continue; IdString derived_type = inst_module->derive(design, cell->parameters); inst_module = design->module(derived_type); @@ -630,7 +928,12 @@ void prep_box(RTLIL::Design *design) dict> box_ports; for (auto module : design->modules()) { - if (!module->attributes.erase(ID::abc9_box)) + auto it = module->attributes.find(ID::abc9_box); + if (it == module->attributes.end()) + continue; + bool box = it->second.as_bool(); + module->attributes.erase(it); + if (!box) continue; auto r = module->attributes.insert(ID::abc9_box_id); @@ -758,8 +1061,6 @@ void prep_box(RTLIL::Design *design) auto &t = timing.setup_module(module); if (t.comb.empty()) log_error("Module '%s' with (* abc9_box *) has no timing (and thus no connectivity) information.\n", log_id(module)); - if (!t.arrival.empty() || !t.required.empty()) - log_error("Module '%s' with (* abc9_box *) has setup and/or edge-sensitive timing information.\n", log_id(module)); for (const auto &o : outputs) { first = true; @@ -1226,21 +1527,38 @@ struct Abc9OpsPass : public Pass { log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n"); log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); log("\n"); - log(" -prep_dff_hier\n"); - log(" derive all cells with a type instantiating an (* abc9_flop *) module.\n"); - log(" store such modules in named selection '$abc9_flops'. create stubs within\n"); - log(" a new '$abc9_unmap' design to be used by -prep_dff_unmap.\n"); + log(" -prep_hier\n"); + log(" derive all used (* abc9_box *) requiring bypass, or (* abc9_flop *) (if\n"); + log(" -dff option) whitebox modules. with (* abc9_box *) modules, bypassing is\n"); + log(" necessary if sequential elements (e.g. $dff, $mem, etc.) are discovered\n"); + log(" inside, to ensure that any combinatorial paths are correctly captured.\n"); + log(" with (* abc9_flop *) modules, only those containing $dff/$_DFF_[NP]_\n"); + log(" cells with zero initial state -- due to an ABC limitation -- will be\n"); + log(" derived. for such derived modules, add a rule inside the '$abc9_unmap'\n"); + log(" design that can map a cell instantiating a derived module back to the\n"); + log(" original cell with parameters.\n"); + log("\n"); + log(" -prep_bypass\n"); + log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n"); + log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n"); + log(" (named *_$abc9_byp) that has inherited all its $specify2 (simple path)\n"); + log(" cells.\n"); + log("\n"); + log(" -prep_dff\n"); + log(" select all (* abc9_flop *) modules instantiated in the design and store\n"); + log(" in the named selection '$abc9_flops'.\n"); log("\n"); log(" -prep_dff_map\n"); - log(" within (* abc9_flop *) modules, move all $specify{2,3}/$specrule cells\n"); - log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n"); - log(" the DFF's 'D' port. this is to prepare such specify cells to be moved into\n"); - log(" a submodule.\n"); + log(" within (* abc9_flop *) modules, attach dummy buffers to all ports and move\n"); + log(" all $specify3/$specrule cells that share a 'DST' port with the $_DFF_[NP]_.Q\n"); + log(" port from this 'Q' port to the DFF's 'D' port. this is to ensure that all\n"); + log(" module ports will exist in any submodule, and prepare such specify cells to\n"); + log(" be moved within.\n"); log("\n"); log(" -prep_dff_unmap\n"); - log(" fill in previously created '$abc9_unmap' design to contain techmap rules\n"); - log(" for mapping *_$abc9_flop cells back into their original (* abc9_flop *)\n"); - log(" cells (including their original parameters).\n"); + log(" populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop\n"); + log(" cells back into their derived cell types (where the rules created by\n"); + log(" -prep_hier will then map back to the original cell with parameters).\n"); log("\n"); log(" -prep_delays\n"); log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); @@ -1288,7 +1606,9 @@ struct Abc9OpsPass : public Pass { bool check_mode = false; bool prep_delays_mode = false; bool mark_scc_mode = false; - bool prep_dff_hier_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; + bool prep_hier_mode = false; + bool prep_bypass_mode = false; + bool prep_dff_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; bool prep_xaiger_mode = false; bool prep_lut_mode = false; bool prep_box_mode = false; @@ -1312,8 +1632,18 @@ struct Abc9OpsPass : public Pass { valid = true; continue; } - if (arg == "-prep_dff_hier") { - prep_dff_hier_mode = true; + if (arg == "-prep_hier") { + prep_hier_mode = true; + valid = true; + continue; + } + if (arg == "-prep_bypass") { + prep_bypass_mode = true; + valid = true; + continue; + } + if (arg == "-prep_dff") { + prep_dff_mode = true; valid = true; continue; } @@ -1376,13 +1706,17 @@ struct Abc9OpsPass : public Pass { if (!valid) log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n"); - if (dff_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode) - log_cmd_error("'-dff' option is only relevant for -prep_{delay,xaiger} or -reintegrate.\n"); + if (dff_mode && !check_mode && !prep_hier_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode) + log_cmd_error("'-dff' option is only relevant for -prep_{hier,delay,xaiger} or -reintegrate.\n"); if (check_mode) - check(design); - if (prep_dff_hier_mode) - prep_dff_hier(design); + check(design, dff_mode); + if (prep_hier_mode) + prep_hier(design, dff_mode); + if (prep_bypass_mode) + prep_bypass(design); + if (prep_dff_mode) + prep_dff(design); if (prep_dff_map_mode) prep_dff_map(design); if (prep_dff_unmap_mode) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index c1545cbb5..3e475baab 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -316,7 +316,7 @@ struct SynthEcp5Pass : public ScriptPass if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); if ((abc9 && dff) || help_mode) - run("zinit -all", "(-abc9 and -dff only)"); + run("zinit -all t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index f780832e6..f2270dbca 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -362,7 +362,7 @@ struct SynthIce40Pass : public ScriptPass run("simplemap t:$dff"); } if ((abc9 && dff) || help_mode) - run("zinit -all", "(-abc9 and -dff only)"); + run("zinit -all t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); run("techmap -map +/ice40/ff_map.v"); run("opt_expr -mux_undef"); run("simplemap"); diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 9984290a6..d4d863831 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -54,8 +54,6 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc5v_dsp_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_dsp_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_dsp_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_unmap.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_model.v)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v deleted file mode 100644 index 1d733a650..000000000 --- a/techlibs/xilinx/abc9_map.v +++ /dev/null @@ -1,432 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * 2019 Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// The following techmapping rules are intended to be run (with -max_iter 1) -// before invoking the `abc9` pass in order to transform the design into -// a format that it understands. - -// Attach a (combinatorial) black-box onto the output -// of thes LUTRAM primitives to capture their -// asynchronous read behaviour -module RAM32X1D ( - output DPO, SPO, - (* techmap_autopurge *) input D, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE, - (* techmap_autopurge *) input A0, A1, A2, A3, A4, - (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 -); - parameter INIT = 32'h0; - parameter IS_WCLK_INVERTED = 1'b0; - wire $DPO, $SPO; - RAM32X1D #( - .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DPO($DPO), .SPO($SPO), - .D(D), .WCLK(WCLK), .WE(WE), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), - .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) - ); - $__ABC9_RAM6 spo (.A($SPO), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO)); - $__ABC9_RAM6 dpo (.A($DPO), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); -endmodule - -module RAM64X1D ( - output DPO, SPO, - (* techmap_autopurge *) input D, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE, - (* techmap_autopurge *) input A0, A1, A2, A3, A4, A5, - (* techmap_autopurge *) input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 -); - parameter INIT = 64'h0; - parameter IS_WCLK_INVERTED = 1'b0; - wire $DPO, $SPO; - RAM64X1D #( - .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DPO($DPO), .SPO($SPO), - .D(D), .WCLK(WCLK), .WE(WE), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), - .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) - ); - $__ABC9_RAM6 spo (.A($SPO), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO)); - $__ABC9_RAM6 dpo (.A($DPO), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); -endmodule - -module RAM128X1D ( - output DPO, SPO, - (* techmap_autopurge *) input D, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE, - (* techmap_autopurge *) input [6:0] A, DPRA -); - parameter INIT = 128'h0; - parameter IS_WCLK_INVERTED = 1'b0; - wire $DPO, $SPO; - RAM128X1D #( - .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DPO($DPO), .SPO($SPO), - .D(D), .WCLK(WCLK), .WE(WE), - .A(A), - .DPRA(DPRA) - ); - $__ABC9_RAM7 spo (.A($SPO), .S(A), .Y(SPO)); - $__ABC9_RAM7 dpo (.A($DPO), .S(DPRA), .Y(DPO)); -endmodule - -module RAM32M ( - output [1:0] DOA, - output [1:0] DOB, - output [1:0] DOC, - output [1:0] DOD, - (* techmap_autopurge *) input [4:0] ADDRA, - (* techmap_autopurge *) input [4:0] ADDRB, - (* techmap_autopurge *) input [4:0] ADDRC, - (* techmap_autopurge *) input [4:0] ADDRD, - (* techmap_autopurge *) input [1:0] DIA, - (* techmap_autopurge *) input [1:0] DIB, - (* techmap_autopurge *) input [1:0] DIC, - (* techmap_autopurge *) input [1:0] DID, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE -); - parameter [63:0] INIT_A = 64'h0000000000000000; - parameter [63:0] INIT_B = 64'h0000000000000000; - parameter [63:0] INIT_C = 64'h0000000000000000; - parameter [63:0] INIT_D = 64'h0000000000000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - wire [1:0] $DOA, $DOB, $DOC, $DOD; - RAM32M #( - .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), - .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD), - .WCLK(WCLK), .WE(WE), - .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), - .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) - ); - $__ABC9_RAM6 doa0 (.A($DOA[0]), .S({1'b1, ADDRA}), .Y(DOA[0])); - $__ABC9_RAM6 doa1 (.A($DOA[1]), .S({1'b1, ADDRA}), .Y(DOA[1])); - $__ABC9_RAM6 dob0 (.A($DOB[0]), .S({1'b1, ADDRB}), .Y(DOB[0])); - $__ABC9_RAM6 dob1 (.A($DOB[1]), .S({1'b1, ADDRB}), .Y(DOB[1])); - $__ABC9_RAM6 doc0 (.A($DOC[0]), .S({1'b1, ADDRC}), .Y(DOC[0])); - $__ABC9_RAM6 doc1 (.A($DOC[1]), .S({1'b1, ADDRC}), .Y(DOC[1])); - $__ABC9_RAM6 dod0 (.A($DOD[0]), .S({1'b1, ADDRD}), .Y(DOD[0])); - $__ABC9_RAM6 dod1 (.A($DOD[1]), .S({1'b1, ADDRD}), .Y(DOD[1])); -endmodule - -module RAM64M ( - output DOA, - output DOB, - output DOC, - output DOD, - (* techmap_autopurge *) input [5:0] ADDRA, - (* techmap_autopurge *) input [5:0] ADDRB, - (* techmap_autopurge *) input [5:0] ADDRC, - (* techmap_autopurge *) input [5:0] ADDRD, - (* techmap_autopurge *) input DIA, - (* techmap_autopurge *) input DIB, - (* techmap_autopurge *) input DIC, - (* techmap_autopurge *) input DID, - (* techmap_autopurge *) input WCLK, - (* techmap_autopurge *) input WE -); - parameter [63:0] INIT_A = 64'h0000000000000000; - parameter [63:0] INIT_B = 64'h0000000000000000; - parameter [63:0] INIT_C = 64'h0000000000000000; - parameter [63:0] INIT_D = 64'h0000000000000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - wire $DOA, $DOB, $DOC, $DOD; - RAM64M #( - .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), - .IS_WCLK_INVERTED(IS_WCLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD), - .WCLK(WCLK), .WE(WE), - .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), - .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) - ); - $__ABC9_RAM6 doa (.A($DOA), .S(ADDRA), .Y(DOA)); - $__ABC9_RAM6 dob (.A($DOB), .S(ADDRB), .Y(DOB)); - $__ABC9_RAM6 doc (.A($DOC), .S(ADDRC), .Y(DOC)); - $__ABC9_RAM6 dod (.A($DOD), .S(ADDRD), .Y(DOD)); -endmodule - -module SRL16 ( - output Q, - (* techmap_autopurge *) input A0, A1, A2, A3, CLK, D -); - parameter [15:0] INIT = 16'h0000; - wire $Q; - SRL16 #( - .INIT(INIT), - ) _TECHMAP_REPLACE_ ( - .Q($Q), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRL16E ( - output Q, - (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D -); - parameter [15:0] INIT = 16'h0000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - wire $Q; - SRL16E #( - .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .Q($Q), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRLC16 ( - output Q, Q15, - (* techmap_autopurge *) input A0, A1, A2, A3, CLK, D -); - parameter [15:0] INIT = 16'h0000; - wire $Q; - SRLC16 #( - .INIT(INIT), - ) _TECHMAP_REPLACE_ ( - .Q($Q), .Q(Q15), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRLC16E ( - output Q, Q15, - (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D -); - parameter [15:0] INIT = 16'h0000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - wire $Q; - SRLC16E #( - .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .Q($Q), .Q(Q15), - .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); -endmodule - -module SRLC32E ( - output Q, - output Q31, - (* techmap_autopurge *) input [4:0] A, - (* techmap_autopurge *) input CE, CLK, D -); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - wire $Q; - SRLC32E #( - .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) - ) _TECHMAP_REPLACE_ ( - .Q($Q), .Q31(Q31), - .A(A), .CE(CE), .CLK(CLK), .D(D) - ); - $__ABC9_RAM6 q (.A($Q), .S({1'b1, A}), .Y(Q)); -endmodule - -module DSP48E1 ( - (* techmap_autopurge *) output [29:0] ACOUT, - (* techmap_autopurge *) output [17:0] BCOUT, - (* techmap_autopurge *) output reg CARRYCASCOUT, - (* techmap_autopurge *) output reg [3:0] CARRYOUT, - (* techmap_autopurge *) output reg MULTSIGNOUT, - (* techmap_autopurge *) output OVERFLOW, - (* techmap_autopurge *) output reg signed [47:0] P, - (* techmap_autopurge *) output PATTERNBDETECT, - (* techmap_autopurge *) output PATTERNDETECT, - (* techmap_autopurge *) output [47:0] PCOUT, - (* techmap_autopurge *) output UNDERFLOW, - (* techmap_autopurge *) input signed [29:0] A, - (* techmap_autopurge *) input [29:0] ACIN, - (* techmap_autopurge *) input [3:0] ALUMODE, - (* techmap_autopurge *) input signed [17:0] B, - (* techmap_autopurge *) input [17:0] BCIN, - (* techmap_autopurge *) input [47:0] C, - (* techmap_autopurge *) input CARRYCASCIN, - (* techmap_autopurge *) input CARRYIN, - (* techmap_autopurge *) input [2:0] CARRYINSEL, - (* techmap_autopurge *) input CEA1, - (* techmap_autopurge *) input CEA2, - (* techmap_autopurge *) input CEAD, - (* techmap_autopurge *) input CEALUMODE, - (* techmap_autopurge *) input CEB1, - (* techmap_autopurge *) input CEB2, - (* techmap_autopurge *) input CEC, - (* techmap_autopurge *) input CECARRYIN, - (* techmap_autopurge *) input CECTRL, - (* techmap_autopurge *) input CED, - (* techmap_autopurge *) input CEINMODE, - (* techmap_autopurge *) input CEM, - (* techmap_autopurge *) input CEP, - (* techmap_autopurge *) input CLK, - (* techmap_autopurge *) input [24:0] D, - (* techmap_autopurge *) input [4:0] INMODE, - (* techmap_autopurge *) input MULTSIGNIN, - (* techmap_autopurge *) input [6:0] OPMODE, - (* techmap_autopurge *) input [47:0] PCIN, - (* techmap_autopurge *) input RSTA, - (* techmap_autopurge *) input RSTALLCARRYIN, - (* techmap_autopurge *) input RSTALUMODE, - (* techmap_autopurge *) input RSTB, - (* techmap_autopurge *) input RSTC, - (* techmap_autopurge *) input RSTCTRL, - (* techmap_autopurge *) input RSTD, - (* techmap_autopurge *) input RSTINMODE, - (* techmap_autopurge *) input RSTM, - (* techmap_autopurge *) input RSTP -); - parameter integer ACASCREG = 1; - parameter integer ADREG = 1; - parameter integer ALUMODEREG = 1; - parameter integer AREG = 1; - parameter AUTORESET_PATDET = "NO_RESET"; - parameter A_INPUT = "DIRECT"; - parameter integer BCASCREG = 1; - parameter integer BREG = 1; - parameter B_INPUT = "DIRECT"; - parameter integer CARRYINREG = 1; - parameter integer CARRYINSELREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer INMODEREG = 1; - parameter integer MREG = 1; - parameter integer OPMODEREG = 1; - parameter integer PREG = 1; - parameter SEL_MASK = "MASK"; - parameter SEL_PATTERN = "PATTERN"; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - parameter USE_PATTERN_DETECT = "NO_PATDET"; - parameter USE_SIMD = "ONE48"; - parameter [47:0] MASK = 48'h3FFFFFFFFFFF; - parameter [47:0] PATTERN = 48'h000000000000; - parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; - parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - parameter [4:0] IS_INMODE_INVERTED = 5'b0; - parameter [6:0] IS_OPMODE_INVERTED = 7'b0; - - wire [47:0] $P, $PCOUT; - - DSP48E1 #( - .ACASCREG(ACASCREG), - .ADREG(ADREG), - .ALUMODEREG(ALUMODEREG), - .AREG(AREG), - .AUTORESET_PATDET(AUTORESET_PATDET), - .A_INPUT(A_INPUT), - .BCASCREG(BCASCREG), - .BREG(BREG), - .B_INPUT(B_INPUT), - .CARRYINREG(CARRYINREG), - .CARRYINSELREG(CARRYINSELREG), - .CREG(CREG), - .DREG(DREG), - .INMODEREG(INMODEREG), - .MREG(MREG), - .OPMODEREG(OPMODEREG), - .PREG(PREG), - .SEL_MASK(SEL_MASK), - .SEL_PATTERN(SEL_PATTERN), - .USE_DPORT(USE_DPORT), - .USE_MULT(USE_MULT), - .USE_PATTERN_DETECT(USE_PATTERN_DETECT), - .USE_SIMD(USE_SIMD), - .MASK(MASK), - .PATTERN(PATTERN), - .IS_ALUMODE_INVERTED(IS_ALUMODE_INVERTED), - .IS_CARRYIN_INVERTED(IS_CARRYIN_INVERTED), - .IS_CLK_INVERTED(IS_CLK_INVERTED), - .IS_INMODE_INVERTED(IS_INMODE_INVERTED), - .IS_OPMODE_INVERTED(IS_OPMODE_INVERTED) - ) _TECHMAP_REPLACE_ ( - .ACOUT(ACOUT), - .BCOUT(BCOUT), - .CARRYCASCOUT(CARRYCASCOUT), - .CARRYOUT(CARRYOUT), - .MULTSIGNOUT(MULTSIGNOUT), - .OVERFLOW(OVERFLOW), - .P($P), - .PATTERNBDETECT(PATTERNBDETECT), - .PATTERNDETECT(PATTERNDETECT), - .PCOUT($PCOUT), - .UNDERFLOW(UNDERFLOW), - .A(A), - .ACIN(ACIN), - .ALUMODE(ALUMODE), - .B(B), - .BCIN(BCIN), - .C(C), - .CARRYCASCIN(CARRYCASCIN), - .CARRYIN(CARRYIN), - .CARRYINSEL(CARRYINSEL), - .CEA1(CEA1), - .CEA2(CEA2), - .CEAD(CEAD), - .CEALUMODE(CEALUMODE), - .CEB1(CEB1), - .CEB2(CEB2), - .CEC(CEC), - .CECARRYIN(CECARRYIN), - .CECTRL(CECTRL), - .CED(CED), - .CEINMODE(CEINMODE), - .CEM(CEM), - .CEP(CEP), - .CLK(CLK), - .D(D), - .INMODE(INMODE), - .MULTSIGNIN(MULTSIGNIN), - .OPMODE(OPMODE), - .PCIN(PCIN), - .RSTA(RSTA), - .RSTALLCARRYIN(RSTALLCARRYIN), - .RSTALUMODE(RSTALUMODE), - .RSTB(RSTB), - .RSTC(RSTC), - .RSTCTRL(RSTCTRL), - .RSTD(RSTD), - .RSTINMODE(RSTINMODE), - .RSTM(RSTM), - .RSTP(RSTP) - ); - $__ABC9_DSP48E1 #( - .ADREG(ADREG), - .AREG(AREG), - .BREG(BREG), - .CREG(CREG), - .DREG(DREG), - .MREG(MREG), - .PREG(PREG), - .USE_DPORT(USE_DPORT), - .USE_MULT(USE_MULT) - ) dsp_comb ( - .$A(A), .$B(B), .$C(C), .$D(D), .$P($P), .$PCIN(PCIN), .$PCOUT($PCOUT), .P(P), .PCOUT(PCOUT)); -endmodule diff --git a/techlibs/xilinx/abc9_model.v b/techlibs/xilinx/abc9_model.v index 2d109ef8a..db44ff00b 100644 --- a/techlibs/xilinx/abc9_model.v +++ b/techlibs/xilinx/abc9_model.v @@ -37,174 +37,3 @@ module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1); (S1 => O) = 273; endspecify endmodule - -// Box to emulate async behaviour of FDC* -(* abc9_box, lib_whitebox *) -module \$__ABC9_ASYNC0 (input A, S, output Y); - assign Y = S ? 1'b0 : A; - specify - (A => Y) = 0; - // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - (S => Y) = 764; - endspecify -endmodule - -// Box to emulate async behaviour of FDP* -(* abc9_box, lib_whitebox *) -module \$__ABC9_ASYNC1 (input A, S, output Y); - assign Y = S ? 1'b1 : A; - specify - (A => Y) = 0; - // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - (S => Y) = 764; - endspecify -endmodule - -// Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32} -// Necessary since RAMD* and SRL* have both combinatorial (i.e. -// same-cycle read operation) and sequential (write operation -// is only committed on the next clock edge). -// To model the combinatorial path, such cells have to be split -// into comb and seq parts, with this box modelling only the former. -(* abc9_box *) -module \$__ABC9_RAM6 (input A, input [5:0] S, output Y); - specify - (A => Y) = 0; - (S[0] => Y) = 642; - (S[1] => Y) = 631; - (S[2] => Y) = 472; - (S[3] => Y) = 407; - (S[4] => Y) = 238; - (S[5] => Y) = 127; - endspecify -endmodule -// Box to emulate comb/seq behaviour of RAM128 -(* abc9_box *) -module \$__ABC9_RAM7 (input A, input [6:0] S, output Y); - specify - (A => Y) = 0; - // https://github.com/SymbiFlow/prjxray-db/blob/1c85daf1b115da4d27ca83c6b89f53a94de39748/artix7/timings/slicel.sdf#L867 - (S[0] => Y) = 642 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[1] => Y) = 631 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[2] => Y) = 472 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[3] => Y) = 407 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[4] => Y) = 238 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[5] => Y) = 127 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; - (S[6] => Y) = 0 + 296 /* to select F7BMUX */ + 174 /* CMUX */; - endspecify -endmodule - -// Boxes used to represent the comb behaviour of DSP48E1 -(* abc9_box *) -module $__ABC9_DSP48E1 ( - input [29:0] $A, - input [17:0] $B, - input [47:0] $C, - input [24:0] $D, - input [47:0] $P, - input [47:0] $PCIN, - input [47:0] $PCOUT, - output [47:0] P, - output [47:0] PCOUT -); - parameter integer ADREG = 1; - parameter integer AREG = 1; - parameter integer BREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer MREG = 1; - parameter integer PREG = 1; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - - function integer \A.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \A.P.comb = 2823; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \A.P.comb = 3806; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \A.P.comb = 1523; - end - endfunction - function integer \A.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \A.PCOUT.comb = 2970; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \A.PCOUT.comb = 3954; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \A.PCOUT.comb = 1671; - end - endfunction - function integer \B.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \B.P.comb = 2690; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \B.P.comb = 2690; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \B.P.comb = 1509; - end - endfunction - function integer \B.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \B.PCOUT.comb = 2838; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \B.PCOUT.comb = 2838; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \B.PCOUT.comb = 1658; - end - endfunction - function integer \C.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \C.P.comb = 1325; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \C.P.comb = 1325; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \C.P.comb = 1325; - end - endfunction - function integer \C.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") \C.PCOUT.comb = 1474; - else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \C.PCOUT.comb = 1474; - else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") \C.PCOUT.comb = 1474; - end - endfunction - function integer \D.P.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \D.P.comb = 3717; - end - endfunction - function integer \D.PCOUT.comb ; - begin - if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") \D.PCOUT.comb = 3700; - end - endfunction - - specify - ($P *> P) = 0; - ($PCOUT *> PCOUT) = 0; - endspecify - - // Identical comb delays to DSP48E1 in cells_sim.v - generate - if (PREG == 0 && MREG == 0 && AREG == 0 && ADREG == 0) - specify - ($A *> P) = \A.P.comb (); - ($A *> PCOUT) = \A.PCOUT.comb (); - endspecify - - if (PREG == 0 && MREG == 0 && BREG == 0) - specify - ($B *> P) = \B.P.comb (); - ($B *> PCOUT) = \B.PCOUT.comb (); - endspecify - - if (PREG == 0 && CREG == 0) - specify - ($C *> P) = \C.P.comb (); - ($C *> PCOUT) = \C.PCOUT.comb (); - endspecify - - if (PREG == 0 && MREG == 0 && ADREG == 0 && DREG == 0) - specify - ($D *> P) = \D.P.comb (); - ($D *> PCOUT) = \D.PCOUT.comb (); - endspecify - - if (PREG == 0) - specify - ($PCIN *> P) = 1107; - ($PCIN *> PCOUT) = 1255; - endspecify - endgenerate -endmodule diff --git a/techlibs/xilinx/abc9_unmap.v b/techlibs/xilinx/abc9_unmap.v deleted file mode 100644 index 49a7bd88c..000000000 --- a/techlibs/xilinx/abc9_unmap.v +++ /dev/null @@ -1,57 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * 2019 Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// ============================================================================ - -(* techmap_celltype = "$__ABC9_ASYNC0 $__ABC9_ASYNC1" *) -module $__ABC9_ASYNC01(input A, S, output Y); - assign Y = A; -endmodule - -module $__ABC9_RAM6(input A, input [5:0] S, output Y); - assign Y = A; -endmodule -module $__ABC9_RAM7(input A, input [6:0] S, output Y); - assign Y = A; -endmodule - -module $__ABC9_DSP48E1( - input [29:0] $A, - input [17:0] $B, - input [47:0] $C, - input [24:0] $D, - input [47:0] $P, - input [47:0] $PCIN, - input [47:0] $PCOUT, - output [47:0] P, - output [47:0] PCOUT -); - parameter integer ADREG = 1; - parameter integer AREG = 1; - parameter integer BREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer MREG = 1; - parameter integer PREG = 1; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - - assign P = $P, PCOUT = $PCOUT; -endmodule diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 25df3a865..a6eb9a90e 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -524,10 +524,10 @@ module FDRE ( $setup(R , posedge C &&& !IS_C_INVERTED, 404); $setup(R , negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L243 - if (!IS_C_INVERTED && R ^ IS_R_INVERTED) (posedge C => (Q : 1'b0)) = 303; - if ( IS_C_INVERTED && R ^ IS_R_INVERTED) (negedge C => (Q : 1'b0)) = 303; - if (!IS_C_INVERTED && R ~^ IS_R_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && R ~^ IS_R_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if (!IS_C_INVERTED && R != IS_R_INVERTED) (posedge C => (Q : 1'b0)) = 303; + if ( IS_C_INVERTED && R != IS_R_INVERTED) (negedge C => (Q : 1'b0)) = 303; + if (!IS_C_INVERTED && R == IS_R_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && R == IS_R_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule @@ -589,10 +589,10 @@ module FDSE ( $setup(S , posedge C &&& !IS_C_INVERTED, 404); $setup(S , negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L243 - if (!IS_C_INVERTED && S ^ IS_S_INVERTED) (posedge C => (Q : 1'b1)) = 303; - if ( IS_C_INVERTED && S ^ IS_S_INVERTED) (negedge C => (Q : 1'b1)) = 303; - if (!IS_C_INVERTED && S ~^ IS_S_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && S ~^ IS_S_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if (!IS_C_INVERTED && S != IS_S_INVERTED) (posedge C => (Q : 1'b1)) = 303; + if ( IS_C_INVERTED && S != IS_S_INVERTED) (negedge C => (Q : 1'b1)) = 303; + if (!IS_C_INVERTED && S == IS_S_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && S == IS_S_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule @@ -656,6 +656,7 @@ module FDRSE ( Q <= d; endmodule +(* abc9_box, lib_whitebox *) module FDCE ( output reg Q, (* clkbuf_sink *) @@ -691,13 +692,15 @@ module FDCE ( $setup(CLR, posedge C &&& !IS_C_INVERTED, 404); $setup(CLR, negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //if (!IS_CLR_INVERTED) (posedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0 - //if ( IS_CLR_INVERTED) (negedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0 - if (!IS_C_INVERTED && CLR ~^ IS_CLR_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && CLR ~^ IS_CLR_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if (IS_CLR_INVERTED != CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path + if (!IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule +(* abc9_box, lib_whitebox *) module FDCE_1 ( output reg Q, (* clkbuf_sink *) @@ -717,11 +720,14 @@ module FDCE_1 ( // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 $setup(CLR, negedge C, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //(posedge CLR => (Q : 1'b0)) = 764; // Captured by $__ABC9_ASYNC0 + if (CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path if (!CLR && CE) (negedge C => (Q : D)) = 303; endspecify endmodule +//(* abc9_box, lib_whitebox *) module FDPE ( output reg Q, (* clkbuf_sink *) @@ -756,13 +762,15 @@ module FDPE ( $setup(PRE, posedge C &&& !IS_C_INVERTED, 404); $setup(PRE, negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 - //if ( IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 - if (!IS_C_INVERTED && PRE ~^ IS_PRE_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; - if ( IS_C_INVERTED && PRE ~^ IS_PRE_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if (IS_PRE_INVERTED != PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path + if (!IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; + if ( IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify endmodule +(* abc9_box, lib_whitebox *) module FDPE_1 ( output reg Q, (* clkbuf_sink *) @@ -782,8 +790,9 @@ module FDPE_1 ( // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 $setup(PRE, negedge C, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 - //if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 - //if (IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; // Captured by $__ABC9_ASYNC1 + if (PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path if (!PRE && CE) (negedge C => (Q : D)) = 303; endspecify endmodule @@ -1395,6 +1404,7 @@ module RAM16X1D_1 ( always @(negedge clk) if (WE) mem[a] <= D; endmodule +(* abc9_box, lib_whitebox *) module RAM32X1D ( output DPO, SPO, input D, @@ -1441,15 +1451,15 @@ module RAM32X1D ( if (!IS_WCLK_INVERTED) (posedge WCLK => (DPO : 1'bx)) = 1153; if ( IS_WCLK_INVERTED) (posedge WCLK => (SPO : D)) = 1153; if ( IS_WCLK_INVERTED) (negedge WCLK => (DPO : 1'bx)) = 1153; - // Captured by $__ABC9_RAM6 - //({A0,DPRA0} => {SPO,DPO}) = 642; - //({A1,DPRA1} => {SPO,DPO}) = 631; - //({A2,DPRA2} => {SPO,DPO}) = 472; - //({A3,DPRA3} => {SPO,DPO}) = 407; - //({A4,DPRA4} => {SPO,DPO}) = 238; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module RAM32X1D_1 ( output DPO, SPO, input D, @@ -1491,15 +1501,15 @@ module RAM32X1D_1 ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 if (WE) (negedge WCLK => (SPO : D)) = 1153; if (WE) (negedge WCLK => (DPO : 1'bx)) = 1153; - // Captured by $__ABC9_RAM6 - //({A0,DPRA0} => {SPO,DPO}) = 642; - //({A1,DPRA1} => {SPO,DPO}) = 631; - //({A2,DPRA2} => {SPO,DPO}) = 472; - //({A3,DPRA3} => {SPO,DPO}) = 407; - //({A4,DPRA4} => {SPO,DPO}) = 238; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module RAM64X1D ( output DPO, SPO, input D, @@ -1549,13 +1559,12 @@ module RAM64X1D ( if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DPO : 1'bx)) = 1153; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (SPO : D)) = 1153; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DPO : 1'bx)) = 1153; - // Captured by $__ABC9_RAM6 - //({A0,DPRA0} => {SPO,DPO}) = 642; - //({A1,DPRA1} => {SPO,DPO}) = 631; - //({A2,DPRA2} => {SPO,DPO}) = 472; - //({A3,DPRA3} => {SPO,DPO}) = 407; - //({A4,DPRA4} => {SPO,DPO}) = 238; - //({A5,DPRA5} => {SPO,DPO}) = 127; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; + (A5 => SPO) = 127; (DPRA5 => DPO) = 127; endspecify endmodule @@ -1598,9 +1607,16 @@ module RAM64X1D_1 ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 if (WE) (negedge WCLK => (SPO : D)) = 1153; if (WE) (negedge WCLK => (DPO : 1'bx)) = 1153; + (A0 => SPO) = 642; (DPRA0 => DPO) = 642; + (A1 => SPO) = 632; (DPRA1 => DPO) = 631; + (A2 => SPO) = 472; (DPRA2 => DPO) = 472; + (A3 => SPO) = 407; (DPRA3 => DPO) = 407; + (A4 => SPO) = 238; (DPRA4 => DPO) = 238; + (A5 => SPO) = 127; (DPRA5 => DPO) = 127; endspecify endmodule +(* abc9_box, lib_whitebox *) module RAM128X1D ( output DPO, SPO, input D, @@ -1645,21 +1661,20 @@ module RAM128X1D ( if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (SPO : D)) = 1153 + 217 /* to cross F7AMUX */ + 175 /* AMUX */; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DPO : 1'bx)) = 1153 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; `endif - // Captured by $__ABC9_RAM7 - //(A[0] => SPO) = 642 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[1] => SPO) = 631 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[2] => SPO) = 472 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[3] => SPO) = 407 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[4] => SPO) = 238 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[5] => SPO) = 127 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; - //(A[6] => SPO) = 0 + 276 /* to select F7AMUX */ + 175 /* AMUX */; - //(DPRA[0] => DPO) = 642 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[1] => DPO) = 631 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[2] => DPO) = 472 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[3] => DPO) = 407 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[4] => DPO) = 238 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[5] => DPO) = 127 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; - //(DPRA[6] => DPO) = 0 + 296 /* to select MUXF7 */ + 174 /* CMUX */; + (A[0] => SPO) = 642 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[1] => SPO) = 631 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[2] => SPO) = 472 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[3] => SPO) = 407 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[4] => SPO) = 238 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[5] => SPO) = 127 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; + (A[6] => SPO) = 0 + 276 /* to select F7AMUX */ + 175 /* AMUX */; + (DPRA[0] => DPO) = 642 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[1] => DPO) = 631 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[2] => DPO) = 472 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[3] => DPO) = 407 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[4] => DPO) = 238 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[5] => DPO) = 127 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; + (DPRA[6] => DPO) = 0 + 296 /* to select MUXF7 */ + 174 /* CMUX */; endspecify endmodule @@ -1683,6 +1698,7 @@ endmodule // Multi port. +(* abc9_box, lib_whitebox *) module RAM32M ( output [1:0] DOA, output [1:0] DOB, @@ -1779,12 +1795,11 @@ module RAM32M ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061 if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DOD[1] : DID[1])) = 1190; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DOD[1] : DID[1])) = 1190; - // Captured by $__ABC9_RAM6 - //({{2{ADDRA[0]}},{2{ADDRB[0]}},{2{ADDRC[0]}},{2{ADDRD[0]}}} => {DOA,DOB,DOC,DOD}) = 642; - //({{2{ADDRA[1]}},{2{ADDRB[1]}},{2{ADDRC[1]}},{2{ADDRD[1]}}} => {DOA,DOB,DOC,DOD}) = 631; - //({{2{ADDRA[2]}},{2{ADDRB[2]}},{2{ADDRC[2]}},{2{ADDRD[2]}}} => {DOA,DOB,DOC,DOD}) = 472; - //({{2{ADDRA[3]}},{2{ADDRB[3]}},{2{ADDRC[3]}},{2{ADDRD[3]}}} => {DOA,DOB,DOC,DOD}) = 407; - //({{2{ADDRA[4]}},{2{ADDRB[4]}},{2{ADDRC[4]}},{2{ADDRD[4]}}} => {DOA,DOB,DOC,DOD}) = 238; + (ADDRA[0] *> DOA) = 642; (ADDRB[0] *> DOB) = 642; (ADDRC[0] *> DOC) = 642; (ADDRD[0] *> DOD) = 642; + (ADDRA[1] *> DOA) = 631; (ADDRB[1] *> DOB) = 631; (ADDRC[1] *> DOC) = 631; (ADDRD[1] *> DOD) = 631; + (ADDRA[2] *> DOA) = 472; (ADDRB[2] *> DOB) = 472; (ADDRC[2] *> DOC) = 472; (ADDRD[2] *> DOD) = 472; + (ADDRA[3] *> DOA) = 407; (ADDRB[3] *> DOB) = 407; (ADDRC[3] *> DOC) = 407; (ADDRD[3] *> DOD) = 407; + (ADDRA[4] *> DOA) = 238; (ADDRB[4] *> DOB) = 238; (ADDRC[4] *> DOC) = 238; (ADDRD[4] *> DOD) = 238; endspecify endmodule @@ -1857,6 +1872,7 @@ module RAM32M16 ( end endmodule +(* abc9_box, lib_whitebox *) module RAM64M ( output DOA, output DOB, @@ -1935,12 +1951,11 @@ module RAM64M ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093 if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (DOD : DID)) = 1163; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DOD : DID)) = 1163; - // Captured by $__ABC9_RAM6 - //({ADDRA[0],ADDRB[0],ADDRC[0],ADDRD[0]} => {DOA,DOB,DOC,DOD}) = 642; - //({ADDRA[1],ADDRB[1],ADDRC[1],ADDRD[1]} => {DOA,DOB,DOC,DOD}) = 631; - //({ADDRA[2],ADDRB[2],ADDRC[2],ADDRD[2]} => {DOA,DOB,DOC,DOD}) = 472; - //({ADDRA[3],ADDRB[3],ADDRC[3],ADDRD[3]} => {DOA,DOB,DOC,DOD}) = 407; - //({ADDRA[4],ADDRB[4],ADDRC[4],ADDRD[4]} => {DOA,DOB,DOC,DOD}) = 238; + (ADDRA[0] => DOA) = 642; (ADDRB[0] => DOB) = 642; (ADDRC[0] => DOC) = 642; (ADDRD[0] => DOD) = 642; + (ADDRA[1] => DOA) = 631; (ADDRB[1] => DOB) = 631; (ADDRC[1] => DOC) = 631; (ADDRD[1] => DOD) = 631; + (ADDRA[2] => DOA) = 472; (ADDRB[2] => DOB) = 472; (ADDRC[2] => DOC) = 472; (ADDRD[2] => DOD) = 472; + (ADDRA[3] => DOA) = 407; (ADDRB[3] => DOB) = 407; (ADDRC[3] => DOC) = 407; (ADDRD[3] => DOD) = 407; + (ADDRA[4] => DOA) = 238; (ADDRB[4] => DOB) = 238; (ADDRC[4] => DOC) = 238; (ADDRD[4] => DOD) = 238; endspecify endmodule @@ -2057,6 +2072,7 @@ endmodule // Shift registers. +(* abc9_box, lib_whitebox *) module SRL16 ( output Q, input A0, A1, A2, A3, @@ -2075,14 +2091,14 @@ module SRL16 ( (posedge CLK => (Q : 1'bx)) = 1472; // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK, 173); - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 631; - //(A1 => Q) = 472; - //(A2 => Q) = 407; - //(A3 => Q) = 238; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRL16E ( output Q, input A0, A1, A2, A3, CE, @@ -2108,16 +2124,19 @@ module SRL16E ( $setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173); $setup(D , negedge CLK &&& IS_CLK_INVERTED, 173); // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 + if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : D)) = 1472; + if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : D)) = 1472; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1472; if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1472; - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 631; - //(A1 => Q) = 472; - //(A2 => Q) = 407; - //(A3 => Q) = 238; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRLC16 ( output Q, output Q15, @@ -2134,18 +2153,20 @@ module SRLC16 ( always @(posedge CLK) r <= { r[14:0], D }; specify - // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 - (posedge CLK => (Q : 1'bx)) = 1472; // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK, 173); - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 631; - //(A1 => Q) = 472; - //(A2 => Q) = 407; - //(A3 => Q) = 238; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 + (posedge CLK => (Q : 1'bx)) = 1472; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904 + (posedge CLK => (Q15 : 1'bx)) = 1114; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRLC16E ( output Q, output Q15, @@ -2172,18 +2193,23 @@ module SRLC16E ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173); $setup(D , negedge CLK &&& IS_CLK_INVERTED, 173); + // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 + $setup(CE, posedge CLK &&& !IS_CLK_INVERTED, 109); + $setup(CE, negedge CLK &&& IS_CLK_INVERTED, 109); // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : D)) = 1472; if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : D)) = 1472; - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 642; - //(A1 => Q) = 631; - //(A2 => Q) = 472; - //(A3 => Q) = 407; - //(A4 => Q) = 238; + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904 + if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q15 : 1'bx)) = 1114; + if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q15 : 1'bx)) = 1114; + (A0 => Q) = 631; + (A1 => Q) = 472; + (A2 => Q) = 407; + (A3 => Q) = 238; endspecify endmodule +(* abc9_box, lib_whitebox *) module SRLC32E ( output Q, output Q31, @@ -2211,18 +2237,20 @@ module SRLC32E ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L912 $setup(D , posedge CLK &&& !IS_CLK_INVERTED, 173); $setup(D , negedge CLK &&& IS_CLK_INVERTED, 173); + // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L248 + $setup(CE, posedge CLK &&& !IS_CLK_INVERTED, 109); + $setup(CE, negedge CLK &&& IS_CLK_INVERTED, 109); // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1472; if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1472; // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904 - if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q : 1'bx)) = 1114; - if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q : 1'bx)) = 1114; - // Captured by $__ABC9_RAM6 - //(A0 => Q) = 642; - //(A1 => Q) = 631; - //(A2 => Q) = 472; - //(A3 => Q) = 407; - //(A4 => Q) = 238; + if (!IS_CLK_INVERTED && CE) (posedge CLK => (Q31 : 1'bx)) = 1114; + if ( IS_CLK_INVERTED && CE) (negedge CLK => (Q31 : 1'bx)) = 1114; + (A[0] => Q) = 642; + (A[1] => Q) = 631; + (A[2] => Q) = 472; + (A[3] => Q) = 407; + (A[4] => Q) = 238; endspecify endmodule @@ -2990,6 +3018,8 @@ endmodule // Virtex 6, Series 7. +(* abc9_box=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG), + lib_whitebox=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG) *) module DSP48E1 ( output [29:0] ACOUT, output [17:0] BCOUT, diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index d6ca9e57e..d05715ec2 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -598,7 +598,7 @@ struct SynthXilinxPass : public ScriptPass if (check_label("map_ffs", "('-abc9' only)")) { if (abc9 || help_mode) { if (dff || help_mode) - run("zinit -all", "('-dff' only)"); + run("zinit -all t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "('-dff' only)"); run("techmap -map " + ff_map_file); } } @@ -615,7 +615,6 @@ struct SynthXilinxPass : public ScriptPass if (family != "xc7") log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, " "will use timing for 'xc7' instead.\n", family.c_str()); - run("techmap -map +/xilinx/abc9_map.v -max_iter 1"); run("read_verilog -icells -lib -specify +/xilinx/abc9_model.v"); std::string abc9_opts; std::string k = "synth_xilinx.abc9.W"; @@ -630,7 +629,6 @@ struct SynthXilinxPass : public ScriptPass if (dff) abc9_opts += " -dff"; run("abc9" + abc9_opts); - run("techmap -map +/xilinx/abc9_unmap.v"); } else { std::string abc_opts; diff --git a/tests/arch/xilinx/abc9_dff.ys b/tests/arch/xilinx/abc9_dff.ys index 15343970f..fd343969b 100644 --- a/tests/arch/xilinx/abc9_dff.ys +++ b/tests/arch/xilinx/abc9_dff.ys @@ -46,16 +46,40 @@ FDCE #(.INIT(1)) fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2])); FDPE #(.INIT(1)) fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3])); FDRE_1 #(.INIT(1)) fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4])); FDSE_1 #(.INIT(1)) fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5])); -FDCE_1 #(.INIT(1)) fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6])); +FDCE_1 /*#(.INIT(1))*/ fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6])); FDPE_1 #(.INIT(1)) fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7])); endmodule EOT -logger -expect warning "Module '\$paramod\\FDRE\\INIT=1' contains a \$_DFF_P_ cell .*" 1 -logger -expect warning "Module '\$paramod\\FDRE_1\\INIT=1' contains a \$_DFF_N_ cell .*" 1 -logger -expect warning "Module 'FDSE' contains a \$_DFF_P_ cell .*" 1 -logger -expect warning "Module '\$paramod\\FDSE_1\\INIT=1' contains a \$_DFF_N_ cell .*" 1 +logger -expect warning "Module '\$paramod\\FDRE\\INIT=1' contains a \$dff cell .*" 1 +logger -expect warning "Module '\$paramod\\FDRE_1\\INIT=1' contains a \$dff cell .*" 1 +logger -expect warning "Module 'FDSE' contains a \$dff cell .*" 1 +logger -expect warning "Module '\$paramod\\FDSE_1\\INIT=1' contains a \$dff cell .*" 1 equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf design -load postopt select -assert-count 8 t:FD* + +design -reset +read_verilog < Date: Tue, 21 Apr 2020 12:30:25 -0700 Subject: [PATCH 087/197] abc9_ops: cleanup; -prep_dff -> -prep_dff_submod --- passes/techmap/abc9.cc | 6 +++--- passes/techmap/abc9_ops.cc | 30 +++++++++++------------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index ff9b46b5f..3355cd7aa 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -298,9 +298,9 @@ struct Abc9Pass : public ScriptPass run("opt"); if (dff_mode) { if (!help_mode) - active_design->scratchpad_unset("abc9_ops.prep_dff_map.did_something"); - run("abc9_ops -prep_dff_map", "(only if -dff)"); // rewrite specify - bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_map.did_something"); + active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something"); + run("abc9_ops -prep_dff_submod", "(only if -dff)"); // rewrite specify + bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_submod.did_something"); if (did_something) { // select all $_DFF_[NP]_ // then select all its fanins diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 25ac5c340..bc20d4731 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -191,10 +191,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) // because ABC9 doesn't support them if (init != State::S0) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type)); - // TODO: still necessary? - // Do not use set_bool_attribute() as it will unset the value - // and (attributes.count(ID::abc9_flop) will fail) - derived_module->attributes[ID::abc9_flop] = false; + derived_module->set_bool_attribute(ID::abc9_flop, false); goto skip_cell; } break; @@ -214,10 +211,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) goto skip_cell; } - // TODO: still necessary? - // Do not use set_bool_attribute() as it will unset the value - // and (attributes.count(ID::abc9_box) will fail) - derived_module->attributes[ID::abc9_box] = false; + derived_module->set_bool_attribute(ID::abc9_box, false); } if (derived_type != cell->type) { @@ -273,9 +267,7 @@ void prep_bypass(RTLIL::Design *design) log_assert(inst_module); if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - // Skip if (* abc9_box *) exists or is true - auto it = inst_module->attributes.find(ID::abc9_box); - if (it == inst_module->attributes.end() || it->second.as_bool()) + if (!inst_module->get_bool_attribute(ID::abc9_box)) continue; @@ -464,7 +456,7 @@ void prep_dff(RTLIL::Design *design) } } -void prep_dff_map(RTLIL::Design *design) +void prep_dff_submod(RTLIL::Design *design) { for (auto module : design->modules()) { vector specify_cells; @@ -512,7 +504,7 @@ void prep_dff_map(RTLIL::Design *design) cell->setPort(ID::DST, DST); } - design->scratchpad_set_bool("abc9_ops.prep_dff_map.did_something", true); + design->scratchpad_set_bool("abc9_ops.prep_dff_submod.did_something", true); } } @@ -1548,7 +1540,7 @@ struct Abc9OpsPass : public Pass { log(" select all (* abc9_flop *) modules instantiated in the design and store\n"); log(" in the named selection '$abc9_flops'.\n"); log("\n"); - log(" -prep_dff_map\n"); + log(" -prep_dff_submod\n"); log(" within (* abc9_flop *) modules, attach dummy buffers to all ports and move\n"); log(" all $specify3/$specrule cells that share a 'DST' port with the $_DFF_[NP]_.Q\n"); log(" port from this 'Q' port to the DFF's 'D' port. this is to ensure that all\n"); @@ -1608,7 +1600,7 @@ struct Abc9OpsPass : public Pass { bool mark_scc_mode = false; bool prep_hier_mode = false; bool prep_bypass_mode = false; - bool prep_dff_mode = false, prep_dff_map_mode = false, prep_dff_unmap_mode = false; + bool prep_dff_mode = false, prep_dff_submod_mode = false, prep_dff_unmap_mode = false; bool prep_xaiger_mode = false; bool prep_lut_mode = false; bool prep_box_mode = false; @@ -1647,8 +1639,8 @@ struct Abc9OpsPass : public Pass { valid = true; continue; } - if (arg == "-prep_dff_map") { - prep_dff_map_mode = true; + if (arg == "-prep_dff_submod") { + prep_dff_submod_mode = true; valid = true; continue; } @@ -1717,8 +1709,8 @@ struct Abc9OpsPass : public Pass { prep_bypass(design); if (prep_dff_mode) prep_dff(design); - if (prep_dff_map_mode) - prep_dff_map(design); + if (prep_dff_submod_mode) + prep_dff_submod(design); if (prep_dff_unmap_mode) prep_dff_unmap(design); if (prep_delays_mode) From e2044fd9c7de4534428ee4f3e8cf1448c493a7fc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 12:32:30 -0700 Subject: [PATCH 088/197] abc9_ops: -prep_delays to not insert delay box if input connection is const --- passes/techmap/abc9_ops.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index bc20d4731..d7280e3fd 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -804,6 +804,8 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); if (!port_wire->port_input) continue; + if (conn.second.is_fully_const()) + continue; SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); for (int i = 0; i < GetSize(conn.second); i++) { From d5a8aaba8c6160fe51214677f7452492e950b702 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 12:42:09 -0700 Subject: [PATCH 089/197] abc9_ops: tidy up, suppress error if no boxes/holes --- passes/techmap/abc9.cc | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 3355cd7aa..8fa1f60c5 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -296,25 +296,25 @@ struct Abc9Pass : public ScriptPass run("wbflip"); run("techmap"); run("opt"); - if (dff_mode) { + if (dff_mode || help_mode) { if (!help_mode) active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something"); - run("abc9_ops -prep_dff_submod", "(only if -dff)"); // rewrite specify + run("abc9_ops -prep_dff_submod", " (only if -dff)"); // rewrite specify bool did_something = help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_dff_submod.did_something"); if (did_something) { // select all $_DFF_[NP]_ // then select all its fanins // then select all fanouts of all that // lastly remove $_DFF_[NP]_ cells - run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d"); - run("submod"); - run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop"); - run("abc9_ops -prep_dff_unmap"); - run("design -copy-to $abc9 *_$abc9_flop"); // copy submod out - run("delete *_$abc9_flop"); + run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d", " (only if -dff)"); + run("submod", " (only if -dff)"); + run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop", "(only if -dff)"); + run("abc9_ops -prep_dff_unmap", " (only if -dff)"); + run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out + run("delete *_$abc9_flop", " (only if -dff)"); if (help_mode) { run("foreach module in design"); - run(" rename _$abc9_flop _TECHMAP_REPLACE_"); + run(" rename _$abc9_flop _TECHMAP_REPLACE_", " (only if -dff)"); } else { // Rename all submod-s to _TECHMAP_REPLACE_ to inherit name + attrs @@ -346,17 +346,17 @@ struct Abc9Pass : public ScriptPass run(stringf("abc9_ops -prep_lut %d", maxlut)); if (help_mode) run("abc9_ops -prep_box", "(skip if -box)"); - else if (box_file.empty()) { + else if (box_file.empty()) run("abc9_ops -prep_box"); + if (saved_designs.count("$abc9_holes") || help_mode) { + run("design -stash $abc9"); + run("design -load $abc9_holes"); + run("techmap -wb -map %$abc9 -map +/techmap.v"); + run("opt -purge"); + run("design -stash $abc9_holes"); + run("design -load $abc9"); + run("design -delete $abc9"); } - run("design -stash $abc9"); - run("design -load $abc9_holes"); - run("techmap -wb -map %$abc9 -map +/techmap.v"); - run("opt -purge"); - run("aigmap"); - run("design -stash $abc9_holes"); - run("design -load $abc9"); - run("design -delete $abc9"); } if (check_label("exe")) { From b3e2538a140cac36c32b133d4475a052cfc46809 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 14:12:28 -0700 Subject: [PATCH 090/197] abc9_ops: fix bypass boxes using (* abc9_bypass *) --- kernel/constids.inc | 3 +-- passes/techmap/abc9_ops.cc | 21 +++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/kernel/constids.inc b/kernel/constids.inc index 6b40a5908..25996d2d8 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -2,10 +2,9 @@ X(A) X(abc9_box) X(abc9_box_id) X(abc9_box_seq) +X(abc9_bypass) X(abc9_carry) X(abc9_flop) -X(abc9_holes) -X(abc9_init) X(abc9_lut) X(abc9_mergeability) X(abc9_scc) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d7280e3fd..37d0528c1 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -102,7 +102,7 @@ void check(RTLIL::Design *design, bool dff_mode) auto inst_module = design->module(cell->type); if (!inst_module) continue; - if (!inst_module->attributes.count(ID::abc9_flop)) + if (!inst_module->get_bool_attribute(ID::abc9_flop)) continue; auto derived_type = inst_module->derive(design, cell->parameters); if (!processed.insert(derived_type).second) @@ -171,9 +171,9 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - if (inst_module->attributes.count(ID::abc9_flop) && !dff_mode) + if (inst_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) continue; - if (!inst_module->attributes.count(ID::abc9_box) && !inst_module->attributes.count(ID::abc9_flop)) + if (!inst_module->get_bool_attribute(ID::abc9_box) && !inst_module->get_bool_attribute(ID::abc9_flop)) continue; if (!unmap_design->module(derived_type)) { @@ -205,13 +205,11 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) break; } - if (!found) { - derived_module->set_bool_attribute(ID::abc9_box, false); - log_assert(!derived_module->attributes.count(ID::abc9_box)); + if (!found) goto skip_cell; - } derived_module->set_bool_attribute(ID::abc9_box, false); + derived_module->set_bool_attribute(ID::abc9_bypass); } if (derived_type != cell->type) { @@ -265,9 +263,8 @@ void prep_bypass(RTLIL::Design *design) auto derived_type = inst_module->derive(design, cell->parameters); inst_module = design->module(derived_type); log_assert(inst_module); - if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) - continue; - if (!inst_module->get_bool_attribute(ID::abc9_box)) + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; @@ -444,7 +441,7 @@ void prep_dff(RTLIL::Design *design) auto inst_module = design->module(cell->type); if (!inst_module) continue; - if (!inst_module->attributes.count(ID::abc9_flop)) + if (!inst_module->get_bool_attribute(ID::abc9_flop)) continue; auto derived_type = inst_module->derive(design, cell->parameters); auto derived_module = design->module(derived_type); @@ -589,7 +586,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; auto inst_module = design->module(cell->type); - bool abc9_flop = inst_module && inst_module->attributes.count(ID::abc9_flop); + bool abc9_flop = inst_module && inst_module->get_bool_attribute(ID::abc9_flop); if (abc9_flop && !dff) continue; From a323881e152c0d51728f3df773ac2f326544b379 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 14:13:38 -0700 Subject: [PATCH 091/197] xilinx/ecp5/ice40: add (* abc9_flop *) to bypass-able cells --- techlibs/ecp5/cells_sim.v | 29 ++++++- techlibs/ice40/cells_sim.v | 153 ++++++++++++++++++++++++++++++++++++ techlibs/xilinx/cells_sim.v | 20 ++++- 3 files changed, 198 insertions(+), 4 deletions(-) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 563592218..6f37823e4 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -186,6 +186,7 @@ module PFUMX (input ALUT, BLUT, C0, output Z); endmodule // --------------------------------------- +(* abc9_box, lib_whitebox *) module TRELLIS_DPR16X4 ( input [3:0] DI, input [3:0] WAD, @@ -222,10 +223,16 @@ module TRELLIS_DPR16X4 ( 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, @@ -281,6 +288,10 @@ module DPR16X4C ( assign DO = ram[RAD]; + specify + // TODO + (RAD *> DO) = 0; + endspecify endmodule // --------------------------------------- @@ -295,7 +306,7 @@ endmodule // --------------------------------------- `ifdef YOSYS -(* abc9_flop=(SRMODE != "ASYNC"), lib_whitebox=(SRMODE != "ASYNC") *) +(* 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"; @@ -351,15 +362,27 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); $setup(DI, negedge CLK, 0); $setup(CE, negedge CLK, 0); $setup(LSR, negedge CLK, 0); - if (muxlsr) (negedge CLK => (Q : DI)) = 0; - if (!muxlsr && muxce) (negedge CLK => (Q : srval)) = 0; +`ifndef YOSYS + if (muxlsr) (negedge CLK => (Q : srval)) = 0; +`else + if (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) (negedge CLK => (Q : DI)) = 0; endspecify else specify $setup(DI, posedge CLK, 0); $setup(CE, posedge CLK, 0); $setup(LSR, posedge CLK, 0); +`ifndef YOSYS if (muxlsr) (posedge CLK => (Q : srval)) = 0; +`else + if (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) (posedge CLK => (Q : DI)) = 0; endspecify endgenerate diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 1b759a28f..ad572c877 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -372,6 +372,7 @@ module SB_DFFSR ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFR ( output `SB_DFF_REG, input C, R, D @@ -389,7 +390,13 @@ module SB_DFFR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge R, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!R) (posedge C => (Q : D)) = 540; endspecify @@ -402,7 +409,13 @@ module SB_DFFR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge R, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!R) (posedge C => (Q : D)) = 796; endspecify @@ -415,7 +428,13 @@ module SB_DFFR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!R) (posedge C => (Q : D)) = 1391; endspecify @@ -470,6 +489,7 @@ module SB_DFFSS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFS ( output `SB_DFF_REG, input C, S, D @@ -487,7 +507,13 @@ module SB_DFFS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge S, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!S) (posedge C => (Q : D)) = 540; endspecify @@ -500,7 +526,13 @@ module SB_DFFS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge S, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!S) (posedge C => (Q : D)) = 796; endspecify @@ -513,7 +545,13 @@ module SB_DFFS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge S, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!S) (posedge C => (Q : D)) = 1391; endspecify @@ -576,6 +614,7 @@ module SB_DFFESR ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFER ( output `SB_DFF_REG, input C, E, R, D @@ -595,7 +634,13 @@ module SB_DFFER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge R, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !R) (posedge C => (Q : D)) = 540; endspecify @@ -610,7 +655,13 @@ module SB_DFFER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge R, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !R) (posedge C => (Q : D)) = 796; endspecify @@ -625,7 +676,13 @@ module SB_DFFER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !R) (posedge C => (Q : D)) = 1391; endspecify @@ -688,6 +745,7 @@ module SB_DFFESS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFES ( output `SB_DFF_REG, input C, E, S, D @@ -707,7 +765,13 @@ module SB_DFFES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(posedge S, posedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !S) (posedge C => (Q : D)) = 540; endspecify @@ -722,7 +786,13 @@ module SB_DFFES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(posedge S, posedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !S) (posedge C => (Q : D)) = 796; endspecify @@ -737,7 +807,13 @@ module SB_DFFES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(posedge S, posedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !S) (posedge C => (Q : D)) = 1391; endspecify @@ -891,7 +967,13 @@ module SB_DFFNR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge R, negedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!R) (negedge C => (Q : D)) = 540; endspecify @@ -904,7 +986,13 @@ module SB_DFFNR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge R, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!R) (negedge C => (Q : D)) = 796; endspecify @@ -917,7 +1005,13 @@ module SB_DFFNR ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!R) (negedge C => (Q : D)) = 1391; endspecify @@ -972,6 +1066,7 @@ module SB_DFFNSS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFNS ( output `SB_DFF_REG, input C, S, D @@ -989,7 +1084,13 @@ module SB_DFFNS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge S, negedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (!S) (negedge C => (Q : D)) = 540; endspecify @@ -1002,7 +1103,13 @@ module SB_DFFNS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge S, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (!S) (negedge C => (Q : D)) = 796; endspecify @@ -1015,7 +1122,13 @@ module SB_DFFNS ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge S, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (!S) (negedge C => (Q : D)) = 1391; endspecify @@ -1078,6 +1191,7 @@ module SB_DFFNESR ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFNER ( output `SB_DFF_REG, input C, E, R, D @@ -1097,7 +1211,13 @@ module SB_DFFNER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(R, negedge C, 2160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 599; +`else + if (R) (R => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !R) (negedge C => (Q : D)) = 540; endspecify @@ -1112,7 +1232,13 @@ module SB_DFFNER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(R, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 883; +`else + if (R) (R => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !R) (negedge C => (Q : D)) = 796; endspecify @@ -1127,7 +1253,13 @@ module SB_DFFNER ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge R, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge R => (Q : 1'b0)) = 1589; +`else + if (R) (R => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !R) (negedge C => (Q : D)) = 1391; endspecify @@ -1190,6 +1322,7 @@ module SB_DFFNESS ( `endif endmodule +(* abc9_box, lib_whitebox *) module SB_DFFNES ( output `SB_DFF_REG, input C, E, S, D @@ -1209,7 +1342,14 @@ module SB_DFFNES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L63 $setup(negedge S, negedge C, 160); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 599; +`else + if (S) (S => Q) = 599; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif + // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 if (E && !S) (negedge C => (Q : D)) = 540; endspecify @@ -1224,7 +1364,13 @@ module SB_DFFNES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L63 $setup(negedge S, negedge C, 235); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L91 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 883; +`else + if (S) (S => Q) = 883; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 if (E && !S) (negedge C => (Q : D)) = 796; endspecify @@ -1239,7 +1385,13 @@ module SB_DFFNES ( // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L75 $setup(negedge S, negedge C, 424); // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L103 +`ifndef YOSYS (posedge S => (Q : 1'b1)) = 1589; +`else + if (S) (S => Q) = 1589; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 if (E && !S) (negedge C => (Q : D)) = 1391; endspecify @@ -2736,6 +2888,7 @@ module SB_IO_OD ( `endif endmodule +//(* abc9_box, lib_whitebox *) // TODO module SB_MAC16 ( input CLK, CE, input [15:0] C, A, B, D, diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index a6eb9a90e..cd611399e 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -692,9 +692,14 @@ module FDCE ( $setup(CLR, posedge C &&& !IS_C_INVERTED, 404); $setup(CLR, negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 +`ifndef YOSYS + if (!IS_CLR_INVERTED) (posedge CLR => (Q : 1'b0)) = 764; + if ( IS_CLR_INVERTED) (negedge CLR => (Q : 1'b0)) = 764; +`else if (IS_CLR_INVERTED != CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path // but for facilitating a bypass box, let's pretend it's // a simple path +`endif if (!IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; if ( IS_C_INVERTED && CLR == IS_CLR_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify @@ -720,14 +725,18 @@ module FDCE_1 ( // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 $setup(CLR, negedge C, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 +`ifndef YOSYS + (posedge CLR => (Q : 1'b0)) = 764; +`else if (CLR) (CLR => Q) = 764; // Technically, this should be an edge sensitive path // but for facilitating a bypass box, let's pretend it's // a simple path +`endif if (!CLR && CE) (negedge C => (Q : D)) = 303; endspecify endmodule -//(* abc9_box, lib_whitebox *) +(* abc9_box, lib_whitebox *) module FDPE ( output reg Q, (* clkbuf_sink *) @@ -762,9 +771,14 @@ module FDPE ( $setup(PRE, posedge C &&& !IS_C_INVERTED, 404); $setup(PRE, negedge C &&& IS_C_INVERTED, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 +`ifndef YOSYS + if (!IS_PRE_INVERTED) (posedge PRE => (Q : 1'b1)) = 764; + if ( IS_PRE_INVERTED) (negedge PRE => (Q : 1'b1)) = 764; +`else if (IS_PRE_INVERTED != PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path // but for facilitating a bypass box, let's pretend it's // a simple path +`endif if (!IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (posedge C => (Q : D ^ IS_D_INVERTED)) = 303; if ( IS_C_INVERTED && PRE == IS_PRE_INVERTED && CE) (negedge C => (Q : D ^ IS_D_INVERTED)) = 303; endspecify @@ -790,9 +804,13 @@ module FDPE_1 ( // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L274 $setup(PRE, negedge C, 404); // https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L270 +`ifndef YOSYS + (posedge PRE => (Q : 1'b1)) = 764; +`else if (PRE) (PRE => Q) = 764; // Technically, this should be an edge sensitive path // but for facilitating a bypass box, let's pretend it's // a simple path +`endif if (!PRE && CE) (negedge C => (Q : D)) = 303; endspecify endmodule From ed7cb0b095e0eaf0ced643f7f828ea2c61b939b5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 15:42:05 -0700 Subject: [PATCH 092/197] abc9: put 'aigmap' back --- passes/techmap/abc9.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 8fa1f60c5..93751e0bc 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -353,6 +353,7 @@ struct Abc9Pass : public ScriptPass run("design -load $abc9_holes"); run("techmap -wb -map %$abc9 -map +/techmap.v"); run("opt -purge"); + run("aigmap"); run("design -stash $abc9_holes"); run("design -load $abc9"); run("design -delete $abc9"); From b65610fb628cfd38edcab3c64507477a58cbdd10 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 15:44:56 -0700 Subject: [PATCH 093/197] abc9_ops: move assert --- passes/techmap/abc9_ops.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 37d0528c1..b3f5b9919 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -263,9 +263,9 @@ void prep_bypass(RTLIL::Design *design) auto derived_type = inst_module->derive(design, cell->parameters); inst_module = design->module(derived_type); log_assert(inst_module); - log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); // The idea is to create two techmap designs, one which maps: From 6c34945371a0446159423b0d70f9f10dbc2c4d07 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 15:45:05 -0700 Subject: [PATCH 094/197] xilinx/ice40/ecp5: zinit requires selected wires, so select them all --- techlibs/ecp5/synth_ecp5.cc | 2 +- techlibs/ice40/synth_ice40.cc | 2 +- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 3e475baab..0e49ef01a 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -316,7 +316,7 @@ struct SynthEcp5Pass : public ScriptPass if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); if ((abc9 && dff) || help_mode) - run("zinit -all t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); + run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index f2270dbca..27850b075 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -362,7 +362,7 @@ struct SynthIce40Pass : public ScriptPass run("simplemap t:$dff"); } if ((abc9 && dff) || help_mode) - run("zinit -all t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); + run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "(only if -abc9 and -dff"); run("techmap -map +/ice40/ff_map.v"); run("opt_expr -mux_undef"); run("simplemap"); diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index d05715ec2..d0de73f83 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -598,7 +598,7 @@ struct SynthXilinxPass : public ScriptPass if (check_label("map_ffs", "('-abc9' only)")) { if (abc9 || help_mode) { if (dff || help_mode) - run("zinit -all t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "('-dff' only)"); + run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$__DFFS*", "('-dff' only)"); run("techmap -map " + ff_map_file); } } @@ -608,7 +608,7 @@ struct SynthXilinxPass : public ScriptPass if (flatten_before_abc) run("flatten"); if (help_mode) - run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for 'nowidelut', '-dff', '-retime')"); + run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for '-nowidelut', '-dff', '-retime')"); else if (abc9) { if (lut_size != 6) log_error("'synth_xilinx -abc9' not currently supported for LUT4-based devices.\n"); From 7146c0339e0b79ec24bc89e7fdf15331436e0e53 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 17:03:28 -0700 Subject: [PATCH 095/197] timinginfo: ignore $specify2 cells if EN is false --- kernel/timinginfo.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/timinginfo.h b/kernel/timinginfo.h index 36908868c..d818e580b 100644 --- a/kernel/timinginfo.h +++ b/kernel/timinginfo.h @@ -82,6 +82,9 @@ struct TimingInfo for (auto cell : module->cells()) { if (cell->type == ID($specify2)) { + auto en = cell->getPort(ID::EN); + if (en.is_fully_const() && !en.as_bool()) + continue; auto src = cell->getPort(ID::SRC); auto dst = cell->getPort(ID::DST); for (const auto &c : src.chunks()) From 8cda29137e0e1c19e1115211ee695681bc901030 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 17:04:26 -0700 Subject: [PATCH 096/197] ecp5: TRELLIS_FF bypass path only in async mode --- techlibs/ecp5/cells_sim.v | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 6f37823e4..357fd9173 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -363,11 +363,11 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); $setup(CE, negedge CLK, 0); $setup(LSR, negedge CLK, 0); `ifndef YOSYS - if (muxlsr) (negedge CLK => (Q : srval)) = 0; + if (SRMODE == "ASYNC" && muxlsr) (negedge CLK => (Q : srval)) = 0; `else - if (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 + 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) (negedge CLK => (Q : DI)) = 0; endspecify @@ -377,11 +377,11 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); $setup(CE, posedge CLK, 0); $setup(LSR, posedge CLK, 0); `ifndef YOSYS - if (muxlsr) (posedge CLK => (Q : srval)) = 0; + if (SRMODE == "ASYNC" && muxlsr) (posedge CLK => (Q : srval)) = 0; `else - if (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 + 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) (posedge CLK => (Q : DI)) = 0; endspecify From 2946bb60e95408be1ffc5b667b6c84160f7f41e6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 17:25:15 -0700 Subject: [PATCH 097/197] abc9: rework submod -- since it won't move (* keep *) cells --- passes/techmap/abc9.cc | 7 +++-- passes/techmap/abc9_ops.cc | 60 +++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 93751e0bc..147d6e572 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -309,9 +309,6 @@ struct Abc9Pass : public ScriptPass run("setattr -set submod \"$abc9_flop\" t:$_DFF_?_ %ci* %co* t:$_DFF_?_ %d", " (only if -dff)"); run("submod", " (only if -dff)"); run("setattr -mod -set whitebox 1 -set abc9_flop 1 -set abc9_box 1 *_$abc9_flop", "(only if -dff)"); - run("abc9_ops -prep_dff_unmap", " (only if -dff)"); - run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out - run("delete *_$abc9_flop", " (only if -dff)"); if (help_mode) { run("foreach module in design"); run(" rename _$abc9_flop _TECHMAP_REPLACE_", " (only if -dff)"); @@ -323,7 +320,11 @@ struct Abc9Pass : public ScriptPass if (module->cell(stringf("%s_$abc9_flop", module->name.c_str()))) run(stringf("rename %s_$abc9_flop _TECHMAP_REPLACE_", module->name.c_str())); } + active_design->selected_active_module.clear(); } + run("abc9_ops -prep_dff_unmap", " (only if -dff)"); + run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out + run("delete *_$abc9_flop", " (only if -dff)"); } } run("design -stash $abc9_map"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index b3f5b9919..5521bdf62 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -474,22 +474,11 @@ void prep_dff_submod(RTLIL::Design *design) specify_cells.emplace_back(cell); log_assert(dff_cell); - // Add dummy buffers for all module inputs/outputs - // to ensure that these ports exists in the flop box - // created by later submod pass - for (auto port_name : module->ports) { - auto port = module->wire(port_name); - log_assert(GetSize(port) == 1); - auto c = module->addBufGate(NEW_ID, port, module->addWire(NEW_ID)); - // Need to set (* keep *) otherwise opt_clean - // inside submod will blow it away - c->set_bool_attribute(ID::keep); - } - // Add an additional buffer that drives $_DFF_[NP]_.D - // so that the flop box will have an output + // Add an always-enabled CE mux that drives $_DFF_[NP]_.D so that: + // (a) flop box will have an output + // (b) $_DFF_[NP]_.Q will be present as an input SigBit D = module->addWire(NEW_ID); - Cell *c = module->addBufGate(NEW_ID, dff_cell->getPort(ID::D), D); - c->set_bool_attribute(ID::keep); + module->addMuxGate(NEW_ID, dff_cell->getPort(ID::D), Q, State::S0, D); dff_cell->setPort(ID::D, D); // Rewrite $specify cells that end with $_DFF_[NP]_.Q @@ -513,26 +502,31 @@ void prep_dff_unmap(RTLIL::Design *design) if (!module->get_bool_attribute(ID::abc9_flop) || module->get_bool_attribute(ID::abc9_box)) continue; - auto unmap_module = unmap_design->addModule(module->name.str() + "_$abc9_flop"); - auto replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name); - for (auto port_name : module->ports) { - auto w = unmap_module->addWire(port_name, module->wire(port_name)); - // Do not propagate (* init *) values inside the box - if (w->port_output) - w->attributes.erase(ID::init); - replace_cell->setPort(port_name, w); - } - - // Add new ports appearing in "_$abc9_flop" - auto box_module = design->module(unmap_module->name); + // Make sure the box module has all the same ports present on flop cell + auto replace_cell = module->cell(ID::_TECHMAP_REPLACE_); + log_assert(replace_cell); + auto box_module = design->module(module->name.str() + "_$abc9_flop"); log_assert(box_module); + for (auto port_name : module->ports) { + auto port = module->wire(port_name); + auto box_port = box_module->wire(port_name); + if (box_port) { + // Do not propagate init -- already captured by box + box_port->attributes.erase(ID::init); + continue; + } + log_assert(port->port_input); + box_module->addWire(port_name, port); + replace_cell->setPort(port_name, port); + } + box_module->fixup_ports(); + + auto unmap_module = unmap_design->addModule(box_module->name); + replace_cell = unmap_module->addCell(ID::_TECHMAP_REPLACE_, module->name); for (auto port_name : box_module->ports) { - auto port = box_module->wire(port_name); - auto unmap_port = unmap_module->wire(port_name); - if (!unmap_port) - unmap_port = unmap_module->addWire(port_name, port); - else - unmap_port->port_id = port->port_id; + auto w = unmap_module->addWire(port_name, box_module->wire(port_name)); + if (module->wire(port_name)) + replace_cell->setPort(port_name, w); } unmap_module->ports = box_module->ports; unmap_module->check(); From 57c478c537ef23c05ca34ecdf4c4334fd82c104e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 17:54:24 -0700 Subject: [PATCH 098/197] abc9: only do +/abc9_map if `DFF --- passes/techmap/abc9.cc | 5 ++++- techlibs/common/abc9_map.v | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 147d6e572..60a88f729 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -330,7 +330,10 @@ struct Abc9Pass : public ScriptPass run("design -stash $abc9_map"); run("design -load $abc9"); run("design -delete $abc9"); - run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v"); + if (help_mode) + run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)"); + else + run(stringf("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : "")); run("design -delete $abc9_map"); } diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v index 5f1822485..57b3831d8 100644 --- a/techlibs/common/abc9_map.v +++ b/techlibs/common/abc9_map.v @@ -1,3 +1,4 @@ +`ifdef DFF (* techmap_celltype = "$_DFF_N_ $_DFF_P_" *) module $_DFF_x_(input C, D, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; @@ -23,3 +24,4 @@ module $_DFF_x_(input C, D, output Q); $error("Unrecognised _TECHMAP_CELLTYPE_"); endgenerate endmodule +`endif From ca4f8c94441c16392ffc02a6117f9b3883e7042e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Apr 2020 20:44:11 -0700 Subject: [PATCH 099/197] xilinx: gate specify/attributes from iverilog --- techlibs/xilinx/cells_sim.v | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index cd611399e..d87cfe91b 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -1678,7 +1678,6 @@ module RAM128X1D ( // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 if (!IS_WCLK_INVERTED && WE) (posedge WCLK => (SPO : D)) = 1153 + 217 /* to cross F7AMUX */ + 175 /* AMUX */; if ( IS_WCLK_INVERTED && WE) (negedge WCLK => (DPO : 1'bx)) = 1153 + 223 /* to cross F7BMUX */ + 174 /* CMUX */; -`endif (A[0] => SPO) = 642 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; (A[1] => SPO) = 631 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; (A[2] => SPO) = 472 + 193 /* to cross F7AMUX */ + 175 /* AMUX */; @@ -1693,6 +1692,7 @@ module RAM128X1D ( (DPRA[4] => DPO) = 238 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; (DPRA[5] => DPO) = 127 + 223 /* to cross MUXF7 */ + 174 /* CMUX */; (DPRA[6] => DPO) = 0 + 296 /* to select MUXF7 */ + 174 /* CMUX */; +`endif endspecify endmodule @@ -3036,8 +3036,10 @@ endmodule // Virtex 6, Series 7. +`ifdef YOSYS (* abc9_box=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG), lib_whitebox=!(PREG || AREG || ADREG || BREG || CREG || DREG || MREG) *) +`endif module DSP48E1 ( output [29:0] ACOUT, output [17:0] BCOUT, From f652a9c11c75b7728db838c1c74c587ba92043ca Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Apr 2020 13:07:19 -0700 Subject: [PATCH 100/197] abc9_ops: update docs --- passes/techmap/abc9_ops.cc | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 5521bdf62..a87a94b1d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1516,29 +1516,28 @@ struct Abc9OpsPass : public Pass { log(" derive all used (* abc9_box *) requiring bypass, or (* abc9_flop *) (if\n"); log(" -dff option) whitebox modules. with (* abc9_box *) modules, bypassing is\n"); log(" necessary if sequential elements (e.g. $dff, $mem, etc.) are discovered\n"); - log(" inside, to ensure that any combinatorial paths are correctly captured.\n"); + log(" inside to ensure that any combinatorial paths are correctly captured.\n"); log(" with (* abc9_flop *) modules, only those containing $dff/$_DFF_[NP]_\n"); log(" cells with zero initial state -- due to an ABC limitation -- will be\n"); - log(" derived. for such derived modules, add a rule inside the '$abc9_unmap'\n"); - log(" design that can map a cell instantiating a derived module back to the\n"); - log(" original cell with parameters.\n"); + log(" derived.\n"); log("\n"); log(" -prep_bypass\n"); log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n"); log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n"); - log(" (named *_$abc9_byp) that has inherited all its $specify2 (simple path)\n"); - log(" cells.\n"); + log(" (named *_$abc9_byp). this bypass box will only contain ports that are\n"); + log(" referenced by a simple path declaration ($specify2 cell) inside a\n"); + log(" specify block.\n"); log("\n"); log(" -prep_dff\n"); log(" select all (* abc9_flop *) modules instantiated in the design and store\n"); log(" in the named selection '$abc9_flops'.\n"); log("\n"); log(" -prep_dff_submod\n"); - log(" within (* abc9_flop *) modules, attach dummy buffers to all ports and move\n"); - log(" all $specify3/$specrule cells that share a 'DST' port with the $_DFF_[NP]_.Q\n"); - log(" port from this 'Q' port to the DFF's 'D' port. this is to ensure that all\n"); - log(" module ports will exist in any submodule, and prepare such specify cells to\n"); - log(" be moved within.\n"); + log(" within (* abc9_flop *) modules, rewrite all edge-sensitive path\n"); + log(" declarations and $setup() timing checks ($specify3 and $specrule cells)\n"); + log(" that share a 'DST' port with the $_DFF_[NP]_.Q port from this 'Q' port to\n"); + log(" the DFF's 'D' port. this is to prepare such specify cells to be moved\n"); + log(" into the flop box.\n"); log("\n"); log(" -prep_dff_unmap\n"); log(" populate the '$abc9_unmap' design with techmap rules for mapping *_$abc9_flop\n"); From 8d34aee3d5addfc796ca7057d38e77628c6a77b4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 22 Apr 2020 17:37:07 -0700 Subject: [PATCH 101/197] abc9: update to =_$abc9_flops pattern which includes whiteboxes --- passes/techmap/abc9.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 60a88f729..06097a6f7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -323,8 +323,8 @@ struct Abc9Pass : public ScriptPass active_design->selected_active_module.clear(); } run("abc9_ops -prep_dff_unmap", " (only if -dff)"); - run("design -copy-to $abc9 *_$abc9_flop", " (only if -dff)"); // copy submod out - run("delete *_$abc9_flop", " (only if -dff)"); + run("design -copy-to $abc9 =*_$abc9_flop", " (only if -dff)"); // copy submod out + run("delete =*_$abc9_flop", " (only if -dff)"); } } run("design -stash $abc9_map"); @@ -333,7 +333,7 @@ struct Abc9Pass : public ScriptPass if (help_mode) run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)"); else - run(stringf("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : "")); + run(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : "")); run("design -delete $abc9_map"); } From 39759d5f0ec9bfc0db3dd718cb035596da7f9668 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 14:12:06 -0700 Subject: [PATCH 102/197] ecp5: fix rebase mistake --- techlibs/ecp5/synth_ecp5.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 0e49ef01a..c13020cc1 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -348,10 +348,10 @@ struct SynthEcp5Pass : public ScriptPass else abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); if (nowidelut) - abc9_args += " -maxlut 4"; + abc9_opts += " -maxlut 4"; if (dff) - abc9_args += " -dff"; - run("abc9" + abc9_args); + abc9_opts += " -dff"; + run("abc9" + abc9_opts); run("techmap -map +/ecp5/abc9_unmap.v"); } else { std::string abc_args = " -dress"; From fdc340db8e93d5b50ef515a231f2fef18bdd8165 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 14:16:42 -0700 Subject: [PATCH 103/197] ecp5: synth_ecp5 to no longer need +/ecp5/abc9_{,un}map.v --- techlibs/ecp5/Makefile.inc | 3 --- techlibs/ecp5/abc9_map.v | 27 --------------------------- techlibs/ecp5/abc9_unmap.v | 5 ----- techlibs/ecp5/synth_ecp5.cc | 11 +++-------- 4 files changed, 3 insertions(+), 43 deletions(-) delete mode 100644 techlibs/ecp5/abc9_map.v delete mode 100644 techlibs/ecp5/abc9_unmap.v diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 217151e96..9a337b2b6 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -23,9 +23,6 @@ $(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)) - -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_unmap.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_model.v)) EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk diff --git a/techlibs/ecp5/abc9_map.v b/techlibs/ecp5/abc9_map.v deleted file mode 100644 index 113a35b91..000000000 --- a/techlibs/ecp5/abc9_map.v +++ /dev/null @@ -1,27 +0,0 @@ -// --------------------------------------- - -// Attach a (combinatorial) black-box onto the output -// of this LUTRAM primitive to capture its -// asynchronous read behaviour -module TRELLIS_DPR16X4 ( - (* techmap_autopurge *) input [3:0] DI, - (* techmap_autopurge *) input [3:0] WAD, - (* techmap_autopurge *) input WRE, - (* techmap_autopurge *) input WCK, - (* techmap_autopurge *) input [3:0] RAD, - output [3:0] DO -); - parameter WCKMUX = "WCK"; - parameter WREMUX = "WRE"; - parameter [63:0] INITVAL = 64'h0000000000000000; - wire [3:0] $DO; - - TRELLIS_DPR16X4 #( - .WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL) - ) _TECHMAP_REPLACE_ ( - .DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK), - .RAD(RAD), .DO($DO) - ); - - $__ABC9_DPR16X4_COMB do (.$DO($DO), .RAD(RAD), .DO(DO)); -endmodule diff --git a/techlibs/ecp5/abc9_unmap.v b/techlibs/ecp5/abc9_unmap.v deleted file mode 100644 index cbdffdaf1..000000000 --- a/techlibs/ecp5/abc9_unmap.v +++ /dev/null @@ -1,5 +0,0 @@ -// --------------------------------------- - -module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO); - assign DO = $DO; -endmodule diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index c13020cc1..b99cbdf83 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -328,14 +328,10 @@ struct SynthEcp5Pass : public ScriptPass if (check_label("map_luts")) { - if (abc2 || help_mode) { + if (abc2 || help_mode) run("abc", " (only if -abc2)"); - } - std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v"; - if (abc9) - techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1"; - if (!techmap_args.empty()) - run("techmap " + techmap_args); + if (asyncprld || help_mode) + run("techmap -map +/ecp5/latches_map.v", "(only if -asyncprld)"); if (abc9) { run("read_verilog -icells -lib -specify +/ecp5/abc9_model.v"); @@ -352,7 +348,6 @@ struct SynthEcp5Pass : public ScriptPass if (dff) abc9_opts += " -dff"; run("abc9" + abc9_opts); - run("techmap -map +/ecp5/abc9_unmap.v"); } else { std::string abc_args = " -dress"; if (nowidelut) From cea614f5aeb78446c663240103f94f10e71681e2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 14:42:18 -0700 Subject: [PATCH 104/197] ecp5: latches_map.v if *not* -asyncprld --- techlibs/ecp5/synth_ecp5.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index b99cbdf83..e5c1f7550 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -330,8 +330,8 @@ struct SynthEcp5Pass : public ScriptPass { if (abc2 || help_mode) run("abc", " (only if -abc2)"); - if (asyncprld || help_mode) - run("techmap -map +/ecp5/latches_map.v", "(only if -asyncprld)"); + if (!asyncprld || help_mode) + run("techmap -map +/ecp5/latches_map.v", "(skip if -asyncprld)"); if (abc9) { run("read_verilog -icells -lib -specify +/ecp5/abc9_model.v"); From e79127fcebf9c5aed47f6f56fcfc8a4c4f98705c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 18:02:05 -0700 Subject: [PATCH 105/197] Cleanup; reduce Module::derive() calls --- backends/aiger/xaiger.cc | 38 ++--- passes/techmap/abc9_ops.cc | 271 ++++++++++++++++++----------------- techlibs/common/abc9_model.v | 6 +- techlibs/common/abc9_unmap.v | 2 +- 4 files changed, 164 insertions(+), 153 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index e1962119c..413566699 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -76,6 +76,7 @@ void aiger_encode(std::ostream &f, int x) struct XAigerWriter { + Design *design; Module *module; SigMap sigmap; @@ -138,7 +139,7 @@ struct XAigerWriter return a; } - XAigerWriter(Module *module, bool dff_mode) : module(module), sigmap(module) + XAigerWriter(Module *module, bool dff_mode) : design(module->design), module(module), sigmap(module) { pool undriven_bits; pool unused_bits; @@ -240,15 +241,16 @@ struct XAigerWriter continue; } - RTLIL::Module* inst_module = module->design->module(cell->type); - if (inst_module) { + RTLIL::Module* inst_module = design->module(cell->type); + if (inst_module && inst_module->get_blackbox_attribute()) { IdString derived_type; if (cell->parameters.empty()) derived_type = cell->type; else - derived_type = inst_module->derive(module->design, cell->parameters); - inst_module = module->design->module(derived_type); + derived_type = inst_module->derive(design, cell->parameters); + inst_module = design->module(derived_type); log_assert(inst_module); + log_assert(inst_module->get_blackbox_attribute()); bool abc9_flop = false; if (!cell->has_keep_attr()) { @@ -326,9 +328,9 @@ struct XAigerWriter for (auto cell : box_list) { log_assert(cell); - RTLIL::Module* box_module = module->design->module(cell->type); + RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); - log_assert(box_module->attributes.count(ID::abc9_box_id)); + log_assert(box_module->has_attribute(ID::abc9_box_id)); auto r = box_ports.insert(cell->type); if (r.second) { @@ -576,23 +578,23 @@ struct XAigerWriter for (auto cell : box_list) { log_assert(cell); - RTLIL::Module* box_module = module->design->module(cell->type); + RTLIL::Module* box_module = design->module(cell->type); log_assert(box_module); IdString derived_type; if (cell->parameters.empty()) derived_type = cell->type; else - derived_type = box_module->derive(module->design, cell->parameters); - box_module = box_module->design->module(derived_type); - log_assert(box_module); + derived_type = box_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + log_assert(derived_module); auto r = cell_cache.insert(derived_type); auto &v = r.first->second; if (r.second) { int box_inputs = 0, box_outputs = 0; - for (auto port_name : box_module->ports) { - RTLIL::Wire *w = box_module->wire(port_name); + for (auto port_name : derived_module->ports) { + RTLIL::Wire *w = derived_module->wire(port_name); log_assert(w); if (w->port_input) box_inputs += GetSize(w); @@ -602,7 +604,7 @@ struct XAigerWriter std::get<0>(v) = box_inputs; std::get<1>(v) = box_outputs; - std::get<2>(v) = box_module->attributes.at(ID::abc9_box_id).as_int(); + std::get<2>(v) = derived_module->attributes.at(ID::abc9_box_id).as_int(); } write_h_buffer(std::get<0>(v)); @@ -699,10 +701,10 @@ struct XAigerWriter f << stringf("Generated by %s\n", yosys_version_str); - module->design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); - module->design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); - module->design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size()); - module->design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size()); + design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); + design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); + design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size()); + design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size()); } void write_map(std::ostream &f) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index a87a94b1d..2fbae8c5e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -87,7 +87,7 @@ void check(RTLIL::Design *design, bool dff_mode) } if (dff_mode) { - pool unsupported{ + static pool unsupported{ ID($adff), ID($dlatch), ID($dlatchsr), ID($sr), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), @@ -102,38 +102,38 @@ void check(RTLIL::Design *design, bool dff_mode) auto inst_module = design->module(cell->type); if (!inst_module) continue; - if (!inst_module->get_bool_attribute(ID::abc9_flop)) + if (!inst_module->get_blackbox_attribute()) continue; auto derived_type = inst_module->derive(design, cell->parameters); if (!processed.insert(derived_type).second) continue; - if (inst_module->get_blackbox_attribute(true /* ignore_wb */)) + auto derived_module = design->module(derived_type); + if (!derived_module->get_bool_attribute(ID::abc9_flop)) + continue; + if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) log_error("Module '%s' with (* abc9_flop *) is a blackbox.\n", log_id(derived_type)); - auto derived_module = design->module(derived_type); if (derived_module->has_processes()) Pass::call_on_module(design, derived_module, "proc"); - if (derived_module->get_bool_attribute(ID::abc9_flop)) { - bool found = false; - for (auto derived_cell : derived_module->cells()) - if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { - if (found) - log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module)); - found = true; + bool found = false; + for (auto derived_cell : derived_module->cells()) { + if (derived_cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) { + if (found) + log_error("Module '%s' with (* abc9_flop *) contains more than one $_DFF_[NP]_ cell.\n", log_id(derived_module)); + found = true; - SigBit Q = derived_cell->getPort(ID::Q); - log_assert(GetSize(Q.wire) == 1); + SigBit Q = derived_cell->getPort(ID::Q); + log_assert(GetSize(Q.wire) == 1); - if (!Q.wire->port_output) - log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type)); + if (!Q.wire->port_output) + log_error("Module '%s' contains a %s cell where its 'Q' port does not drive a module output!\n", log_id(derived_module), log_id(derived_cell->type)); - Const init = Q.wire->attributes.at(ID::init, State::Sx); - log_assert(GetSize(init) == 1); - } - else if (unsupported.count(derived_cell->type)) { - log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type)); - } + Const init = Q.wire->attributes.at(ID::init, State::Sx); + log_assert(GetSize(init) == 1); + } + else if (unsupported.count(derived_cell->type)) + log_error("Module '%s' with (* abc9_flop *) contains a %s cell, which is not supported for sequential synthesis.\n", log_id(derived_module), log_id(derived_cell->type)); } } } @@ -146,7 +146,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) r.first->second = new Design; Design *unmap_design = r.first->second; - pool seq_types{ + static const pool seq_types{ ID($dff), ID($dffsr), ID($adff), ID($dlatch), ID($dlatchsr), ID($sr), ID($mem), @@ -166,14 +166,16 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) auto inst_module = design->module(cell->type); if (!inst_module) continue; + if (!inst_module->get_blackbox_attribute()) + continue; auto derived_type = inst_module->derive(design, cell->parameters); auto derived_module = design->module(derived_type); if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - if (inst_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) + if (derived_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) continue; - if (!inst_module->get_bool_attribute(ID::abc9_box) && !inst_module->get_bool_attribute(ID::abc9_flop)) + if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_flop)) continue; if (!unmap_design->module(derived_type)) { @@ -260,11 +262,9 @@ void prep_bypass(RTLIL::Design *design) auto inst_module = design->module(cell->type); if (!inst_module) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; + log_assert(cell->parameters.empty()); log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); @@ -297,7 +297,7 @@ void prep_bypass(RTLIL::Design *design) // assign o = $abc9_byp$o; - // Copy derived_module into map_design, with the same interface + // Copy inst_module into map_design, with the same interface // and duplicate $abc9$* wires for its output ports auto map_module = map_design->addModule(cell->type); for (auto port_name : inst_module->ports) { @@ -443,13 +443,9 @@ void prep_dff(RTLIL::Design *design) continue; if (!inst_module->get_bool_attribute(ID::abc9_flop)) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - log_assert(derived_module); - if (!derived_module->get_bool_attribute(ID::abc9_flop)) - continue; - log_assert(!derived_module->get_blackbox_attribute(true /* ignore_wb */)); - modules_sel.select(derived_module); + log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + log_assert(cell->parameters.empty()); + modules_sel.select(inst_module); } } @@ -562,6 +558,99 @@ void mark_scc(RTLIL::Module *module) } } +void prep_delays(RTLIL::Design *design, bool dff_mode) +{ + TimingInfo timing; + + // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes + // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations + pool flops; + std::vector> cells; + for (auto module : design->selected_modules()) { + if (module->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(module)); + continue; + } + + for (auto cell : module->cells()) { + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) + continue; + + RTLIL::Module* inst_module = design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_blackbox_attribute()) + continue; + + IdString derived_type; + if (cell->parameters.empty()) + derived_type = cell->type; + else + derived_type = inst_module->derive(design, cell->parameters); + auto derived_module = design->module(derived_type); + log_assert(derived_module); + log_assert(derived_module->get_blackbox_attribute()); + + if (derived_module->get_bool_attribute(ID::abc9_box)) + continue; + if (derived_module->get_bool_attribute(ID::abc9_bypass)) + continue; + + if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { + flops.insert(inst_module); + continue; // do not add $__ABC9_DELAY boxes to flops + // as delays will be captured in the flop box + } + + if (!timing.count(derived_type)) + timing.setup_module(derived_module); + + cells.emplace_back(cell, derived_module); + } + } + + // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes + // (or bypassed white-boxes with required times) + for (const auto &i : cells) { + auto cell = i.first; + auto module = cell->module; + auto derived_module = i.second; + auto derived_type = derived_module->name; + + auto &t = timing.at(derived_type).required; + for (auto &conn : cell->connections_) { + auto port_wire = derived_module->wire(conn.first); + if (!port_wire) + log_error("Port %s in cell %s (type %s) of module %s does not actually exist", + log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); + if (!port_wire->port_input) + continue; + if (conn.second.is_fully_const()) + continue; + + SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); + for (int i = 0; i < GetSize(conn.second); i++) { + auto d = t.at(TimingInfo::NameBit(conn.first,i), 0); + if (d == 0) + continue; + +#ifndef NDEBUG + if (ys_debug(1)) { + static std::set> seen; + if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", + log_id(cell->type), log_id(conn.first), i, d); + } +#endif + auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); + box->setPort(ID::I, conn.second[i]); + box->setPort(ID::O, O[i]); + box->setParam(ID::DELAY, d); + conn.second[i] = O[i]; + } + } + } +} + void prep_xaiger(RTLIL::Module *module, bool dff) { auto design = module->design; @@ -670,30 +759,36 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || !box_module->get_bool_attribute(ID::abc9_box)) + if (!box_module) + continue; + if (!box_module->get_blackbox_attribute()) continue; - - cell->attributes[ID::abc9_box_seq] = box_count++; IdString derived_type; if (cell->parameters.empty()) derived_type = cell->type; else derived_type = box_module->derive(design, cell->parameters); - box_module = design->module(derived_type); + auto derived_module = design->module(derived_type); + log_assert(derived_module); + + if (!derived_module->get_bool_attribute(ID::abc9_box)) + continue; + + cell->attributes[ID::abc9_box_seq] = box_count++; auto r = cell_cache.insert(derived_type); auto &holes_cell = r.first->second; if (r.second) { - if (box_module->get_bool_attribute(ID::whitebox)) { + if (derived_module->get_bool_attribute(ID::whitebox)) { holes_cell = holes_module->addCell(cell->name, derived_type); - if (box_module->has_processes()) - Pass::call_on_module(design, box_module, "proc"); + if (derived_module->has_processes()) + Pass::call_on_module(design, derived_module, "proc"); int box_inputs = 0; for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = box_module->wire(port_name); + RTLIL::Wire *w = derived_module->wire(port_name); log_assert(w); log_assert(!w->port_input || !w->port_output); auto &conn = holes_cell->connections_[port_name]; @@ -714,12 +809,12 @@ void prep_xaiger(RTLIL::Module *module, bool dff) conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); } } - else // box_module is a blackbox + else // derived_module is a blackbox log_assert(holes_cell == nullptr); } for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = box_module->wire(port_name); + RTLIL::Wire *w = derived_module->wire(port_name); log_assert(w); if (!w->port_output) continue; @@ -735,92 +830,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } -void prep_delays(RTLIL::Design *design, bool dff_mode) -{ - TimingInfo timing; - - // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes - // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations - pool flops; - std::vector cells; - for (auto module : design->selected_modules()) { - if (module->processes.size() > 0) { - log("Skipping module %s as it contains processes.\n", log_id(module)); - continue; - } - - for (auto cell : module->cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) - continue; - - RTLIL::Module* inst_module = module->design->module(cell->type); - if (!inst_module) - continue; - if (!inst_module->get_blackbox_attribute()) - continue; - if (inst_module->get_bool_attribute(ID::abc9_box)) - continue; - IdString derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - - if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { - flops.insert(inst_module); - continue; // do not add $__ABC9_DELAY boxes to flops - // as delays will be captured in the flop box - } - - if (!timing.count(derived_type)) - timing.setup_module(inst_module); - - cells.emplace_back(cell); - } - } - - // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes - // with required times - for (auto cell : cells) { - auto module = cell->module; - RTLIL::Module* inst_module = module->design->module(cell->type); - log_assert(inst_module); - IdString derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - - auto &t = timing.at(derived_type).required; - for (auto &conn : cell->connections_) { - auto port_wire = inst_module->wire(conn.first); - if (!port_wire) - log_error("Port %s in cell %s (type %s) of module %s does not actually exist", - log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); - if (!port_wire->port_input) - continue; - if (conn.second.is_fully_const()) - continue; - - SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); - for (int i = 0; i < GetSize(conn.second); i++) { - auto d = t.at(TimingInfo::NameBit(conn.first,i), 0); - if (d == 0) - continue; - -#ifndef NDEBUG - if (ys_debug(1)) { - static std::set> seen; - if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", - log_id(cell->type), log_id(conn.first), i, d); - } -#endif - auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); - box->setPort(ID::I, conn.second[i]); - box->setPort(ID::O, O[i]); - box->setParam(ID::DELAY, d); - conn.second[i] = O[i]; - } - } - } -} - void prep_lut(RTLIL::Design *design, int maxlut) { TimingInfo timing; diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v index 41acf4d97..a86f6a436 100644 --- a/techlibs/common/abc9_model.v +++ b/techlibs/common/abc9_model.v @@ -1,5 +1,5 @@ (* abc9_box *) -module \$__ABC9_DELAY (input I, output O); +module $__ABC9_DELAY (input I, output O); parameter DELAY = 0; specify (I => O) = DELAY; @@ -7,7 +7,7 @@ module \$__ABC9_DELAY (input I, output O); endmodule (* abc9_flop, abc9_box, lib_whitebox *) -module $__DFF_N__$abc9_flop(input C, D, Q, (* init=INIT *) output n1); +module $__DFF_N__$abc9_flop (input C, D, Q, (* init=INIT *) output n1); parameter [0:0] INIT = 1'bx; assign n1 = D; specify @@ -17,7 +17,7 @@ module $__DFF_N__$abc9_flop(input C, D, Q, (* init=INIT *) output n1); endmodule (* abc9_flop, abc9_box, lib_whitebox *) -module $__DFF_P__$abc9_flop(input C, D, Q, (* init=INIT *) output n1); +module $__DFF_P__$abc9_flop (input C, D, Q, (* init=INIT *) output n1); parameter [0:0] INIT = 1'bx; assign n1 = D; specify diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v index 4dfac0cbb..d628a73ac 100644 --- a/techlibs/common/abc9_unmap.v +++ b/techlibs/common/abc9_unmap.v @@ -12,7 +12,7 @@ module $__DFF_x__$abc9_flop (input C, D, Q, (* init = INIT *) output n1); endmodule (* techmap_celltype = "$__DFF_N_ $__DFF_P_" *) -module $__DFF_N__$abc9_flop(input C, D, output Q); +module $__DFF_N__$abc9_flop (input C, D, output Q); parameter _TECHMAP_CELLTYPE_ = ""; generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N_") $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); From 97a0a0431489568300b40c1d376af7b5d8cb7027 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 21:56:06 -0700 Subject: [PATCH 106/197] abc9_ops/xaiger: further reducing Module::derive() calls by ... replacing _all_ (* abc9_box *) instantiations with their derived types --- backends/aiger/xaiger.cc | 72 +++++++-------- passes/techmap/abc9_ops.cc | 174 +++++++++++++++++------------------ techlibs/common/abc9_map.v | 6 +- techlibs/common/abc9_model.v | 6 +- 4 files changed, 122 insertions(+), 136 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 413566699..3aa0e1110 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -243,34 +243,33 @@ struct XAigerWriter RTLIL::Module* inst_module = design->module(cell->type); if (inst_module && inst_module->get_blackbox_attribute()) { - IdString derived_type; - if (cell->parameters.empty()) - derived_type = cell->type; - else - derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - log_assert(inst_module->get_blackbox_attribute()); - bool abc9_flop = false; - if (!cell->has_keep_attr()) { - auto it = cell->attributes.find(ID::abc9_box_seq); - if (it != cell->attributes.end()) { - int abc9_box_seq = it->second.as_int(); - if (GetSize(box_list) <= abc9_box_seq) - box_list.resize(abc9_box_seq+1); - box_list[abc9_box_seq] = cell; - // Only flop boxes may have arrival times - // (all others are combinatorial) - abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop); - if (!abc9_flop) - continue; - } + + auto it = cell->attributes.find(ID::abc9_box_seq); + if (it != cell->attributes.end()) { + log_assert(!cell->has_keep_attr()); + int abc9_box_seq = it->second.as_int(); + if (GetSize(box_list) <= abc9_box_seq) + box_list.resize(abc9_box_seq+1); + box_list[abc9_box_seq] = cell; + // Only flop boxes may have arrival times + // (all others are combinatorial) + log_assert(cell->parameters.empty()); + abc9_flop = inst_module->get_bool_attribute(ID::abc9_flop); + if (!abc9_flop) + continue; } - if (!timing.count(derived_type)) + if (!cell->parameters.empty()) { + auto derived_type = inst_module->derive(design, cell->parameters); + inst_module = design->module(derived_type); + log_assert(inst_module); + log_assert(inst_module->get_blackbox_attribute()); + } + + if (!timing.count(inst_module->name)) timing.setup_module(inst_module); - auto &t = timing.at(derived_type).arrival; + auto &t = timing.at(inst_module->name).arrival; for (const auto &conn : cell->connections()) { auto port_wire = inst_module->wire(conn.first); if (!port_wire->port_output) @@ -284,7 +283,7 @@ struct XAigerWriter #ifndef NDEBUG if (ys_debug(1)) { static std::set> seen; - if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_arrival = %d\n", + if (seen.emplace(inst_module->name, conn.first, i).second) log("%s.%s[%d] abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), i, d); } #endif @@ -577,24 +576,17 @@ struct XAigerWriter int box_count = 0; for (auto cell : box_list) { log_assert(cell); + log_assert(cell->parameters.empty()); - RTLIL::Module* box_module = design->module(cell->type); - log_assert(box_module); - - IdString derived_type; - if (cell->parameters.empty()) - derived_type = cell->type; - else - derived_type = box_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - log_assert(derived_module); - - auto r = cell_cache.insert(derived_type); + auto r = cell_cache.insert(cell->type); auto &v = r.first->second; if (r.second) { + RTLIL::Module* box_module = design->module(cell->type); + log_assert(box_module); + int box_inputs = 0, box_outputs = 0; - for (auto port_name : derived_module->ports) { - RTLIL::Wire *w = derived_module->wire(port_name); + for (auto port_name : box_module->ports) { + RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); if (w->port_input) box_inputs += GetSize(w); @@ -604,7 +596,7 @@ struct XAigerWriter std::get<0>(v) = box_inputs; std::get<1>(v) = box_outputs; - std::get<2>(v) = derived_module->attributes.at(ID::abc9_box_id).as_int(); + std::get<2>(v) = box_module->attributes.at(ID::abc9_box_id).as_int(); } write_h_buffer(std::get<0>(v)); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2fbae8c5e..2794c913a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -104,10 +104,17 @@ void check(RTLIL::Design *design, bool dff_mode) continue; if (!inst_module->get_blackbox_attribute()) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - if (!processed.insert(derived_type).second) - continue; - auto derived_module = design->module(derived_type); + IdString derived_type; + Module *derived_module; + if (cell->parameters.empty()) { + derived_type = cell->type; + derived_module = inst_module; + } + else { + derived_type = inst_module->derive(design, cell->parameters); + derived_module = design->module(derived_type); + log_assert(derived_module); + } if (!derived_module->get_bool_attribute(ID::abc9_flop)) continue; if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) @@ -168,15 +175,27 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) continue; if (!inst_module->get_blackbox_attribute()) continue; - auto derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); + IdString derived_type; + Module *derived_module; + if (cell->parameters.empty()) { + derived_type = cell->type; + derived_module = inst_module; + } + else { + derived_type = inst_module->derive(design, cell->parameters); + derived_module = design->module(derived_type); + } if (derived_module->get_blackbox_attribute(true /* ignore_wb */)) continue; - if (derived_module->get_bool_attribute(ID::abc9_flop) && !dff_mode) - continue; - if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_flop)) - continue; + if (derived_module->get_bool_attribute(ID::abc9_flop)) { + if (!dff_mode) + continue; + } + else { + if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass)) + continue; + } if (!unmap_design->module(derived_type)) { if (derived_module->has_processes()) @@ -200,18 +219,12 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) } } else if (derived_module->get_bool_attribute(ID::abc9_box)) { - bool found = false; for (auto derived_cell : derived_module->cells()) if (seq_types.count(derived_cell->type)) { - found = true; + derived_module->set_bool_attribute(ID::abc9_box, false); + derived_module->set_bool_attribute(ID::abc9_bypass); break; } - - if (!found) - goto skip_cell; - - derived_module->set_bool_attribute(ID::abc9_box, false); - derived_module->set_bool_attribute(ID::abc9_bypass); } if (derived_type != cell->type) { @@ -264,8 +277,8 @@ void prep_bypass(RTLIL::Design *design) continue; if (!inst_module->get_bool_attribute(ID::abc9_bypass)) continue; - log_assert(cell->parameters.empty()); log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */)); + log_assert(cell->parameters.empty()); // The idea is to create two techmap designs, one which maps: @@ -564,8 +577,7 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) // Derive all Yosys blackbox modules that are not combinatorial abc9 boxes // (e.g. DSPs, RAMs, etc.) nor abc9 flops and collect all such instantiations - pool flops; - std::vector> cells; + std::vector cells; for (auto module : design->selected_modules()) { if (module->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(module)); @@ -573,56 +585,51 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) } for (auto cell : module->cells()) { - if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_), ID($__ABC9_DELAY))) + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($_DFF_N_), ID($_DFF_P_))) continue; + log_assert(!cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")); RTLIL::Module* inst_module = design->module(cell->type); if (!inst_module) continue; if (!inst_module->get_blackbox_attribute()) continue; - - IdString derived_type; - if (cell->parameters.empty()) - derived_type = cell->type; - else - derived_type = inst_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - log_assert(derived_module); - log_assert(derived_module->get_blackbox_attribute()); - - if (derived_module->get_bool_attribute(ID::abc9_box)) + if (!cell->parameters.empty()) continue; - if (derived_module->get_bool_attribute(ID::abc9_bypass)) + + if (inst_module->get_bool_attribute(ID::abc9_box)) + continue; + if (inst_module->get_bool_attribute(ID::abc9_bypass)) continue; if (dff_mode && inst_module->get_bool_attribute(ID::abc9_flop)) { - flops.insert(inst_module); continue; // do not add $__ABC9_DELAY boxes to flops // as delays will be captured in the flop box } - if (!timing.count(derived_type)) - timing.setup_module(derived_module); + if (!timing.count(cell->type)) + timing.setup_module(inst_module); - cells.emplace_back(cell, derived_module); + cells.emplace_back(cell); } } // Insert $__ABC9_DELAY cells on all cells that instantiate blackboxes // (or bypassed white-boxes with required times) - for (const auto &i : cells) { - auto cell = i.first; + dict box_cache; + Module *delay_module = design->module(ID($__ABC9_DELAY)); + log_assert(delay_module); + for (auto cell : cells) { auto module = cell->module; - auto derived_module = i.second; - auto derived_type = derived_module->name; + auto inst_module = design->module(cell->type); + log_assert(inst_module); - auto &t = timing.at(derived_type).required; + auto &t = timing.at(cell->type).required; for (auto &conn : cell->connections_) { - auto port_wire = derived_module->wire(conn.first); + auto port_wire = inst_module->wire(conn.first); if (!port_wire) - log_error("Port %s in cell %s (type %s) of module %s does not actually exist", - log_id(conn.first), log_id(cell->name), log_id(cell->type), log_id(module->name)); + log_error("Port %s in cell %s (type %s) from module %s does not actually exist", + log_id(conn.first), log_id(cell), log_id(cell->type), log_id(module)); if (!port_wire->port_input) continue; if (conn.second.is_fully_const()) @@ -637,14 +644,18 @@ void prep_delays(RTLIL::Design *design, bool dff_mode) #ifndef NDEBUG if (ys_debug(1)) { static std::set> seen; - if (seen.emplace(derived_type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", + if (seen.emplace(cell->type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n", log_id(cell->type), log_id(conn.first), i, d); } #endif - auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); + auto r = box_cache.insert(d); + if (r.second) { + r.first->second = delay_module->derive(design, {{ID::DELAY, d}}); + log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY=")); + } + auto box = module->addCell(NEW_ID, r.first->second); box->setPort(ID::I, conn.second[i]); box->setPort(ID::O, O[i]); - box->setParam(ID::DELAY, d); conn.second[i] = O[i]; } } @@ -761,34 +772,26 @@ void prep_xaiger(RTLIL::Module *module, bool dff) RTLIL::Module* box_module = design->module(cell->type); if (!box_module) continue; - if (!box_module->get_blackbox_attribute()) - continue; - - IdString derived_type; - if (cell->parameters.empty()) - derived_type = cell->type; - else - derived_type = box_module->derive(design, cell->parameters); - auto derived_module = design->module(derived_type); - log_assert(derived_module); - - if (!derived_module->get_bool_attribute(ID::abc9_box)) + if (!box_module->get_bool_attribute(ID::abc9_box)) continue; +log_cell(cell); + log_assert(cell->parameters.empty()); + log_assert(box_module->get_blackbox_attribute()); cell->attributes[ID::abc9_box_seq] = box_count++; - auto r = cell_cache.insert(derived_type); + auto r = cell_cache.insert(cell->type); auto &holes_cell = r.first->second; if (r.second) { - if (derived_module->get_bool_attribute(ID::whitebox)) { - holes_cell = holes_module->addCell(cell->name, derived_type); + if (box_module->get_bool_attribute(ID::whitebox)) { + holes_cell = holes_module->addCell(cell->name, cell->type); - if (derived_module->has_processes()) - Pass::call_on_module(design, derived_module, "proc"); + if (box_module->has_processes()) + Pass::call_on_module(design, box_module, "proc"); int box_inputs = 0; for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = derived_module->wire(port_name); + RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); log_assert(!w->port_input || !w->port_output); auto &conn = holes_cell->connections_[port_name]; @@ -806,15 +809,15 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } else if (w->port_output) - conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); + conn = holes_module->addWire(stringf("%s.%s", cell->type.c_str(), log_id(port_name)), GetSize(w)); } } - else // derived_module is a blackbox + else // box_module is a blackbox log_assert(holes_cell == nullptr); } for (auto port_name : box_ports.at(cell->type)) { - RTLIL::Wire *w = derived_module->wire(port_name); + RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); if (!w->port_output) continue; @@ -1282,7 +1285,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) if (!existing_cell) log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell)); - if (existing_cell->type == ID($__ABC9_DELAY)) { + if (existing_cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { SigBit I = mapped_cell->getPort(ID(i)); SigBit O = mapped_cell->getPort(ID(o)); if (I.wire) @@ -1294,14 +1297,8 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) } RTLIL::Module* box_module = design->module(existing_cell->type); - IdString derived_type; - if (existing_cell->parameters.empty()) - derived_type = existing_cell->type; - else - derived_type = box_module->derive(design, existing_cell->parameters); - RTLIL::Module* derived_module = design->module(derived_type); - log_assert(derived_module); - log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at(ID::abc9_box_id).as_int())); + log_assert(existing_cell->parameters.empty()); + log_assert(mapped_cell->type == stringf("$__boxid%d", box_module->attributes.at(ID::abc9_box_id).as_int())); mapped_cell->type = existing_cell->type; RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); @@ -1329,7 +1326,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) } int input_count = 0, output_count = 0; - for (const auto &port_name : box_ports.at(derived_type)) { + for (const auto &port_name : box_ports.at(existing_cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); @@ -1522,19 +1519,18 @@ struct Abc9OpsPass : public Pass { log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); log("\n"); log(" -prep_hier\n"); - log(" derive all used (* abc9_box *) requiring bypass, or (* abc9_flop *) (if\n"); - log(" -dff option) whitebox modules. with (* abc9_box *) modules, bypassing is\n"); - log(" necessary if sequential elements (e.g. $dff, $mem, etc.) are discovered\n"); - log(" inside to ensure that any combinatorial paths are correctly captured.\n"); - log(" with (* abc9_flop *) modules, only those containing $dff/$_DFF_[NP]_\n"); - log(" cells with zero initial state -- due to an ABC limitation -- will be\n"); - log(" derived.\n"); + log(" derive all used (* abc9_box *) or (* abc9_flop *) (if -dff option)\n"); + log(" whitebox modules. with (* abc9_flop *) modules, only those containing\n"); + log(" $dff/$_DFF_[NP]_ cells with zero initial state -- due to an ABC limitation\n"); + log(" -- will be derived.\n"); log("\n"); log(" -prep_bypass\n"); log(" create techmap rules in the '$abc9_map' and '$abc9_unmap' designs for\n"); log(" bypassing sequential (* abc9_box *) modules using a combinatorial box\n"); - log(" (named *_$abc9_byp). this bypass box will only contain ports that are\n"); - log(" referenced by a simple path declaration ($specify2 cell) inside a\n"); + log(" (named *_$abc9_byp). bypassing is necessary if sequential elements (e.g.\n"); + log(" $dff, $mem, etc.) are discovered inside so that any combinatorial paths\n"); + log(" will be correctly captured. this bypass box will only contain ports that\n"); + log(" are referenced by a simple path declaration ($specify2 cell) inside a\n"); log(" specify block.\n"); log("\n"); log(" -prep_dff\n"); diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v index 57b3831d8..182915842 100644 --- a/techlibs/common/abc9_map.v +++ b/techlibs/common/abc9_map.v @@ -3,10 +3,10 @@ module $_DFF_x_(input C, D, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter _TECHMAP_CELLTYPE_ = ""; - wire D_; + (* init=_TECHMAP_WIREINIT_Q_ *) wire D_; generate if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin - $__DFF_N__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $__DFF_N__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); $_DFF_N_ ff (.C(C), .D(D_), .Q(Q)); end else @@ -14,7 +14,7 @@ module $_DFF_x_(input C, D, output Q); end else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin - $__DFF_P__$abc9_flop #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); + $__DFF_P__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); $_DFF_P_ ff (.C(C), .D(D_), .Q(Q)); end else diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v index a86f6a436..4fee60f75 100644 --- a/techlibs/common/abc9_model.v +++ b/techlibs/common/abc9_model.v @@ -7,8 +7,7 @@ module $__ABC9_DELAY (input I, output O); endmodule (* abc9_flop, abc9_box, lib_whitebox *) -module $__DFF_N__$abc9_flop (input C, D, Q, (* init=INIT *) output n1); - parameter [0:0] INIT = 1'bx; +module $__DFF_N__$abc9_flop (input C, D, Q, output n1); assign n1 = D; specify $setup(D, posedge C, 0); @@ -17,8 +16,7 @@ module $__DFF_N__$abc9_flop (input C, D, Q, (* init=INIT *) output n1); endmodule (* abc9_flop, abc9_box, lib_whitebox *) -module $__DFF_P__$abc9_flop (input C, D, Q, (* init=INIT *) output n1); - parameter [0:0] INIT = 1'bx; +module $__DFF_P__$abc9_flop (input C, D, Q, output n1); assign n1 = D; specify $setup(D, posedge C, 0); From fa31e84112c004348fae30e64ca224367b71d187 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 May 2020 22:10:24 -0700 Subject: [PATCH 107/197] Fix broken test when ignoring abc9_flop with init == 1'b1 --- passes/techmap/abc9_ops.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2794c913a..41a11e9a7 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -213,7 +213,6 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) if (init != State::S0) { log_warning("Module '%s' contains a %s cell with non-zero initial state -- this is not unsupported for ABC9 sequential synthesis. Treating as a blackbox.\n", log_id(derived_module), log_id(derived_cell->type)); derived_module->set_bool_attribute(ID::abc9_flop, false); - goto skip_cell; } break; } @@ -250,8 +249,6 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) cell->type = derived_type; cell->parameters.clear(); - -skip_cell: ; } } From 13f9d65b6fc09af76330c02ab420324b50db61da Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 00:29:45 -0700 Subject: [PATCH 108/197] abc9: preserve $_DFF_?_.Q's (* init *); rely on clean to remove it --- passes/techmap/abc9_ops.cc | 18 +----------------- techlibs/common/abc9_map.v | 4 ++-- techlibs/common/abc9_unmap.v | 5 ++--- tests/various/abc9.ys | 11 ++++++++--- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 41a11e9a7..03a3c5583 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1101,17 +1101,6 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) map_autoidx = autoidx++; - // TODO: Get rid of this expensive lookup - dict> sig2inits; - SigMap sigmap(module); - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it == w->attributes.end()) - continue; - for (const auto &b : SigSpec(w)) - sig2inits[sigmap(b)].emplace_back(b); - } - RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str())); if (mapped_mod == NULL) log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module)); @@ -1164,12 +1153,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // Short out $_DFF_[NP]_ cells since the flop box already has // all the information we need to reconstruct cell if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - SigBit Q = cell->getPort(ID::Q); - auto it = sig2inits.find(Q); - if (it != sig2inits.end()) - for (const auto &b : it->second) - b.wire->attributes.at(ID::init)[b.offset] = State::Sx; - module->connect(Q, cell->getPort(ID::D)); + module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); module->remove(cell); } else if (cell->type.in(ID($_AND_), ID($_NOT_))) diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v index 182915842..bb2b4a4b1 100644 --- a/techlibs/common/abc9_map.v +++ b/techlibs/common/abc9_map.v @@ -3,14 +3,14 @@ module $_DFF_x_(input C, D, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; parameter _TECHMAP_CELLTYPE_ = ""; - (* init=_TECHMAP_WIREINIT_Q_ *) wire D_; + wire D_; generate if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin $__DFF_N__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_)); $_DFF_N_ ff (.C(C), .D(D_), .Q(Q)); end else - $__DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));// hide from abc9 using $__ prefix + $__DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); // hide from abc9 using $__ prefix end else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v index d628a73ac..b765356d8 100644 --- a/techlibs/common/abc9_unmap.v +++ b/techlibs/common/abc9_unmap.v @@ -1,6 +1,5 @@ (* techmap_celltype = "$__DFF_N__$abc9_flop $__DFF_P__$abc9_flop" *) -module $__DFF_x__$abc9_flop (input C, D, Q, (* init = INIT *) output n1); - parameter [0:0] INIT = 1'bx; +module $__DFF_x__$abc9_flop (input C, D, Q, output n1); parameter _TECHMAP_CELLTYPE_ = ""; generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N__$abc9_flop") $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); @@ -12,7 +11,7 @@ module $__DFF_x__$abc9_flop (input C, D, Q, (* init = INIT *) output n1); endmodule (* techmap_celltype = "$__DFF_N_ $__DFF_P_" *) -module $__DFF_N__$abc9_flop (input C, D, output Q); +module $__DFF_x_ (input C, D, output Q); parameter _TECHMAP_CELLTYPE_ = ""; generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N_") $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys index 9586091c4..ac714665f 100644 --- a/tests/various/abc9.ys +++ b/tests/various/abc9.ys @@ -78,18 +78,23 @@ abc9 design -reset read_verilog -icells < Date: Thu, 14 May 2020 02:09:13 -0700 Subject: [PATCH 109/197] abc9_ops: -prep_hier to create unmap module that removes Q's (* init *) --- passes/techmap/abc9_ops.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 03a3c5583..6a8dbde8b 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -230,9 +230,12 @@ void prep_hier(RTLIL::Design *design, bool dff_mode) auto unmap_module = unmap_design->addModule(derived_type); for (auto port : derived_module->ports) { auto w = unmap_module->addWire(port, derived_module->wire(port)); - // Do not propagate (* init *) values inside the box - if (w->port_output) - w->attributes.erase(ID::init); + // Do not propagate (* init *) values into the box, + // in fact, remove it from outside too + if (w->port_output && w->attributes.erase(ID::init)) { + auto r = unmap_module->addWire(stringf("\\_TECHMAP_REMOVEINIT_%s_", log_id(port))); + unmap_module->connect(r, State::S1); + } } unmap_module->ports = derived_module->ports; unmap_module->check(); @@ -771,7 +774,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; if (!box_module->get_bool_attribute(ID::abc9_box)) continue; -log_cell(cell); log_assert(cell->parameters.empty()); log_assert(box_module->get_blackbox_attribute()); From 425867d175f465a7568e146ef4d23bd975d9c55c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 10:38:31 -0700 Subject: [PATCH 110/197] logger: clean up doc --- passes/cmds/logger.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 64f939525..50b89d92f 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -58,7 +58,8 @@ struct LoggerPass : public Pass { log(" do not print warnings for the specified experimental feature\n"); log("\n"); log(" -expect \n"); - log(" expect log,warning or error to appear. In case of error return code is 0.\n"); + log(" expect log, warning or error to appear. matched errors will terminate\n"); + log(" with exit code 0.\n"); log("\n"); log(" -expect-no-warnings\n"); log(" gives error in case there is at least one warning that is not expected.\n"); From 7b3a4a1fff297481a463f27da250af8436041753 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 12:14:23 -0700 Subject: [PATCH 111/197] opt_expr: Sx to Sz; spotted by @Xiretza --- passes/opt/opt_expr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 63811c1a1..777a24777 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -175,7 +175,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ } } - bool def = (bit_a != State::Sx && bit_a != State::Sz && bit_b != State::Sx && bit_b != State::Sx); + bool def = (bit_a != State::Sx && bit_a != State::Sz && bit_b != State::Sx && bit_b != State::Sz); if (def || !keepdc) { if (bit_a.wire == NULL && bit_b.wire == NULL) group_idx = GRP_CONST_AB; From 985a29ff3b1f9ce19b091aa2541dc07dbc669341 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 5 Apr 2020 07:07:50 +0000 Subject: [PATCH 112/197] Clean up pseudo-private member usage, superfluous `std::vector` instantiation, and `RTLIL::id2cstr()` usage in `passes/techmap/techmap.cc`. --- passes/techmap/techmap.cc | 146 ++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 76 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index a554be257..f300c2f72 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -54,8 +54,8 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) if (chunk.wire != NULL) { IdString wire_name = chunk.wire->name; apply_prefix(prefix, wire_name); - log_assert(module->wires_.count(wire_name) > 0); - chunk.wire = module->wires_[wire_name]; + log_assert(module->wire(wire_name) != nullptr); + chunk.wire = module->wire(wire_name); } sig = chunks; } @@ -132,8 +132,8 @@ struct TechmapWorker if (module == NULL) return result; - for (auto &it : module->wires_) { - const char *p = it.first.c_str(); + for (auto w : module->wires()) { + const char *p = w->name.c_str(); if (*p == '$') continue; @@ -142,11 +142,11 @@ struct TechmapWorker if (!strncmp(p, "_TECHMAP_", 9)) { TechmapWireData record; - record.wire = it.second; - record.value = it.second; + record.wire = w; + record.value = w; result[p].push_back(record); - it.second->attributes[ID::keep] = RTLIL::Const(1); - it.second->attributes[ID::_techmap_special_] = RTLIL::Const(1); + w->attributes[ID::keep] = RTLIL::Const(1); + w->attributes[ID::_techmap_special_] = RTLIL::Const(1); } } @@ -165,7 +165,7 @@ struct TechmapWorker if (tpl->processes.size() != 0) { log("Technology map yielded processes:"); for (auto &it : tpl->processes) - log(" %s",RTLIL::id2cstr(it.first)); + log(" %s",log_id(it.first)); log("\n"); if (autoproc_mode) { Pass::call_on_module(tpl->design, tpl, "proc"); @@ -179,8 +179,8 @@ struct TechmapWorker orig_cell_name = cell->name.str(); if (!flatten_mode) { - for (auto &it : tpl->cells_) - if (it.first == ID::_TECHMAP_REPLACE_) { + for (auto tpl_cell : tpl->cells()) + if (tpl_cell->name == ID::_TECHMAP_REPLACE_) { module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); break; } @@ -208,26 +208,26 @@ struct TechmapWorker dict temp_renamed_wires; pool autopurge_tpl_bits; - for (auto &it : tpl->wires_) + for (auto tpl_w : tpl->wires()) { - if (it.second->port_id > 0) + if (tpl_w->port_id > 0) { - IdString posportname = stringf("$%d", it.second->port_id); - positional_ports[posportname] = it.first; + IdString posportname = stringf("$%d", tpl_w->port_id); + positional_ports[posportname] = tpl_w->name; - if (!flatten_mode && it.second->get_bool_attribute(ID::techmap_autopurge) && - (!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) && + if (!flatten_mode && tpl_w->get_bool_attribute(ID::techmap_autopurge) && + (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) { if (sigmaps.count(tpl) == 0) sigmaps[tpl].set(tpl); - for (auto bit : sigmaps.at(tpl)(it.second)) + for (auto bit : sigmaps.at(tpl)(tpl_w)) if (bit.wire != nullptr) autopurge_tpl_bits.insert(bit); } } - IdString w_name = it.second->name; + IdString w_name = tpl_w->name; apply_prefix(cell->name, w_name); RTLIL::Wire *w = module->wire(w_name); if (w != nullptr) { @@ -237,30 +237,30 @@ struct TechmapWorker w = nullptr; } else { w->attributes.erase(ID::hierconn); - if (GetSize(w) < GetSize(it.second)) { + if (GetSize(w) < GetSize(tpl_w)) { log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), - log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); - w->width = GetSize(it.second); + log_id(tpl), log_id(tpl_w), log_id(module), log_id(cell)); + w->width = GetSize(tpl_w); } } } if (w == nullptr) { - w = module->addWire(w_name, it.second); + w = module->addWire(w_name, tpl_w); w->port_input = false; w->port_output = false; w->port_id = 0; if (!flatten_mode) w->attributes.erase(ID::techmap_autopurge); - if (it.second->get_bool_attribute(ID::_techmap_special_)) + if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); if (w->attributes.count(ID::src)) w->add_strpool_attribute(ID::src, extra_src_attrs); } design->select(module, w); - if (it.second->name.begins_with("\\_TECHMAP_REPLACE_.")) { - IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), it.second->name.c_str() + strlen("\\_TECHMAP_REPLACE_")); - Wire *replace_w = module->addWire(replace_name, it.second); + if (tpl_w->name.begins_with("\\_TECHMAP_REPLACE_.")) { + IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), tpl_w->name.c_str() + strlen("\\_TECHMAP_REPLACE_")); + Wire *replace_w = module->addWire(replace_name, tpl_w); module->connect(replace_w, w); } } @@ -268,9 +268,9 @@ struct TechmapWorker SigMap tpl_sigmap(tpl); pool tpl_written_bits; - for (auto &it1 : tpl->cells_) - for (auto &it2 : it1.second->connections_) - if (it1.second->output(it2.first)) + for (auto tpl_cell : tpl->cells()) + for (auto &it2 : tpl_cell->connections_) + if (tpl_cell->output(it2.first)) for (auto bit : tpl_sigmap(it2.second)) tpl_written_bits.insert(bit); for (auto &it1 : tpl->connections_) @@ -285,7 +285,7 @@ struct TechmapWorker RTLIL::IdString portname = it.first; if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); - if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) { + if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) { if (portname.begins_with("$")) log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); continue; @@ -294,7 +294,7 @@ struct TechmapWorker if (GetSize(it.second) == 0) continue; - RTLIL::Wire *w = tpl->wires_.at(portname); + RTLIL::Wire *w = tpl->wire(portname); RTLIL::SigSig c, extra_connect; if (w->port_output && !w->port_input) { @@ -377,19 +377,19 @@ struct TechmapWorker } } - for (auto &it : tpl->cells_) + for (auto tpl_cell : tpl->cells()) { - IdString c_name = it.second->name.str(); + IdString c_name = tpl_cell->name; bool techmap_replace_cell = (!flatten_mode) && (c_name == ID::_TECHMAP_REPLACE_); if (techmap_replace_cell) c_name = orig_cell_name; - else if (it.second->name.begins_with("\\_TECHMAP_REPLACE_.")) + else if (tpl_cell->name.begins_with("\\_TECHMAP_REPLACE_.")) c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_")); else apply_prefix(cell->name, c_name); - RTLIL::Cell *c = module->addCell(c_name, it.second); + RTLIL::Cell *c = module->addCell(c_name, tpl_cell); design->select(module, c); if (!flatten_mode && c->type.begins_with("\\$")) @@ -493,9 +493,9 @@ struct TechmapWorker std::map> cell_to_inbit; std::map> outbit_to_cell; - for (auto cell : module->cells()) + for (auto cell : module->selected_cells()) { - if (!design->selected(module, cell) || handled_cells.count(cell) > 0) + if (handled_cells.count(cell) > 0) continue; std::string cell_type = cell->type.str(); @@ -511,7 +511,7 @@ struct TechmapWorker if (flatten_mode) { bool keepit = cell->get_bool_attribute(ID::keep_hierarchy); for (auto &tpl_name : celltypeMap.at(cell_type)) - if (map->modules_[tpl_name]->get_bool_attribute(ID::keep_hierarchy)) + if (map->module(tpl_name)->get_bool_attribute(ID::keep_hierarchy)) keepit = true; if (keepit) { if (!flatten_keep_list[cell]) { @@ -533,7 +533,7 @@ struct TechmapWorker continue; for (auto &tpl_name : celltypeMap.at(cell_type)) { - RTLIL::Module *tpl = map->modules_[tpl_name]; + RTLIL::Module *tpl = map->module(tpl_name); RTLIL::Wire *port = tpl->wire(conn.first); if (port && port->port_input) cell_to_inbit[cell].insert(sig.begin(), sig.end()); @@ -567,7 +567,7 @@ struct TechmapWorker for (auto &tpl_name : celltypeMap.at(cell_type)) { RTLIL::IdString derived_name = tpl_name; - RTLIL::Module *tpl = map->modules_[tpl_name]; + RTLIL::Module *tpl = map->module(tpl_name); std::map parameters(cell->parameters.begin(), cell->parameters.end()); if (tpl->get_blackbox_attribute(ignore_wb)) @@ -675,7 +675,7 @@ struct TechmapWorker if (extmapper_name == "simplemap") { if (simplemap_mappers.count(cell->type) == 0) - log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type)); + log_error("No simplemap mapper for cell type %s found!\n", log_id(cell->type)); simplemap_mappers.at(cell->type)(module, cell); } @@ -697,7 +697,7 @@ struct TechmapWorker for (auto conn : cell->connections()) { if (conn.first.begins_with("$")) continue; - if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0) + if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0) continue; if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) goto next_tpl; @@ -713,20 +713,20 @@ struct TechmapWorker parameters[ID::_TECHMAP_CELLTYPE_] = RTLIL::unescape_id(cell->type); for (auto conn : cell->connections()) { - if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) { + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0); - parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); + parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))] = RTLIL::SigSpec(v).as_const(); } - if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) { + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) if (bit.wire != NULL) bit = RTLIL::SigBit(RTLIL::State::Sx); - parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); + parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))] = RTLIL::SigSpec(v).as_const(); } - if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))) != 0) { + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { auto sig = sigmap(conn.second); RTLIL::Const value(State::Sx, sig.size()); for (int i = 0; i < sig.size(); i++) { @@ -735,7 +735,7 @@ struct TechmapWorker value[i] = it->second; } } - parameters[stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))] = value; + parameters[stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))] = value; } } @@ -747,8 +747,8 @@ struct TechmapWorker unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++; for (auto conn : cell->connections()) - if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { - for (auto &bit : sigmap(conn.second).to_sigbit_vector()) + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) { + for (auto &bit : sigmap(conn.second)) if (unique_bit_id.count(bit) == 0) unique_bit_id[bit] = unique_bit_id_counter++; } @@ -764,13 +764,13 @@ struct TechmapWorker parameters[ID::_TECHMAP_BITS_CONNMAP_] = bits; for (auto conn : cell->connections()) - if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) { RTLIL::Const value; - for (auto &bit : sigmap(conn.second).to_sigbit_vector()) { + for (auto &bit : sigmap(conn.second)) { RTLIL::Const chunk(unique_bit_id.at(bit), bits); value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end()); } - parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value; + parameters[stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))] = value; } } @@ -819,7 +819,7 @@ struct TechmapWorker RTLIL::SigSpec value = it.value; if (value.is_fully_const() && value.as_bool()) { log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", - derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value)); + derived_name.c_str(), log_id(it.wire->name), log_signal(value)); techmap_do_cache[tpl] = false; } } @@ -835,7 +835,7 @@ struct TechmapWorker auto &data = it.second.front(); if (!data.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(data.wire->name), log_signal(data.value)); techmap_wire_names.erase(it.first); @@ -926,7 +926,7 @@ struct TechmapWorker log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); - while (tpl->wires_.count(new_name)) + while (tpl->wire(new_name) != nullptr) new_name += "_"; tpl->rename(data.wire->name, new_name); @@ -942,12 +942,12 @@ struct TechmapWorker if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(it2.wire->name), log_signal(it2.value)); techmap_wire_names.erase(it.first); } for (auto &it : techmap_wire_names) - log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it)); + log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", log_id(it)); if (recursive_mode) { if (log_continue) { @@ -1301,17 +1301,16 @@ struct TechmapPass : public Pass { log_header(design, "Continuing TECHMAP pass.\n"); std::map> celltypeMap; - for (auto &it : map->modules_) { - if (it.second->attributes.count(ID::techmap_celltype) && !it.second->attributes.at(ID::techmap_celltype).bits.empty()) { - char *p = strdup(it.second->attributes.at(ID::techmap_celltype).decode_string().c_str()); + for (auto module : map->modules()) { + if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) { + char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str()); for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n")) - celltypeMap[RTLIL::escape_id(q)].insert(it.first); + celltypeMap[RTLIL::escape_id(q)].insert(module->name); free(p); } else { - string module_name = it.first.str(); - if (it.first.begins_with("\\$")) - module_name = module_name.substr(1); - celltypeMap[module_name].insert(it.first); + std::string module_name = module->name.begins_with("\\$") ? + module->name.substr(1) : module->name.str(); + celltypeMap[module_name].insert(module->name); } } @@ -1402,9 +1401,8 @@ struct FlattenPass : public Pass { worker.flatten_do_list.erase(mod->name); } } else { - for (auto mod : vector(design->modules())) { + for (auto mod : design->modules().to_vector()) while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { } - } } log_suppressed(); @@ -1425,15 +1423,11 @@ struct FlattenPass : public Pass { new_used_modules.insert(cell->type); } - dict new_modules; - for (auto mod : vector(design->modules())) - if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) { - new_modules[mod->name] = mod; - } else { + for (auto mod : design->modules()) + if (!used_modules[mod->name] && !mod->get_blackbox_attribute(worker.ignore_wb)) { log("Deleting now unused module %s.\n", log_id(mod)); - delete mod; + design->remove(mod); } - design->modules_.swap(new_modules); } log_pop(); From e49fdee40441cb4b1892007560d56467fd75a798 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 10 Apr 2020 07:19:05 +0000 Subject: [PATCH 113/197] Do not modify design modules while iterating over `modules()`. Co-Authored-By: Eddie Hung --- passes/techmap/techmap.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index f300c2f72..930b4c416 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1423,11 +1423,14 @@ struct FlattenPass : public Pass { new_used_modules.insert(cell->type); } + std::set to_remove; for (auto mod : design->modules()) if (!used_modules[mod->name] && !mod->get_blackbox_attribute(worker.ignore_wb)) { log("Deleting now unused module %s.\n", log_id(mod)); - design->remove(mod); + to_remove.insert(mod); } + for (auto mod : to_remove) + design->remove(mod); } log_pop(); From 5f7f213c7f3182169c5efe12c9c8e9ceec3ef81f Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 14 Apr 2020 17:38:43 +0000 Subject: [PATCH 114/197] Replace `std::string` and `RTLIL::IdString` with `IdString` in `passes/techmap/techmap.cc`. Co-Authored-By: Eddie Hung --- passes/techmap/techmap.cc | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 930b4c416..dd5369ed0 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -62,10 +62,10 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) struct TechmapWorker { - std::map simplemap_mappers; - std::map>, RTLIL::Module*> techmap_cache; + std::map simplemap_mappers; + std::map>, RTLIL::Module*> techmap_cache; std::map techmap_do_cache; - std::set> module_queue; + std::set> module_queue; dict sigmaps; pool flatten_do_list; @@ -79,7 +79,7 @@ struct TechmapWorker RTLIL::SigSpec value; }; - typedef std::map> TechmapWires; + typedef std::map> TechmapWires; bool extern_mode; bool assert_mode; @@ -101,7 +101,7 @@ struct TechmapWorker std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) { std::string constmap_info; - std::map> connbits_map; + std::map> connbits_map; for (auto conn : cell->connections()) for (int i = 0; i < GetSize(conn.second); i++) { @@ -117,7 +117,7 @@ struct TechmapWorker constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); } else { - connbits_map[bit] = std::pair(conn.first, i); + connbits_map[bit] = std::pair(conn.first, i); constmap_info += stringf("|%s %d", log_id(conn.first), i); } } @@ -204,7 +204,7 @@ struct TechmapWorker design->select(module, m); } - std::map positional_ports; + std::map positional_ports; dict temp_renamed_wires; pool autopurge_tpl_bits; @@ -282,7 +282,7 @@ struct TechmapWorker for (auto &it : cell->connections()) { - RTLIL::IdString portname = it.first; + IdString portname = it.first; if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) { @@ -464,7 +464,7 @@ struct TechmapWorker } bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set &handled_cells, - const std::map> &celltypeMap, bool in_recursion) + const std::map> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -489,7 +489,7 @@ struct TechmapWorker } } - TopoSort> cells; + TopoSort> cells; std::map> cell_to_inbit; std::map> outbit_to_cell; @@ -566,9 +566,9 @@ struct TechmapWorker for (auto &tpl_name : celltypeMap.at(cell_type)) { - RTLIL::IdString derived_name = tpl_name; + IdString derived_name = tpl_name; RTLIL::Module *tpl = map->module(tpl_name); - std::map parameters(cell->parameters.begin(), cell->parameters.end()); + std::map parameters(cell->parameters.begin(), cell->parameters.end()); if (tpl->get_blackbox_attribute(ignore_wb)) continue; @@ -778,13 +778,13 @@ struct TechmapWorker use_wrapper_tpl:; // do not register techmap_wrap modules with techmap_cache } else { - std::pair> key(tpl_name, parameters); + std::pair> key(tpl_name, parameters); if (techmap_cache.count(key) > 0) { tpl = techmap_cache[key]; } else { if (parameters.size() != 0) { mkdebug.on(); - derived_name = tpl->derive(map, dict(parameters.begin(), parameters.end())); + derived_name = tpl->derive(map, dict(parameters.begin(), parameters.end())); tpl = map->module(derived_name); log_continue = true; } @@ -805,7 +805,7 @@ struct TechmapWorker bool keep_running = true; techmap_do_cache[tpl] = true; - std::set techmap_wire_names; + std::set techmap_wire_names; while (keep_running) { @@ -851,7 +851,7 @@ struct TechmapWorker cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); log("Analyzing pattern of constant bits for this cell:\n"); - RTLIL::IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true); + IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true); log("Creating constmapped module `%s'.\n", log_id(new_tpl_name)); log_assert(map->module(new_tpl_name) == nullptr); @@ -871,7 +871,7 @@ struct TechmapWorker if (!wire->port_input || wire->port_output) continue; - RTLIL::IdString port_name = wire->name; + IdString port_name = wire->name; tpl->rename(wire, NEW_ID); RTLIL::Wire *new_wire = tpl->addWire(port_name, wire); @@ -1300,7 +1300,7 @@ struct TechmapPass : public Pass { log_header(design, "Continuing TECHMAP pass.\n"); - std::map> celltypeMap; + std::map> celltypeMap; for (auto module : map->modules()) { if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) { char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str()); @@ -1381,7 +1381,7 @@ struct FlattenPass : public Pass { extra_args(args, argidx, design); - std::map> celltypeMap; + std::map> celltypeMap; for (auto module : design->modules()) celltypeMap[module->name].insert(module->name); @@ -1410,10 +1410,10 @@ struct FlattenPass : public Pass { if (top_mod != NULL) { - pool used_modules, new_used_modules; + pool used_modules, new_used_modules; new_used_modules.insert(top_mod->name); while (!new_used_modules.empty()) { - pool queue; + pool queue; queue.swap(new_used_modules); for (auto modname : queue) used_modules.insert(modname); From 99b586b28367e1aea8c9e75a8132079c4a3687f9 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 14 Apr 2020 17:44:33 +0000 Subject: [PATCH 115/197] Use `nullptr` instead of `NULL` in `passes/techmap/techmap.cc`. --- passes/techmap/techmap.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index dd5369ed0..99ec92f33 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -51,7 +51,7 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) { vector chunks = sig; for (auto &chunk : chunks) - if (chunk.wire != NULL) { + if (chunk.wire != nullptr) { IdString wire_name = chunk.wire->name; apply_prefix(prefix, wire_name); log_assert(module->wire(wire_name) != nullptr); @@ -129,7 +129,7 @@ struct TechmapWorker { TechmapWires result; - if (module == NULL) + if (module == nullptr) return result; for (auto w : module->wires()) { @@ -686,7 +686,7 @@ struct TechmapWorker } module->remove(cell); - cell = NULL; + cell = nullptr; } did_something = true; @@ -716,13 +716,13 @@ struct TechmapWorker if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) - bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0); + bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0); parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))] = RTLIL::SigSpec(v).as_const(); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) - if (bit.wire != NULL) + if (bit.wire != nullptr) bit = RTLIL::SigBit(RTLIL::State::Sx); parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))] = RTLIL::SigSpec(v).as_const(); } @@ -1015,7 +1015,7 @@ struct TechmapWorker } log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); techmap_module_worker(design, module, cell, tpl); - cell = NULL; + cell = nullptr; } did_something = true; mapped_cell = true; @@ -1304,7 +1304,7 @@ struct TechmapPass : public Pass { for (auto module : map->modules()) { if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) { char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str()); - for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n")) + for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n")) celltypeMap[RTLIL::escape_id(q)].insert(module->name); free(p); } else { @@ -1385,14 +1385,14 @@ struct FlattenPass : public Pass { for (auto module : design->modules()) celltypeMap[module->name].insert(module->name); - RTLIL::Module *top_mod = NULL; + RTLIL::Module *top_mod = nullptr; if (design->full_selection()) for (auto mod : design->modules()) if (mod->get_bool_attribute(ID::top)) top_mod = mod; std::set handled_cells; - if (top_mod != NULL) { + if (top_mod != nullptr) { worker.flatten_do_list.insert(top_mod->name); while (!worker.flatten_do_list.empty()) { auto mod = design->module(*worker.flatten_do_list.begin()); @@ -1408,7 +1408,7 @@ struct FlattenPass : public Pass { log_suppressed(); log("No more expansions possible.\n"); - if (top_mod != NULL) + if (top_mod != nullptr) { pool used_modules, new_used_modules; new_used_modules.insert(top_mod->name); From 437f3fb342f91d0c1a1a923c92312301a03cb07d Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 14 Apr 2020 17:50:23 +0000 Subject: [PATCH 116/197] Replace `std::map` with `dict` for `simplemap_mappers`. --- passes/techmap/simplemap.cc | 6 +++--- passes/techmap/simplemap.h | 2 +- passes/techmap/techmap.cc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index b65b3e972..214157a64 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -522,7 +522,7 @@ void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell) } } -void simplemap_get_mappers(std::map &mappers) +void simplemap_get_mappers(dict &mappers) { mappers[ID($not)] = simplemap_not; mappers[ID($pos)] = simplemap_pos; @@ -559,7 +559,7 @@ void simplemap_get_mappers(std::map mappers; + static dict mappers; static bool initialized_mappers = false; if (!initialized_mappers) { @@ -595,7 +595,7 @@ struct SimplemapPass : public Pass { log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); - std::map mappers; + dict mappers; simplemap_get_mappers(mappers); for (auto mod : design->modules()) { diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h index c2d73ea79..5091050a1 100644 --- a/passes/techmap/simplemap.h +++ b/passes/techmap/simplemap.h @@ -42,7 +42,7 @@ extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell); extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell); -extern void simplemap_get_mappers(std::map &mappers); +extern void simplemap_get_mappers(dict &mappers); YOSYS_NAMESPACE_END diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 99ec92f33..bd7cc14a9 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -62,7 +62,7 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) struct TechmapWorker { - std::map simplemap_mappers; + dict simplemap_mappers; std::map>, RTLIL::Module*> techmap_cache; std::map techmap_do_cache; std::set> module_queue; From 2fb4931e5be2c2a0c80ffbca73ad74ebb8c9032f Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 14 Apr 2020 18:09:05 +0000 Subject: [PATCH 117/197] Add specialized `hash()` for type `dict` and use a `dict` instead of a `std::map` for `techmap_cache` and `techmap_do_cache`. --- kernel/hashlib.h | 25 ++++++++++++++++++++----- kernel/rtlil.h | 2 +- passes/techmap/techmap.cc | 8 ++++---- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 592d6e577..cdbad87c4 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -19,6 +19,12 @@ namespace hashlib { +template struct hash_ops; +template> class dict; +template> class idict; +template> class pool; +template> class mfp; + const int hashtable_size_trigger = 2; const int hashtable_size_factor = 3; @@ -100,6 +106,20 @@ template struct hash_ops> { } }; +template struct hash_ops> { + static inline bool cmp(dict a, dict b) { + return a == b; + } + static inline unsigned int hash(dict a) { + unsigned int h = mkhash_init; + for (auto &it : a) { + h = mkhash(h, hash_ops

::hash(it.first)); + h = mkhash(h, hash_ops::hash(it.second)); + } + return h; + } +}; + template struct hash_ops> { static inline bool cmp(std::tuple a, std::tuple b) { return a == b; @@ -191,11 +211,6 @@ inline int hashtable_size(int min_size) throw std::length_error("hash table exceeded maximum size."); } -template> class dict; -template> class idict; -template> class pool; -template> class mfp; - template class dict { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 11c45bbec..dad8508c3 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -150,7 +150,7 @@ namespace RTLIL if (!p[0]) return 0; - log_assert(p[0] == '$' || p[0] == '\\'); + log_assert(p[0] == '$' || p[0] == '\\' || strncmp(p, "_TECHMAP_", strlen("_TECHMAP_")) == 0); log_assert(p[1] != 0); auto it = global_id_index_.find((char*)p); diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index bd7cc14a9..9779ecae9 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -63,8 +63,8 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) struct TechmapWorker { dict simplemap_mappers; - std::map>, RTLIL::Module*> techmap_cache; - std::map techmap_do_cache; + dict>, RTLIL::Module*> techmap_cache; + dict techmap_do_cache; std::set> module_queue; dict sigmaps; @@ -568,7 +568,7 @@ struct TechmapWorker { IdString derived_name = tpl_name; RTLIL::Module *tpl = map->module(tpl_name); - std::map parameters(cell->parameters.begin(), cell->parameters.end()); + dict parameters(cell->parameters.begin(), cell->parameters.end()); if (tpl->get_blackbox_attribute(ignore_wb)) continue; @@ -778,7 +778,7 @@ struct TechmapWorker use_wrapper_tpl:; // do not register techmap_wrap modules with techmap_cache } else { - std::pair> key(tpl_name, parameters); + std::pair> key(tpl_name, parameters); if (techmap_cache.count(key) > 0) { tpl = techmap_cache[key]; } else { From 64c16f8c1364bbe45bc17a54c29d70990efb45ad Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 22:21:52 +0000 Subject: [PATCH 118/197] Replace `std::map` with `dict` for `positional_ports`. --- passes/techmap/techmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 9779ecae9..651f772c9 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -204,7 +204,7 @@ struct TechmapWorker design->select(module, m); } - std::map positional_ports; + dict positional_ports; dict temp_renamed_wires; pool autopurge_tpl_bits; From 67f4046c05622140d9d2ae93d8cc44bb680b3b20 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 22:24:20 +0000 Subject: [PATCH 119/197] Replace `std::set` with `pool` for `handled_cells` and `techmap_wire_names`. --- passes/techmap/techmap.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 651f772c9..55d80bad1 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -463,7 +463,7 @@ struct TechmapWorker } } - bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set &handled_cells, + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, const std::map> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -805,7 +805,7 @@ struct TechmapWorker bool keep_running = true; techmap_do_cache[tpl] = true; - std::set techmap_wire_names; + pool techmap_wire_names; while (keep_running) { @@ -1324,7 +1324,7 @@ struct TechmapPass : public Pass { int module_max_iter = max_iter; bool did_something = true; - std::set handled_cells; + pool handled_cells; while (did_something) { did_something = false; if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) @@ -1391,7 +1391,7 @@ struct FlattenPass : public Pass { if (mod->get_bool_attribute(ID::top)) top_mod = mod; - std::set handled_cells; + pool handled_cells; if (top_mod != nullptr) { worker.flatten_do_list.insert(top_mod->name); while (!worker.flatten_do_list.empty()) { From 644e55b3d30159b3dc033e5cfbfe07bde2604ea7 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 22:32:28 +0000 Subject: [PATCH 120/197] Replace `std::map` with `dict` for `celltypeMap`. --- passes/techmap/techmap.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 55d80bad1..416d96862 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -464,7 +464,7 @@ struct TechmapWorker } bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, - const std::map> &celltypeMap, bool in_recursion) + const dict> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -1300,7 +1300,7 @@ struct TechmapPass : public Pass { log_header(design, "Continuing TECHMAP pass.\n"); - std::map> celltypeMap; + dict> celltypeMap; for (auto module : map->modules()) { if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) { char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str()); @@ -1381,7 +1381,7 @@ struct FlattenPass : public Pass { extra_args(args, argidx, design); - std::map> celltypeMap; + dict> celltypeMap; for (auto module : design->modules()) celltypeMap[module->name].insert(module->name); From c43017fc082ecf860283c860e8f9de18c3ae09c3 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 22:34:17 +0000 Subject: [PATCH 121/197] Replace `std::map` with `dict` for `TechmapWires` type. --- passes/techmap/techmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 416d96862..3a68d3cb9 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -79,7 +79,7 @@ struct TechmapWorker RTLIL::SigSpec value; }; - typedef std::map> TechmapWires; + typedef dict> TechmapWires; bool extern_mode; bool assert_mode; From 5cb4ae46665574e721161d4eb38552f0938b9948 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 22:38:10 +0000 Subject: [PATCH 122/197] Replace `std::map` with `dict` for `connbits_map`, `cell_to_inbit`, and `outbit_to_cell`. --- passes/techmap/techmap.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 3a68d3cb9..96508845d 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -101,7 +101,7 @@ struct TechmapWorker std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) { std::string constmap_info; - std::map> connbits_map; + dict> connbits_map; for (auto conn : cell->connections()) for (int i = 0; i < GetSize(conn.second); i++) { @@ -490,8 +490,8 @@ struct TechmapWorker } TopoSort> cells; - std::map> cell_to_inbit; - std::map> outbit_to_cell; + dict> cell_to_inbit; + dict> outbit_to_cell; for (auto cell : module->selected_cells()) { From 6d64d768b07a027fff42515dbba4cdb6f060d17a Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 22:41:21 +0000 Subject: [PATCH 123/197] Replace `std::map` with `dict` for `port_new2old_map`, `port_connmap`, and `cellbits_to_tplbits`. --- passes/techmap/techmap.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 96508845d..b4df6142e 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -862,9 +862,9 @@ struct TechmapWorker techmap_do_cache[new_tpl] = true; tpl = new_tpl; - std::map port_new2old_map; - std::map port_connmap; - std::map cellbits_to_tplbits; + dict port_new2old_map; + dict port_connmap; + dict cellbits_to_tplbits; for (auto wire : tpl->wires().to_vector()) { From 7857782575bded685bdff55da942670343d54b20 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 22:44:38 +0000 Subject: [PATCH 124/197] Replace `std::map` with `dict` for `unique_bit_id`. --- passes/techmap/techmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index b4df6142e..a915f207d 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -740,7 +740,7 @@ struct TechmapWorker } int unique_bit_id_counter = 0; - std::map unique_bit_id; + dict unique_bit_id; unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++; unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++; unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++; From a4755c50c37636db1f39097e607592487d4eed29 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 19 Apr 2020 23:52:21 +0000 Subject: [PATCH 125/197] Clean up extraneous buffer. --- passes/techmap/techmap.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index a915f207d..6b0957ad7 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1423,14 +1423,11 @@ struct FlattenPass : public Pass { new_used_modules.insert(cell->type); } - std::set to_remove; - for (auto mod : design->modules()) + for (auto mod : design->modules().to_vector()) if (!used_modules[mod->name] && !mod->get_blackbox_attribute(worker.ignore_wb)) { log("Deleting now unused module %s.\n", log_id(mod)); - to_remove.insert(mod); + design->remove(mod); } - for (auto mod : to_remove) - design->remove(mod); } log_pop(); From dfcb936cd565411eb488152213945c7896a980db Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 20 Apr 2020 00:01:14 +0000 Subject: [PATCH 126/197] Clean up pseudo-private member usage and ensure range iteration uses references where possible to avoid unnecessary copies. --- passes/techmap/techmap.cc | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 6b0957ad7..548a80b01 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -103,7 +103,7 @@ struct TechmapWorker std::string constmap_info; dict> connbits_map; - for (auto conn : cell->connections()) + for (auto &conn : cell->connections()) for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); if (bit.wire == nullptr) { @@ -269,12 +269,12 @@ struct TechmapWorker pool tpl_written_bits; for (auto tpl_cell : tpl->cells()) - for (auto &it2 : tpl_cell->connections_) - if (tpl_cell->output(it2.first)) - for (auto bit : tpl_sigmap(it2.second)) + for (auto &conn : tpl_cell->connections()) + if (tpl_cell->output(conn.first)) + for (auto bit : tpl_sigmap(conn.second)) tpl_written_bits.insert(bit); - for (auto &it1 : tpl->connections_) - for (auto bit : tpl_sigmap(it1.first)) + for (auto &conn : tpl->connections()) + for (auto bit : tpl_sigmap(conn.first)) tpl_written_bits.insert(bit); SigMap port_signal_map; @@ -397,12 +397,12 @@ struct TechmapWorker vector autopurge_ports; - for (auto &it2 : c->connections_) + for (auto &conn : c->connections_) { bool autopurge = false; if (!autopurge_tpl_bits.empty()) { - autopurge = GetSize(it2.second) != 0; - for (auto &bit : sigmaps.at(tpl)(it2.second)) + autopurge = GetSize(conn.second) != 0; + for (auto &bit : sigmaps.at(tpl)(conn.second)) if (!autopurge_tpl_bits.count(bit)) { autopurge = false; break; @@ -410,10 +410,10 @@ struct TechmapWorker } if (autopurge) { - autopurge_ports.push_back(it2.first); + autopurge_ports.push_back(conn.first); } else { - apply_prefix(cell->name, it2.second, module); - port_signal_map.apply(it2.second); + apply_prefix(cell->name, conn.second, module); + port_signal_map.apply(conn.second); } } @@ -694,7 +694,7 @@ struct TechmapWorker break; } - for (auto conn : cell->connections()) { + for (auto &conn : cell->connections()) { if (conn.first.begins_with("$")) continue; if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0) @@ -712,7 +712,7 @@ struct TechmapWorker if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0) parameters[ID::_TECHMAP_CELLTYPE_] = RTLIL::unescape_id(cell->type); - for (auto conn : cell->connections()) { + for (auto &conn : cell->connections()) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) @@ -746,7 +746,7 @@ struct TechmapWorker unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++; unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++; - for (auto conn : cell->connections()) + for (auto &conn : cell->connections()) if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) { for (auto &bit : sigmap(conn.second)) if (unique_bit_id.count(bit) == 0) @@ -763,7 +763,7 @@ struct TechmapWorker if (tpl->avail_parameters.count(ID::_TECHMAP_BITS_CONNMAP_)) parameters[ID::_TECHMAP_BITS_CONNMAP_] = bits; - for (auto conn : cell->connections()) + for (auto &conn : cell->connections()) if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) { RTLIL::Const value; for (auto &bit : sigmap(conn.second)) { @@ -884,7 +884,7 @@ struct TechmapWorker } } - for (auto conn : cell->connections()) + for (auto &conn : cell->connections()) for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); From 62946218255eaea385fc62802c881bff256157fb Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 20 Apr 2020 04:42:19 +0000 Subject: [PATCH 127/197] Use `emplace()` rather than `insert()`. --- passes/techmap/techmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 548a80b01..17d98847e 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -213,7 +213,7 @@ struct TechmapWorker if (tpl_w->port_id > 0) { IdString posportname = stringf("$%d", tpl_w->port_id); - positional_ports[posportname] = tpl_w->name; + positional_ports.emplace(posportname, tpl_w->name); if (!flatten_mode && tpl_w->get_bool_attribute(ID::techmap_autopurge) && (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && From f235f212ea242d765e38f4b317390657c1291f77 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 20 Apr 2020 04:46:09 +0000 Subject: [PATCH 128/197] Replace `std::set` with `pool` for `cell_to_inbit` and `outbit_to_cell`. --- passes/techmap/techmap.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 17d98847e..ab719cbaa 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -490,8 +490,8 @@ struct TechmapWorker } TopoSort> cells; - dict> cell_to_inbit; - dict> outbit_to_cell; + dict> cell_to_inbit; + dict> outbit_to_cell; for (auto cell : module->selected_cells()) { From c658d9d59d98063fec463e17978a3e2f449f38de Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 20 Apr 2020 05:10:08 +0000 Subject: [PATCH 129/197] Build constant bits directly rather than constructing an object and copying its bits. --- passes/techmap/techmap.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index ab719cbaa..da53e8448 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -767,8 +767,11 @@ struct TechmapWorker if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))) != 0) { RTLIL::Const value; for (auto &bit : sigmap(conn.second)) { - RTLIL::Const chunk(unique_bit_id.at(bit), bits); - value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end()); + int val = unique_bit_id.at(bit); + for (int i = 0; i < bits; i++) { + value.bits.push_back((val & 1) != 0 ? State::S1 : State::S0); + val = val >> 1; + } } parameters[stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))] = value; } From 982562ff13b475ec96af6e12e0ad8fdec42f91b6 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 20 Apr 2020 05:59:00 +0000 Subject: [PATCH 130/197] Use `emplace()` for more efficient insertion into various `dict`s. --- passes/techmap/techmap.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index da53e8448..d137365c2 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -117,7 +117,7 @@ struct TechmapWorker constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); } else { - connbits_map[bit] = std::pair(conn.first, i); + connbits_map.emplace(bit, std::make_pair(conn.first, i)); constmap_info += stringf("|%s %d", log_id(conn.first), i); } } @@ -710,21 +710,21 @@ struct TechmapWorker } if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0) - parameters[ID::_TECHMAP_CELLTYPE_] = RTLIL::unescape_id(cell->type); + parameters.emplace(ID::_TECHMAP_CELLTYPE_, RTLIL::unescape_id(cell->type)); for (auto &conn : cell->connections()) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0); - parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))] = RTLIL::SigSpec(v).as_const(); + parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) if (bit.wire != nullptr) bit = RTLIL::SigBit(RTLIL::State::Sx); - parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))] = RTLIL::SigSpec(v).as_const(); + parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { auto sig = sigmap(conn.second); @@ -735,7 +735,7 @@ struct TechmapWorker value[i] = it->second; } } - parameters[stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))] = value; + parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), value); } } @@ -773,7 +773,7 @@ struct TechmapWorker val = val >> 1; } } - parameters[stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first))] = value; + parameters.emplace(stringf("\\_TECHMAP_CONNMAP_%s_", log_id(conn.first)), value); } } @@ -882,8 +882,8 @@ struct TechmapWorker wire->port_id = 0; for (int i = 0; i < wire->width; i++) { - port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i); - port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i); + port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(wire, i)); + port_connmap.emplace(RTLIL::SigBit(wire, i), RTLIL::SigBit(new_wire, i)); } } From bd54d67ad4a24992c4161f12b2c8e42df2a65569 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 20 Apr 2020 21:57:23 +0000 Subject: [PATCH 131/197] Further clean up `passes/techmap/techmap.cc`. Co-Authored-By: Eddie Hung --- passes/techmap/techmap.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index d137365c2..898aceccd 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -568,7 +568,7 @@ struct TechmapWorker { IdString derived_name = tpl_name; RTLIL::Module *tpl = map->module(tpl_name); - dict parameters(cell->parameters.begin(), cell->parameters.end()); + dict parameters(cell->parameters); if (tpl->get_blackbox_attribute(ignore_wb)) continue; @@ -782,16 +782,17 @@ struct TechmapWorker // do not register techmap_wrap modules with techmap_cache } else { std::pair> key(tpl_name, parameters); - if (techmap_cache.count(key) > 0) { - tpl = techmap_cache[key]; + auto it = techmap_cache.find(key); + if (it != techmap_cache.end()) { + tpl = it->second; } else { if (parameters.size() != 0) { mkdebug.on(); - derived_name = tpl->derive(map, dict(parameters.begin(), parameters.end())); + derived_name = tpl->derive(map, parameters); tpl = map->module(derived_name); log_continue = true; } - techmap_cache[key] = tpl; + techmap_cache.emplace(std::move(key), tpl); } } From dabeb1e8a136730536d17fd79e6c348d8cdca271 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Apr 2020 15:50:12 -0700 Subject: [PATCH 132/197] techmap: prefix special wires with backslash for use as IdString --- kernel/constids.inc | 1 + kernel/rtlil.h | 2 +- passes/techmap/techmap.cc | 23 ++++++++++++----------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/kernel/constids.inc b/kernel/constids.inc index aa75a9c09..5c8373513 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -169,6 +169,7 @@ X(techmap_autopurge) X(_TECHMAP_BITS_CONNMAP_) X(_TECHMAP_CELLTYPE_) X(techmap_celltype) +X(_TECHMAP_FAIL_) X(techmap_maccmap) X(_TECHMAP_REPLACE_) X(techmap_simplemap) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index dad8508c3..11c45bbec 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -150,7 +150,7 @@ namespace RTLIL if (!p[0]) return 0; - log_assert(p[0] == '$' || p[0] == '\\' || strncmp(p, "_TECHMAP_", strlen("_TECHMAP_")) == 0); + log_assert(p[0] == '$' || p[0] == '\\'); log_assert(p[1] != 0); auto it = global_id_index_.find((char*)p); diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 898aceccd..6513ab827 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -138,15 +138,16 @@ struct TechmapWorker continue; const char *q = strrchr(p+1, '.'); - p = q ? q+1 : p+1; + if (q) + p = q; - if (!strncmp(p, "_TECHMAP_", 9)) { + if (!strncmp(p, "\\_TECHMAP_", 10)) { TechmapWireData record; record.wire = w; record.value = w; result[p].push_back(record); - w->attributes[ID::keep] = RTLIL::Const(1); - w->attributes[ID::_techmap_special_] = RTLIL::Const(1); + w->set_bool_attribute(ID::keep); + w->set_bool_attribute(ID::_techmap_special_); } } @@ -819,7 +820,7 @@ struct TechmapWorker for (auto &it : twd) techmap_wire_names.insert(it.first); - for (auto &it : twd["_TECHMAP_FAIL_"]) { + for (auto &it : twd[ID::_TECHMAP_FAIL_]) { RTLIL::SigSpec value = it.value; if (value.is_fully_const() && value.as_bool()) { log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", @@ -833,7 +834,7 @@ struct TechmapWorker for (auto &it : twd) { - if (it.first.compare(0, 12, "_TECHMAP_DO_") != 0 || it.second.empty()) + if (!it.first.begins_with("\\_TECHMAP_DO_") || it.second.empty()) continue; auto &data = it.second.front(); @@ -941,8 +942,8 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (it.first != "_TECHMAP_FAIL_" && (it.first.substr(0, 20) != "_TECHMAP_REMOVEINIT_" || it.first[it.first.size()-1] != '_') && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") - log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); + if (it.first != ID::_TECHMAP_FAIL_ && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.begins_with("\\_TECHMAP_DO_") && !it.first.begins_with("\\_TECHMAP_DONE_")) + log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first)); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) @@ -974,10 +975,10 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_") { + if (it.first.begins_with("\\_TECHMAP_REMOVEINIT_")) { for (auto &it2 : it.second) { auto val = it2.value.as_const(); - auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1)); + auto wirename = RTLIL::escape_id(it.first.substr(21, it.first.size() - 21 - 1)); auto it = cell->connections().find(wirename); if (it != cell->connections().end()) { auto sig = sigmap(it->second); @@ -1289,7 +1290,7 @@ struct TechmapPass : public Pass { log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1); } for (auto mod : saved_designs.at(fn.substr(1))->modules()) - if (!map->has(mod->name)) + if (!map->module(mod->name)) map->add(mod->clone()); } else { std::ifstream f; From ce62d0751ac25211cd468ae7026805e6933e0ce6 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 20 Apr 2020 22:55:11 +0000 Subject: [PATCH 133/197] Replace `std::set`s using custom comparators with `pool`. Co-Authored-By: Eddie Hung --- passes/techmap/techmap.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 6513ab827..16bc9c803 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -65,7 +65,7 @@ struct TechmapWorker dict simplemap_mappers; dict>, RTLIL::Module*> techmap_cache; dict techmap_do_cache; - std::set> module_queue; + pool module_queue; dict sigmaps; pool flatten_do_list; @@ -465,7 +465,7 @@ struct TechmapWorker } bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, - const dict> &celltypeMap, bool in_recursion) + const dict> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -1305,7 +1305,7 @@ struct TechmapPass : public Pass { log_header(design, "Continuing TECHMAP pass.\n"); - dict> celltypeMap; + dict> celltypeMap; for (auto module : map->modules()) { if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) { char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str()); @@ -1386,7 +1386,7 @@ struct FlattenPass : public Pass { extra_args(args, argidx, design); - dict> celltypeMap; + dict> celltypeMap; for (auto module : design->modules()) celltypeMap[module->name].insert(module->name); From 36bb201dd9572f71c74d0987d8f42b19a6feaa9c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Apr 2020 20:56:38 -0700 Subject: [PATCH 134/197] techmap: sort celltypeMap as it determines techmap order --- passes/techmap/techmap.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 16bc9c803..8a8756757 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1313,11 +1313,13 @@ struct TechmapPass : public Pass { celltypeMap[RTLIL::escape_id(q)].insert(module->name); free(p); } else { - std::string module_name = module->name.begins_with("\\$") ? + IdString module_name = module->name.begins_with("\\$") ? module->name.substr(1) : module->name.str(); celltypeMap[module_name].insert(module->name); } } + for (auto &i : celltypeMap) + i.second.sort(RTLIL::sort_by_id_str()); for (auto module : design->modules()) worker.module_queue.insert(module); @@ -1389,6 +1391,8 @@ struct FlattenPass : public Pass { dict> celltypeMap; for (auto module : design->modules()) celltypeMap[module->name].insert(module->name); + for (auto &i : celltypeMap) + i.second.sort(RTLIL::sort_by_id_str()); RTLIL::Module *top_mod = nullptr; if (design->full_selection()) From 97fd304cbec4b760bb2ea454668c4957ddb99624 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 21 Apr 2020 07:51:29 +0000 Subject: [PATCH 135/197] techmap: Replace pseudo-private member usage with the range accessor function and some naughty `const_cast<>()`s. --- passes/techmap/techmap.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 8a8756757..0b88e5910 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -398,7 +398,7 @@ struct TechmapWorker vector autopurge_ports; - for (auto &conn : c->connections_) + for (auto &conn : c->connections()) { bool autopurge = false; if (!autopurge_tpl_bits.empty()) { @@ -413,8 +413,8 @@ struct TechmapWorker if (autopurge) { autopurge_ports.push_back(conn.first); } else { - apply_prefix(cell->name, conn.second, module); - port_signal_map.apply(conn.second); + apply_prefix(cell->name, const_cast(conn.second), module); + port_signal_map.apply(const_cast(conn.second)); } } From e17329164904f05efa48be63fbb73ec8afdda8e4 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 21 Apr 2020 17:47:00 +0000 Subject: [PATCH 136/197] techmap: Replace naughty `const_cast<>()`s. Co-Authored-By: Eddie Hung --- passes/techmap/techmap.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 0b88e5910..6ac1d1113 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -413,8 +413,10 @@ struct TechmapWorker if (autopurge) { autopurge_ports.push_back(conn.first); } else { - apply_prefix(cell->name, const_cast(conn.second), module); - port_signal_map.apply(const_cast(conn.second)); + RTLIL::SigSpec new_conn = conn.second; + apply_prefix(cell->name, new_conn, module); + port_signal_map.apply(new_conn); + c->setPort(conn.first, std::move(new_conn)); } } From 35b94d1f664928dcf8476a9a6f35e2bb7f647ee1 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Wed, 22 Apr 2020 22:04:22 +0000 Subject: [PATCH 137/197] kernel: Re-implement `dict` hash code as a `dict` member function instead of a specialized template for `hash_ops`. --- kernel/hashlib.h | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index cdbad87c4..18114b6ad 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -19,12 +19,6 @@ namespace hashlib { -template struct hash_ops; -template> class dict; -template> class idict; -template> class pool; -template> class mfp; - const int hashtable_size_trigger = 2; const int hashtable_size_factor = 3; @@ -106,20 +100,6 @@ template struct hash_ops> { } }; -template struct hash_ops> { - static inline bool cmp(dict a, dict b) { - return a == b; - } - static inline unsigned int hash(dict a) { - unsigned int h = mkhash_init; - for (auto &it : a) { - h = mkhash(h, hash_ops

::hash(it.first)); - h = mkhash(h, hash_ops::hash(it.second)); - } - return h; - } -}; - template struct hash_ops> { static inline bool cmp(std::tuple a, std::tuple b) { return a == b; @@ -211,6 +191,11 @@ inline int hashtable_size(int min_size) throw std::length_error("hash table exceeded maximum size."); } +template> class dict; +template> class idict; +template> class pool; +template> class mfp; + template class dict { @@ -630,6 +615,15 @@ public: return !operator==(other); } + unsigned int hash() const { + unsigned int h = mkhash_init; + for (auto &it : entries) { + h = mkhash(h, hash_ops::hash(it.udata.first)); + h = mkhash(h, hash_ops::hash(it.udata.second)); + } + return h; + } + void reserve(size_t n) { entries.reserve(n); } size_t size() const { return entries.size(); } bool empty() const { return entries.empty(); } From 976edb7597692ac04111b3c51b13e18105c14f42 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 24 Apr 2020 08:37:16 +0000 Subject: [PATCH 138/197] kernel: Ensure `dict` always hashes to the same value given the same contents. --- kernel/hashlib.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 18114b6ad..1284f3f8d 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -207,6 +207,7 @@ class dict entry_t() { } entry_t(const std::pair &udata, int next) : udata(udata), next(next) { } entry_t(std::pair &&udata, int next) : udata(std::move(udata)), next(next) { } + bool operator<(const entry_t &other) const { return udata.first < other.udata.first; } }; std::vector hashtable; @@ -616,10 +617,12 @@ public: } unsigned int hash() const { + std::vector entries_(entries); //make a copy to preserve const-ness + std::sort(entries_.begin(), entries_.end()); unsigned int h = mkhash_init; - for (auto &it : entries) { - h = mkhash(h, hash_ops::hash(it.udata.first)); - h = mkhash(h, hash_ops::hash(it.udata.second)); + for (unsigned int i = 0; i < entries_.size(); ++i) { + h = mkhash(h, hash_ops::hash(entries_[i].udata.first)); + h = mkhash(h, hash_ops::hash(entries_[i].udata.second)); } return h; } From e7fd8912f041462bf044b6c93aa4b4db786d01c7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 16:09:41 -0700 Subject: [PATCH 139/197] tests: attributes before task enable --- tests/verilog/task_attr.ys | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/verilog/task_attr.ys diff --git a/tests/verilog/task_attr.ys b/tests/verilog/task_attr.ys new file mode 100644 index 000000000..d6e75f85f --- /dev/null +++ b/tests/verilog/task_attr.ys @@ -0,0 +1,28 @@ +read_verilog < Date: Thu, 14 May 2020 16:10:11 -0700 Subject: [PATCH 140/197] verilog: attributes before task enable (but 13 s/r conflicts) --- frontends/verilog/verilog_parser.y | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index db9a130cf..fd4ff68a9 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2217,23 +2217,23 @@ behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | non_opt_delay behavioral_stmt | simple_behavioral_stmt ';' | ';' | - hierarchical_id attr { + attr hierarchical_id { AstNode *node = new AstNode(AST_TCALL); - node->str = *$1; - delete $1; + node->str = *$2; + delete $2; ast_stack.back()->children.push_back(node); ast_stack.push_back(node); - append_attr(node, $2); + append_attr(node, $1); } opt_arg_list ';'{ ast_stack.pop_back(); } | - TOK_MSG_TASKS attr { + attr TOK_MSG_TASKS { AstNode *node = new AstNode(AST_TCALL); - node->str = *$1; - delete $1; + node->str = *$2; + delete $2; ast_stack.back()->children.push_back(node); ast_stack.push_back(node); - append_attr(node, $2); + append_attr(node, $1); } opt_arg_list ';'{ ast_stack.pop_back(); } | @@ -2330,8 +2330,6 @@ behavioral_stmt: ast_stack.pop_back(); }; - ; - unique_case_attr: /* empty */ { $$ = false; From 67fc0c3698693f049e805211c49d6219f17d7c7d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 May 2020 16:44:35 -0700 Subject: [PATCH 141/197] abc9: use (* abc9_keep *) instead of (* abc9_scc *); apply to $_DFF_?_ instead of moving them to $__ prefix --- backends/aiger/xaiger.cc | 10 +++++----- kernel/constids.inc | 2 +- passes/techmap/abc9_ops.cc | 6 +++--- techlibs/common/abc9_map.v | 4 ++-- techlibs/common/abc9_unmap.v | 12 ------------ 5 files changed, 11 insertions(+), 23 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 3aa0e1110..69797ceaf 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -177,12 +177,12 @@ struct XAigerWriter undriven_bits.insert(bit); unused_bits.insert(bit); - bool scc = wire->attributes.count(ID::abc9_scc); - if (wire->port_input || scc) + bool keep = wire->get_bool_attribute(ID::abc9_keep); + if (wire->port_input || keep) input_bits.insert(bit); - bool keep = wire->get_bool_attribute(ID::keep); - if (wire->port_output || keep || scc) { + keep = keep || wire->get_bool_attribute(ID::keep); + if (wire->port_output || keep) { if (bit != wirebit) alias_map[wirebit] = bit; output_bits.insert(wirebit); @@ -225,7 +225,7 @@ struct XAigerWriter continue; } - if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) { SigBit D = sigmap(cell->getPort(ID::D).as_bit()); SigBit Q = sigmap(cell->getPort(ID::Q).as_bit()); diff --git a/kernel/constids.inc b/kernel/constids.inc index 25996d2d8..345bfaee8 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -5,9 +5,9 @@ X(abc9_box_seq) X(abc9_bypass) X(abc9_carry) X(abc9_flop) +X(abc9_keep) X(abc9_lut) X(abc9_mergeability) -X(abc9_scc) X(abc9_scc_id) X(abcgroup) X(ABITS) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 6a8dbde8b..10c980f73 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -563,7 +563,7 @@ void mark_scc(RTLIL::Module *module) if (c.second.is_fully_const()) continue; if (cell->output(c.first)) { Wire *w = module->addWire(NEW_ID, GetSize(c.second)); - w->set_bool_attribute(ID::abc9_scc); + w->set_bool_attribute(ID::abc9_keep); module->connect(w, c.second); c.second = w; } @@ -1154,7 +1154,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // Short out $_DFF_[NP]_ cells since the flop box already has // all the information we need to reconstruct cell - if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { + if (dff_mode && cell->type.in(ID($_DFF_N_), ID($_DFF_P_)) && !cell->get_bool_attribute(ID::abc9_keep)) { module->connect(cell->getPort(ID::Q), cell->getPort(ID::D)); module->remove(cell); } @@ -1373,7 +1373,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) RTLIL::Wire *mapped_wire = mapped_mod->wire(port); RTLIL::Wire *wire = module->wire(port); log_assert(wire); - wire->attributes.erase(ID::abc9_scc); + wire->attributes.erase(ID::abc9_keep); RTLIL::Wire *remap_wire = module->wire(remap_name(port)); RTLIL::SigSpec signal(wire, remap_wire->start_offset-wire->start_offset, GetSize(remap_wire)); diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v index bb2b4a4b1..6ed90b5f5 100644 --- a/techlibs/common/abc9_map.v +++ b/techlibs/common/abc9_map.v @@ -10,7 +10,7 @@ module $_DFF_x_(input C, D, output Q); $_DFF_N_ ff (.C(C), .D(D_), .Q(Q)); end else - $__DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); // hide from abc9 using $__ prefix + (* abc9_keep *) $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); end else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin @@ -18,7 +18,7 @@ module $_DFF_x_(input C, D, output Q); $_DFF_P_ ff (.C(C), .D(D_), .Q(Q)); end else - $__DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); // hide from abc9 using $__ prefix + (* abc9_keep *) $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); end else if (_TECHMAP_CELLTYPE_ != "") $error("Unrecognised _TECHMAP_CELLTYPE_"); diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v index b765356d8..bcbe91477 100644 --- a/techlibs/common/abc9_unmap.v +++ b/techlibs/common/abc9_unmap.v @@ -9,15 +9,3 @@ module $__DFF_x__$abc9_flop (input C, D, Q, output n1); $error("Unrecognised _TECHMAP_CELLTYPE_"); endgenerate endmodule - -(* techmap_celltype = "$__DFF_N_ $__DFF_P_" *) -module $__DFF_x_ (input C, D, output Q); - parameter _TECHMAP_CELLTYPE_ = ""; - generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N_") - $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); - else if (_TECHMAP_CELLTYPE_ == "$__DFF_P_") - $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); - else if (_TECHMAP_CELLTYPE_ != "") - $error("Unrecognised _TECHMAP_CELLTYPE_"); - endgenerate -endmodule From 8297afe92588c881fbf0590a64c81af08e6f20f6 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Thu, 14 May 2020 22:52:07 +0000 Subject: [PATCH 142/197] log: Use `dict` instead of `std::vector` for `log_expect_{error, warning, log}` to better express the intent that each element is unique. --- kernel/log.cc | 20 ++++++++++---------- kernel/log.h | 13 +++++-------- passes/cmds/logger.cc | 39 ++++++--------------------------------- 3 files changed, 21 insertions(+), 51 deletions(-) diff --git a/kernel/log.cc b/kernel/log.cc index a21ba480a..104bee078 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -42,7 +42,7 @@ std::vector log_files; std::vector log_streams; std::map> log_hdump; std::vector log_warn_regexes, log_nowarn_regexes, log_werror_regexes; -std::vector> log_expect_log, log_expect_warning, log_expect_error; +dict log_expect_log, log_expect_warning, log_expect_error; std::set log_warnings, log_experimentals, log_experimentals_ignored; int log_warnings_count = 0; int log_warnings_count_noexpect = 0; @@ -181,7 +181,7 @@ void logv(const char *format, va_list ap) log_warning("Found log message matching -W regex:\n%s", str.c_str()); for (auto &item : log_expect_log) - if (YS_REGEX_NS::regex_search(linebuffer, item.first)) + if (YS_REGEX_NS::regex_search(linebuffer, item.second.pattern)) item.second.current_count++; linebuffer.clear(); @@ -256,7 +256,7 @@ static void logv_warning_with_prefix(const char *prefix, bool warning_match = false; for (auto &item : log_expect_warning) - if (YS_REGEX_NS::regex_search(message, item.first)) { + if (YS_REGEX_NS::regex_search(message, item.second.pattern)) { item.second.current_count++; warning_match = true; } @@ -349,7 +349,7 @@ static void logv_error_with_prefix(const char *prefix, log_error_atexit(); for (auto &item : log_expect_error) - if (YS_REGEX_NS::regex_search(log_last_error, item.first)) + if (YS_REGEX_NS::regex_search(log_last_error, item.second.pattern)) item.second.current_count++; if (check_expected_logs) @@ -672,31 +672,31 @@ void log_check_expected() for (auto &item : log_expect_warning) { if (item.second.current_count == 0) { log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected warning pattern '%s' not found !\n", item.first.c_str()); } if (item.second.current_count != item.second.expected_count) { log_warn_regexes.clear(); log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + item.first.c_str(), item.second.current_count, item.second.expected_count); } } for (auto &item : log_expect_log) { if (item.second.current_count == 0) { log_warn_regexes.clear(); - log_error("Expected log pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected log pattern '%s' not found !\n", item.first.c_str()); } if (item.second.current_count != item.second.expected_count) { log_warn_regexes.clear(); log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n", - item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); + item.first.c_str(), item.second.current_count, item.second.expected_count); } } for (auto &item : log_expect_error) if (item.second.current_count == item.second.expected_count) { log_warn_regexes.clear(); - log("Expected error pattern '%s' found !!!\n", item.second.pattern.c_str()); + log("Expected error pattern '%s' found !!!\n", item.first.c_str()); #ifdef EMSCRIPTEN throw 0; #elif defined(_MSC_VER) @@ -707,7 +707,7 @@ void log_check_expected() } else { display_error_log_msg = false; log_warn_regexes.clear(); - log_error("Expected error pattern '%s' not found !\n", item.second.pattern.c_str()); + log_error("Expected error pattern '%s' not found !\n", item.first.c_str()); } } diff --git a/kernel/log.h b/kernel/log.h index dee5d44d7..54bfcb911 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -202,19 +202,16 @@ void log_flush(); struct LogExpectedItem { - LogExpectedItem(std::string pattern, int expected) : - expected_count(expected), - current_count(0), - pattern(pattern) - { - } + LogExpectedItem(const YS_REGEX_TYPE &pat, int expected) : + pattern(pat), expected_count(expected), current_count(0) {} + LogExpectedItem() : expected_count(0), current_count(0) {} + YS_REGEX_TYPE pattern; int expected_count; int current_count; - std::string pattern; }; -extern std::vector> log_expect_log, log_expect_warning, log_expect_error; +extern dict log_expect_log, log_expect_warning, log_expect_error; void log_check_expected(); const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); diff --git a/passes/cmds/logger.cc b/passes/cmds/logger.cc index 50b89d92f..c9532eced 100644 --- a/passes/cmds/logger.cc +++ b/passes/cmds/logger.cc @@ -159,39 +159,12 @@ struct LoggerPass : public Pass { log_cmd_error("Expected error message occurrences must be 1 !\n"); log("Added regex '%s' for warnings to expected %s list.\n", pattern.c_str(), type.c_str()); try { - if (type=="error") { - auto it = log_expect_error.begin(); - auto ie = log_expect_error.end(); - for (; it != ie; it++) - if (it->second.pattern == pattern) { - it->second.expected_count = count; - break; - } - if (it == ie) - log_expect_error.emplace_back(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)); - } - else if (type=="warning") { - auto it = log_expect_warning.begin(); - auto ie = log_expect_warning.end(); - for (; it != ie; it++) - if (it->second.pattern == pattern) { - it->second.expected_count = count; - break; - } - if (it == ie) - log_expect_warning.emplace_back(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)); - } - else if (type=="log") { - auto it = log_expect_log.begin(); - auto ie = log_expect_log.end(); - for (; it != ie; it++) - if (it->second.pattern == pattern) { - it->second.expected_count = count; - break; - } - if (it == ie) - log_expect_log.emplace_back(YS_REGEX_COMPILE(pattern), LogExpectedItem(pattern, count)); - } + if (type == "error") + log_expect_error[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "warning") + log_expect_warning[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); + else if (type == "log") + log_expect_log[pattern] = LogExpectedItem(YS_REGEX_COMPILE(pattern), count); else log_abort(); } catch (const YS_REGEX_NS::regex_error& e) { From fa8cb3e35da68ceb55a9147bc1faacf68ad8bbfa Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Sun, 17 May 2020 11:31:11 +0200 Subject: [PATCH 143/197] Revert "Add support for non-power-of-two mem chunks in verific importer" This reverts commit 173aa27ca5ef6e7c0a9277e8da7765adcd63bfe9. --- frontends/verific/verific.cc | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 5f8a78e48..fe4bda68e 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1265,7 +1265,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->OutputSize()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->OutputSize())) + if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0) log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); for (int i = 0; i < numchunks; i++) @@ -1273,11 +1273,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec data = operatorOutput(inst).extract(i * memory->width, memory->width); - if ((numchunks & (numchunks - 1)) != 0) { - addr = module->Mul(NEW_ID, operatorInput1(inst), RTLIL::Const(numchunks)); - addr = module->Add(NEW_ID, addr, RTLIL::Const(i)); - } - RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), ID($memrd)); cell->parameters[ID::MEMID] = memory->name.str(); @@ -1300,7 +1295,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->Input2Size()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->Input2Size())) + if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0) log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name()); for (int i = 0; i < numchunks; i++) @@ -1308,11 +1303,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width); - if ((numchunks & (numchunks - 1)) != 0) { - addr = module->Mul(NEW_ID, operatorInput1(inst), RTLIL::Const(numchunks)); - addr = module->Add(NEW_ID, addr, RTLIL::Const(i)); - } - RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), ID($memwr)); cell->parameters[ID::MEMID] = memory->name.str(); From 049e4caceba2e90a43814152ecaeb340def7dde5 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sun, 17 May 2020 08:44:31 +0000 Subject: [PATCH 144/197] firrtl: Accept techmapped cell types in FIRRTL backend. --- backends/firrtl/firrtl.cc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index f6dae1d8c..89df0366f 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -446,7 +446,7 @@ struct FirrtlWorker string y_id = make_id(cell->name); std::string cellFileinfo = getFileinfo(cell); - if (cell->type.in(ID($not), ID($logic_not), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor))) + if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor))) { string a_expr = make_expr(cell->getPort(ID::A)); wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str())); @@ -462,7 +462,7 @@ struct FirrtlWorker // Assume the FIRRTL width is a single bit. firrtl_width = 1; - if (cell->type == ID($not)) primop = "not"; + if (cell->type.in(ID($not), ID($_NOT_))) primop = "not"; else if (cell->type == ID($neg)) { primop = "neg"; firrtl_is_signed = true; // Result of "neg" is signed (an SInt). @@ -494,7 +494,7 @@ struct FirrtlWorker continue; } - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or), ID($eq), ID($eqx), + if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_), ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl), ID($logic_and), ID($logic_or), ID($pow))) { @@ -524,7 +524,7 @@ struct FirrtlWorker // For the arithmetic ops, expand operand widths to result widths befor performing the operation. // This corresponds (according to iverilog) to what verilog compilers implement. - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or))) + if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_))) { if (a_width < y_width) { a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); @@ -560,17 +560,17 @@ struct FirrtlWorker } else if (cell->type == ID($mod)) { primop = "rem"; firrtl_width = min(a_width, b_width); - } else if (cell->type == ID($and)) { + } else if (cell->type.in(ID($and), ID($_AND_))) { primop = "and"; always_uint = true; firrtl_width = max(a_width, b_width); } - else if (cell->type == ID($or) ) { + else if (cell->type.in(ID($or), ID($_OR_))) { primop = "or"; always_uint = true; firrtl_width = max(a_width, b_width); } - else if (cell->type == ID($xor)) { + else if (cell->type.in(ID($xor), ID($_XOR_))) { primop = "xor"; always_uint = true; firrtl_width = max(a_width, b_width); @@ -694,7 +694,8 @@ struct FirrtlWorker } } - if (!cell->parameters.at(ID::B_SIGNED).as_bool()) { + auto it = cell->parameters.find(ID::B_SIGNED); + if (it == cell->parameters.end() || !it->second.as_bool()) { b_expr = "asUInt(" + b_expr + ")"; } @@ -723,9 +724,10 @@ struct FirrtlWorker continue; } - if (cell->type.in(ID($mux))) + if (cell->type.in(ID($mux), ID($_MUX_))) { - int width = cell->parameters.at(ID::WIDTH).as_int(); + auto it = cell->parameters.find(ID::WIDTH); + int width = it == cell->parameters.end()? 1 : it->second.as_int(); string a_expr = make_expr(cell->getPort(ID::A)); string b_expr = make_expr(cell->getPort(ID::B)); string s_expr = make_expr(cell->getPort(ID::S)); From aee439360bba642dcbffe5b803aa9a994b11d183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 18 May 2020 18:15:03 +0200 Subject: [PATCH 145/197] Add force_downto and force_upto wire attributes. Fixes #2058. --- frontends/ast/genrtlil.cc | 2 +- frontends/ast/simplify.cc | 19 +++++ kernel/constids.inc | 2 + techlibs/achronix/speedster22i/cells_arith.v | 6 ++ techlibs/achronix/speedster22i/cells_map.v | 1 + techlibs/anlogic/arith_map.v | 9 +++ techlibs/anlogic/cells_map.v | 1 + techlibs/common/adff2dff.v | 3 + techlibs/common/cmp2lcu.v | 12 ++++ techlibs/common/cmp2lut.v | 3 + techlibs/common/dff2ff.v | 2 + techlibs/common/mul2dsp.v | 18 +++++ techlibs/common/techmap.v | 73 ++++++++++++++------ techlibs/coolrunner2/cells_counter_map.v | 1 + techlibs/ecp5/arith_map.v | 10 +++ techlibs/ecp5/cells_map.v | 1 + techlibs/efinix/arith_map.v | 11 ++- techlibs/efinix/cells_map.v | 1 + techlibs/gowin/arith_map.v | 8 +++ techlibs/gowin/cells_map.v | 1 + techlibs/greenpak4/cells_map.v | 2 + techlibs/ice40/arith_map.v | 8 +++ techlibs/ice40/cells_map.v | 1 + techlibs/intel/arria10gx/cells_arith.v | 6 ++ techlibs/intel/arria10gx/cells_map.v | 1 + techlibs/intel/cyclone10lp/cells_arith.v | 6 ++ techlibs/intel/cyclone10lp/cells_map.v | 1 + techlibs/intel/cycloneiv/cells_arith.v | 6 ++ techlibs/intel/cycloneiv/cells_map.v | 1 + techlibs/intel/cycloneive/arith_map.v | 6 ++ techlibs/intel/cycloneive/cells_map.v | 1 + techlibs/intel/cyclonev/cells_arith.v | 6 ++ techlibs/intel/cyclonev/cells_map.v | 1 + techlibs/intel/max10/cells_arith.v | 6 ++ techlibs/intel/max10/cells_map.v | 1 + techlibs/intel_alm/common/alm_map.v | 1 + techlibs/intel_alm/common/arith_alm_map.v | 7 ++ techlibs/sf2/cells_map.v | 1 + techlibs/xilinx/arith_map.v | 23 ++++++ techlibs/xilinx/cells_map.v | 6 ++ techlibs/xilinx/lut_map.v | 1 + techlibs/xilinx/mux_map.v | 3 + tests/arch/xilinx/mux.ys | 6 +- 43 files changed, 258 insertions(+), 27 deletions(-) diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d4e9baa5f..cdc3adc9c 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1055,7 +1055,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (!range_valid) log_file_error(filename, location.first_line, "Signal `%s' with non-constant width!\n", str.c_str()); - if (!(range_left >= range_right || (range_left == -1 && range_right == 0))) + if (!(range_left + 1 >= range_right)) log_file_error(filename, location.first_line, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1); RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index f629df387..3314819fb 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1098,6 +1098,25 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = children[0]->range_swapped; range_left = children[0]->range_left; range_right = children[0]->range_right; + bool force_upto = false, force_downto = false; + if (attributes.count(ID::force_upto)) { + AstNode *val = attributes[ID::force_upto]; + if (val->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Attribute `force_upto' with non-constant value!\n"); + force_upto = val->asAttrConst().as_bool(); + } + if (attributes.count(ID::force_downto)) { + AstNode *val = attributes[ID::force_downto]; + if (val->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Attribute `force_downto' with non-constant value!\n"); + force_downto = val->asAttrConst().as_bool(); + } + if (force_upto && force_downto) + log_file_error(filename, location.first_line, "Attributes `force_downto' and `force_upto' cannot be both set!\n"); + if ((force_upto && !range_swapped) || (force_downto && range_swapped)) { + std::swap(range_left, range_right); + range_swapped = force_upto; + } } } else { if (!range_valid) diff --git a/kernel/constids.inc b/kernel/constids.inc index 345bfaee8..93c3a7609 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -79,6 +79,8 @@ X(equiv_merged) X(equiv_region) X(extract_order) X(F) +X(force_downto) +X(force_upto) X(fsm_encoding) X(fsm_export) X(FULL) diff --git a/techlibs/achronix/speedster22i/cells_arith.v b/techlibs/achronix/speedster22i/cells_arith.v index e2194cbd7..8529706a7 100644 --- a/techlibs/achronix/speedster22i/cells_arith.v +++ b/techlibs/achronix/speedster22i/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO); 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; @@ -36,11 +39,14 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v index 9f647cbef..a19e53f49 100644 --- a/techlibs/achronix/speedster22i/cells_map.v +++ b/techlibs/achronix/speedster22i/cells_map.v @@ -38,6 +38,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v index 1186543da..23e190bcb 100644 --- a/techlibs/anlogic/arith_map.v +++ b/techlibs/anlogic/arith_map.v @@ -26,24 +26,33 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); 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 CIx; + (* force_downto *) wire [Y_WIDTH-1:0] COx; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + (* 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = { COx, CIx }; wire dummy; diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v index 8ac087d9d..0bcea9856 100644 --- a/techlibs/anlogic/cells_map.v +++ b/techlibs/anlogic/cells_map.v @@ -32,6 +32,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/common/adff2dff.v b/techlibs/common/adff2dff.v index 86744d415..eca0110eb 100644 --- a/techlibs/common/adff2dff.v +++ b/techlibs/common/adff2dff.v @@ -6,8 +6,11 @@ module adff2dff (CLK, ARST, D, Q); parameter ARST_VALUE = 0; input CLK, ARST; + (* force_downto *) input [WIDTH-1:0] D; + (* force_downto *) output reg [WIDTH-1:0] Q; + (* force_downto *) wire reg [WIDTH-1:0] NEXT_Q; wire [1023:0] _TECHMAP_DO_ = "proc;;"; diff --git a/techlibs/common/cmp2lcu.v b/techlibs/common/cmp2lcu.v index e42f346d1..a221727e7 100644 --- a/techlibs/common/cmp2lcu.v +++ b/techlibs/common/cmp2lcu.v @@ -12,8 +12,11 @@ parameter A_WIDTH = 0; parameter B_WIDTH = 0; parameter Y_WIDTH = 0; +(* force_downto *) input [A_WIDTH-1:0] A; +(* force_downto *) input [B_WIDTH-1:0] B; +(* force_downto *) output [Y_WIDTH-1:0] Y; parameter _TECHMAP_CELLTYPE_ = ""; @@ -32,7 +35,9 @@ generate else begin // Perform sign extension on A and B localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; + (* force_downto *) wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A}; + (* force_downto *) wire [WIDTH-1:0] BB = {{(WIDTH-B_WIDTH){B_SIGNED ? B[B_WIDTH-1] : 1'b0}}, B}; // For $ge operation, start with the assumption that A and B are // equal (propagating this equality if A and B turn out to be so) @@ -54,9 +59,13 @@ parameter LCU_WIDTH = 1; parameter BUDGET = 0; parameter CI = 0; +(* force_downto *) input [AB_WIDTH-1:0] A; // A from original $gt/$ge +(* force_downto *) input [AB_WIDTH-1:0] B; // B from original $gt/$ge +(* force_downto *) input [LCU_WIDTH-1:0] P; // P of $lcu +(* force_downto *) input [LCU_WIDTH-1:0] G; // G of $lcu output Y; @@ -66,6 +75,7 @@ parameter [LCU_WIDTH-1:0] _TECHMAP_CONSTMSK_P_ = 0; generate if (AB_WIDTH == 0) begin + (* force_downto *) wire [LCU_WIDTH-1:0] CO; $lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO)); assign Y = CO[LCU_WIDTH-1]; @@ -104,8 +114,10 @@ generate else begin // Propagate only if all pairs are equal // (inconclusive evidence to say A >= B) + (* force_downto *) wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP}; // Generate if any comparisons call for it + (* force_downto *) wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG}; end if (AB_WIDTH == 1) diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v index 8ecd356cc..ec8f98e8d 100644 --- a/techlibs/common/cmp2lut.v +++ b/techlibs/common/cmp2lut.v @@ -16,8 +16,11 @@ parameter A_WIDTH = 0; parameter B_WIDTH = 0; parameter Y_WIDTH = 0; +(* force_downto *) input [A_WIDTH-1:0] A; +(* force_downto *) input [B_WIDTH-1:0] B; +(* force_downto *) output [Y_WIDTH-1:0] Y; parameter _TECHMAP_CELLTYPE_ = ""; diff --git a/techlibs/common/dff2ff.v b/techlibs/common/dff2ff.v index 2dc4d20d3..33a79ffff 100644 --- a/techlibs/common/dff2ff.v +++ b/techlibs/common/dff2ff.v @@ -4,7 +4,9 @@ module dff2ff (CLK, D, Q); parameter CLK_POLARITY = 1; input CLK; + (* force_downto *) input [WIDTH-1:0] D; + (* force_downto *) output reg [WIDTH-1:0] Q; wire [1023:0] _TECHMAP_DO_ = "proc;;"; diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v index 4cabb4453..bec47d01f 100644 --- a/techlibs/common/mul2dsp.v +++ b/techlibs/common/mul2dsp.v @@ -57,8 +57,11 @@ module _80_mul (A, B, Y); 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] Y; parameter _TECHMAP_CELLTYPE_ = ""; @@ -119,13 +122,19 @@ module _80_mul (A, B, Y); localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom); localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH; if (A_SIGNED && B_SIGNED) begin + (* force_downto *) wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) wire signed [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) wire signed [Y_WIDTH-1:0] partial_sum [n:0]; end else begin + (* force_downto *) wire [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) wire [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) wire [Y_WIDTH-1:0] partial_sum [n:0]; end @@ -170,13 +179,19 @@ module _80_mul (A, B, Y); localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom); localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH; if (A_SIGNED && B_SIGNED) begin + (* force_downto *) wire signed [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) wire signed [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) wire signed [Y_WIDTH-1:0] partial_sum [n:0]; end else begin + (* force_downto *) wire [partial_Y_WIDTH-1:0] partial [n-1:0]; + (* force_downto *) wire [last_Y_WIDTH-1:0] last_partial; + (* force_downto *) wire [Y_WIDTH-1:0] partial_sum [n:0]; end @@ -249,8 +264,11 @@ module _90_soft_mul (A, B, Y); 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] Y; // Indirection necessary since mapping diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 225cff449..c1efc378b 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -85,8 +85,11 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y); localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl"; localparam sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr"; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y; localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH); @@ -96,6 +99,7 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y); wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; + (* force_downto *) reg [WIDTH-1:0] buffer; reg overflow; @@ -125,8 +129,11 @@ module _90_shift_shiftx (A, B, Y); 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] Y; parameter _TECHMAP_CELLTYPE_ = ""; @@ -173,6 +180,7 @@ module _90_shift_shiftx (A, B, Y); wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; + (* force_downto *) reg [WIDTH-1:0] buffer; reg overflow; @@ -216,9 +224,12 @@ endmodule module _90_fa (A, B, C, X, Y); parameter WIDTH = 1; + (* force_downto *) input [WIDTH-1:0] A, B, C; + (* force_downto *) output [WIDTH-1:0] X, Y; + (* force_downto *) wire [WIDTH-1:0] t1, t2, t3; assign t1 = A ^ B, t2 = A & B, t3 = C & t1; @@ -229,12 +240,15 @@ endmodule module _90_lcu (P, G, CI, CO); parameter WIDTH = 2; + (* force_downto *) input [WIDTH-1:0] P, G; input CI; + (* force_downto *) output [WIDTH-1:0] CO; integer i, j; + (* force_downto *) reg [WIDTH-1:0] p, g; wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast"; @@ -278,38 +292,26 @@ module _90_alu (A, B, CI, BI, X, Y, CO); 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 [Y_WIDTH-1:0] AA, BB; + (* force_downto *) + wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; - if (A_WIDTH == 0) begin - wire [Y_WIDTH-1:0] B_buf; - \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - - assign AA = {Y_WIDTH{1'b0}}; - assign BB = BI ? ~B_buf : B_buf; - end - else if (B_WIDTH == 0) begin - wire [Y_WIDTH-1:0] A_buf; - \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); - - assign AA = A_buf; - assign BB = {Y_WIDTH{BI ? 1'b0 : 1'b1}}; - end - else begin - 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)); - - assign AA = A_buf; - assign BB = BI ? ~B_buf : B_buf; - end + (* 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)); \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO)); @@ -335,15 +337,19 @@ endmodule module \$__div_mod_u (A, B, Y, R); parameter WIDTH = 1; + (* force_downto *) input [WIDTH-1:0] A, B; + (* force_downto *) output [WIDTH-1:0] Y, R; + (* force_downto *) wire [WIDTH*WIDTH-1:0] chaindata; assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)]; genvar i; generate begin for (i = 0; i < WIDTH; i=i+1) begin:stage + (* force_downto *) wire [WIDTH-1:0] stage_in; if (i == 0) begin:cp @@ -369,14 +375,19 @@ module \$__div_mod (A, B, Y, R); A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; + (* force_downto *) input [A_WIDTH-1:0] A; + (* force_downto *) input [B_WIDTH-1:0] B; + (* force_downto *) output [Y_WIDTH-1:0] Y, R; + (* force_downto *) wire [WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + (* force_downto *) wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u; assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf; assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf; @@ -402,8 +413,11 @@ module _90_div (A, B, Y); 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] Y; \$__div_mod #( @@ -427,8 +441,11 @@ module _90_mod (A, B, Y); 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] Y; \$__div_mod #( @@ -457,8 +474,11 @@ module _90_pow (A, B, Y); 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] Y; wire _TECHMAP_FAIL_ = 1; @@ -474,20 +494,27 @@ module _90_pmux (A, B, S, Y); parameter WIDTH = 1; parameter S_WIDTH = 1; + (* force_downto *) input [WIDTH-1:0] A; + (* force_downto *) input [WIDTH*S_WIDTH-1:0] B; + (* force_downto *) input [S_WIDTH-1:0] S; + (* force_downto *) output [WIDTH-1:0] Y; + (* force_downto *) wire [WIDTH-1:0] Y_B; genvar i, j; generate + (* force_downto *) wire [WIDTH*S_WIDTH-1:0] B_AND_S; for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}}; end:B_AND for (i = 0; i < WIDTH; i = i + 1) begin:B_OR + (* force_downto *) wire [S_WIDTH-1:0] B_AND_BITS; for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i]; diff --git a/techlibs/coolrunner2/cells_counter_map.v b/techlibs/coolrunner2/cells_counter_map.v index b474fa522..f9c44c80f 100644 --- a/techlibs/coolrunner2/cells_counter_map.v +++ b/techlibs/coolrunner2/cells_counter_map.v @@ -3,6 +3,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP); input wire CE; input wire CLK; output wire OUT; + (* force_downto *) output wire[WIDTH-1:0] POUT; input wire RST; input wire UP; diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v index 17bde0497..ffd42469c 100644 --- a/techlibs/ecp5/arith_map.v +++ b/techlibs/ecp5/arith_map.v @@ -26,15 +26,20 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); 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)); @@ -48,10 +53,15 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); 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; diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index c031703a9..e19ac9ab9 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -70,6 +70,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/efinix/arith_map.v b/techlibs/efinix/arith_map.v index 178f57bc5..4dac360b9 100644 --- a/techlibs/efinix/arith_map.v +++ b/techlibs/efinix/arith_map.v @@ -26,24 +26,33 @@ module _80_efinix_alu (A, B, CI, BI, X, Y, CO); 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 CIx; + (* force_downto *) wire [Y_WIDTH-1:0] COx; wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + (* 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = { COx, CIx }; EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) @@ -76,4 +85,4 @@ module _80_efinix_alu (A, B, CI, BI, X, Y, CO); /* End implementation */ assign X = AA ^ BB; -endmodule \ No newline at end of file +endmodule diff --git a/techlibs/efinix/cells_map.v b/techlibs/efinix/cells_map.v index 3ecec3bac..1090f8b27 100644 --- a/techlibs/efinix/cells_map.v +++ b/techlibs/efinix/cells_map.v @@ -34,6 +34,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v index b6f9e8c38..42aaba870 100644 --- a/techlibs/gowin/arith_map.v +++ b/techlibs/gowin/arith_map.v @@ -26,21 +26,29 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO); 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 <= 2; + (* 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO, CI}; genvar i; diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v index aee912256..b44350616 100644 --- a/techlibs/gowin/cells_map.v +++ b/techlibs/gowin/cells_map.v @@ -232,6 +232,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v index 51c85183d..316be3f73 100644 --- a/techlibs/greenpak4/cells_map.v +++ b/techlibs/greenpak4/cells_map.v @@ -115,6 +115,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; @@ -150,6 +151,7 @@ module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP); input wire CE; input wire CLK; output reg OUT; + (* force_downto *) output reg[WIDTH-1:0] POUT; input wire RST; input wire UP; diff --git a/techlibs/ice40/arith_map.v b/techlibs/ice40/arith_map.v index ed4140e44..3950e882b 100644 --- a/techlibs/ice40/arith_map.v +++ b/techlibs/ice40/arith_map.v @@ -25,21 +25,29 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO); 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 <= 2; + (* 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO, CI}; genvar i; diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v index e9ccca239..7e5c07879 100644 --- a/techlibs/ice40/cells_map.v +++ b/techlibs/ice40/cells_map.v @@ -2,6 +2,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/intel/arria10gx/cells_arith.v b/techlibs/intel/arria10gx/cells_arith.v index 89fb4561f..6a52a0f95 100644 --- a/techlibs/intel/arria10gx/cells_arith.v +++ b/techlibs/intel/arria10gx/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); 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; @@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/arria10gx/cells_map.v b/techlibs/intel/arria10gx/cells_map.v index 1430e8551..83f5881da 100644 --- a/techlibs/intel/arria10gx/cells_map.v +++ b/techlibs/intel/arria10gx/cells_map.v @@ -30,6 +30,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cyclone10lp/cells_arith.v b/techlibs/intel/cyclone10lp/cells_arith.v index 5ae8d6cea..d8c46e865 100644 --- a/techlibs/intel/cyclone10lp/cells_arith.v +++ b/techlibs/intel/cyclone10lp/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); 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; @@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/cyclone10lp/cells_map.v b/techlibs/intel/cyclone10lp/cells_map.v index c2f6f403c..2a80ea678 100644 --- a/techlibs/intel/cyclone10lp/cells_map.v +++ b/techlibs/intel/cyclone10lp/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cycloneiv/cells_arith.v b/techlibs/intel/cycloneiv/cells_arith.v index 010a4b5da..f7bc3cd65 100644 --- a/techlibs/intel/cycloneiv/cells_arith.v +++ b/techlibs/intel/cycloneiv/cells_arith.v @@ -70,8 +70,11 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO); 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; @@ -79,11 +82,14 @@ module _80_cycloneiv_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH < 6; + (* 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH:0] C = {CO, CI}; diff --git a/techlibs/intel/cycloneiv/cells_map.v b/techlibs/intel/cycloneiv/cells_map.v index 191488430..9d8a5a2b7 100644 --- a/techlibs/intel/cycloneiv/cells_map.v +++ b/techlibs/intel/cycloneiv/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v index 49e36aa25..a755e10db 100644 --- a/techlibs/intel/cycloneive/arith_map.v +++ b/techlibs/intel/cycloneive/arith_map.v @@ -66,8 +66,11 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); 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; @@ -75,11 +78,14 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); wire _TECHMAP_FAIL_ = Y_WIDTH < 5; + (* 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH:0] C = {CO, CI}; diff --git a/techlibs/intel/cycloneive/cells_map.v b/techlibs/intel/cycloneive/cells_map.v index abeb92eef..fead2837b 100644 --- a/techlibs/intel/cycloneive/cells_map.v +++ b/techlibs/intel/cycloneive/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel/cyclonev/cells_arith.v b/techlibs/intel/cyclonev/cells_arith.v index 89fb4561f..6a52a0f95 100644 --- a/techlibs/intel/cyclonev/cells_arith.v +++ b/techlibs/intel/cyclonev/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO); 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; @@ -36,11 +39,14 @@ module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v index f8d142bc9..eb4cd54d1 100644 --- a/techlibs/intel/cyclonev/cells_map.v +++ b/techlibs/intel/cyclonev/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; wire VCC; diff --git a/techlibs/intel/max10/cells_arith.v b/techlibs/intel/max10/cells_arith.v index e2194cbd7..8529706a7 100644 --- a/techlibs/intel/max10/cells_arith.v +++ b/techlibs/intel/max10/cells_arith.v @@ -26,8 +26,11 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, CO); 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; @@ -36,11 +39,14 @@ module _80_altera_max10_alu (A, B, CI, BI, X, Y, 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; //wire [Y_WIDTH:0] C = {CO, CI}; wire [Y_WIDTH+1:0] COx; diff --git a/techlibs/intel/max10/cells_map.v b/techlibs/intel/max10/cells_map.v index 6d604e072..6a4072049 100644 --- a/techlibs/intel/max10/cells_map.v +++ b/techlibs/intel/max10/cells_map.v @@ -71,6 +71,7 @@ endmodule module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; generate diff --git a/techlibs/intel_alm/common/alm_map.v b/techlibs/intel_alm/common/alm_map.v index fe646c5d6..6697b2e78 100644 --- a/techlibs/intel_alm/common/alm_map.v +++ b/techlibs/intel_alm/common/alm_map.v @@ -3,6 +3,7 @@ module \$lut (A, Y); parameter WIDTH = 1; parameter LUT = 0; +(* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/intel_alm/common/arith_alm_map.v b/techlibs/intel_alm/common/arith_alm_map.v index ddf81d9d0..8515eeb56 100644 --- a/techlibs/intel_alm/common/arith_alm_map.v +++ b/techlibs/intel_alm/common/arith_alm_map.v @@ -11,17 +11,24 @@ parameter Y_WIDTH = 1; parameter _TECHMAP_CONSTMSK_CI_ = 0; parameter _TECHMAP_CONSTVAL_CI_ = 0; +(* force_downto *) input [A_WIDTH-1:0] A; +(* force_downto *) input [B_WIDTH-1:0] B; input CI, BI; +(* force_downto *) output [Y_WIDTH-1:0] X, Y, CO; +(* 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)); +(* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; +(* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; +(* force_downto *) wire [Y_WIDTH-1:0] BX = B_buf; wire [Y_WIDTH:0] ALM_CARRY; diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v index 6ad7807d2..9fddc0f41 100644 --- a/techlibs/sf2/cells_map.v +++ b/techlibs/sf2/cells_map.v @@ -59,6 +59,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index 2b8b0dcc1..2fc216908 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -24,9 +24,11 @@ module _80_xilinx_lcu (P, G, CI, CO); parameter WIDTH = 2; + (* force_downto *) input [WIDTH-1:0] P, G; input CI; + (* force_downto *) output [WIDTH-1:0] CO; wire _TECHMAP_FAIL_ = WIDTH <= 2; @@ -41,7 +43,9 @@ module _80_xilinx_lcu (P, G, CI, CO); generate if (EXPLICIT_CARRY || `LUT_SIZE == 4) begin + (* force_downto *) wire [WIDTH-1:0] C = {CO, CI}; + (* force_downto *) wire [WIDTH-1:0] S = P & ~G; generate for (i = 0; i < WIDTH; i = i + 1) begin:slice @@ -59,8 +63,11 @@ end else begin localparam MAX_WIDTH = CARRY4_COUNT * 4; localparam PAD_WIDTH = MAX_WIDTH - WIDTH; + (* force_downto *) wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G}; + (* force_downto *) wire [MAX_WIDTH-1:0] GG = {{PAD_WIDTH{1'b0}}, G}; + (* force_downto *) wire [MAX_WIDTH-1:0] C; assign CO = C; @@ -103,20 +110,27 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter _TECHMAP_CONSTVAL_CI_ = 0; parameter _TECHMAP_CONSTMSK_CI_ = 0; + (* 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 <= 2; + (* 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)); + (* force_downto *) wire [Y_WIDTH-1:0] AA = A_buf; + (* force_downto *) wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; genvar i; @@ -129,7 +143,9 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); generate if (`LUT_SIZE == 4) begin + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO, CI}; + (* force_downto *) wire [Y_WIDTH-1:0] S = {AA ^ BB}; genvar i; @@ -149,6 +165,7 @@ generate if (`LUT_SIZE == 4) begin end else if (EXPLICIT_CARRY) begin + (* force_downto *) wire [Y_WIDTH-1:0] S = AA ^ BB; wire CINIT; @@ -161,7 +178,9 @@ end else if (EXPLICIT_CARRY) begin // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR, // e.g. off fabric dedicated chain. CO is the carry outputs that are // available to the fabric. + (* force_downto *) wire [Y_WIDTH-1:0] CO_CHAIN; + (* force_downto *) wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT}; // If carry chain is being initialized to a constant, techmap the constant @@ -250,10 +269,14 @@ end else begin localparam MAX_WIDTH = CARRY4_COUNT * 4; localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; + (* force_downto *) wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; + (* force_downto *) wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA}; + (* force_downto *) wire [MAX_WIDTH-1:0] O; + (* force_downto *) wire [MAX_WIDTH-1:0] C; assign Y = O, CO = C; diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index cc180f2b9..801949d22 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -184,8 +184,11 @@ module \$__XILINX_SHIFTX (A, B, Y); 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] Y; parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0; @@ -321,8 +324,11 @@ module _90__XILINX_SHIFTX (A, B, Y); 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] Y; \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v index ec2e3b234..2ab6075f1 100644 --- a/techlibs/xilinx/lut_map.v +++ b/techlibs/xilinx/lut_map.v @@ -26,6 +26,7 @@ module \$lut (A, Y); parameter WIDTH = 0; parameter LUT = 0; + (* force_downto *) input [WIDTH-1:0] A; output Y; diff --git a/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v index 91aaf2118..bb31d21ec 100644 --- a/techlibs/xilinx/mux_map.v +++ b/techlibs/xilinx/mux_map.v @@ -30,8 +30,11 @@ module \$shiftx (A, B, Y); 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] Y; parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0; diff --git a/tests/arch/xilinx/mux.ys b/tests/arch/xilinx/mux.ys index 99817738d..1b2788448 100644 --- a/tests/arch/xilinx/mux.ys +++ b/tests/arch/xilinx/mux.ys @@ -40,8 +40,10 @@ proc equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module -select -assert-min 5 t:LUT6 +select -assert-max 2 t:LUT4 +select -assert-min 4 t:LUT6 select -assert-max 7 t:LUT6 select -assert-max 2 t:MUXF7 +dump -select -assert-none t:LUT6 t:MUXF7 %% t:* %D +select -assert-none t:LUT6 t:LUT4 t:MUXF7 %% t:* %D From 1053032a81ea54847bfef944d3c5481de8a2046e Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 19 May 2020 16:13:44 +0000 Subject: [PATCH 146/197] smtbmc: Fix typo in error message. Co-Authored-By: N. Engelhardt --- backends/smt2/smtbmc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index f1f55be1c..cc3ebb129 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1511,7 +1511,7 @@ else: # not tempind, covermode smt_assert_consequent(get_constr_expr(constr_assumes, i)) print_msg("Re-solving with appended steps..") if smt_check_sat() == "unsat": - print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) + print("%s Cannot append steps without violating assumptions!" % smt.timestamp()) retstatus = "FAILED" break print_anyconsts(step) From 6eea4b3d79590f874caa3ec740785781f3926666 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 18 May 2020 17:10:01 +0000 Subject: [PATCH 147/197] kernel: Try an order-independent approach to hashing `dict`. Co-Authored-By: David Shah Co-Authored-By: Eddie Hung --- kernel/hashlib.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 1284f3f8d..5c87b55f5 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -617,12 +617,10 @@ public: } unsigned int hash() const { - std::vector entries_(entries); //make a copy to preserve const-ness - std::sort(entries_.begin(), entries_.end()); unsigned int h = mkhash_init; - for (unsigned int i = 0; i < entries_.size(); ++i) { - h = mkhash(h, hash_ops::hash(entries_[i].udata.first)); - h = mkhash(h, hash_ops::hash(entries_[i].udata.second)); + for (auto &entry : entries) { + h ^= hash_ops::hash(entry.udata.first); + h ^= hash_ops::hash(entry.udata.second); } return h; } From 38e858af8d5f61677d9686c022c864857f729d58 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 21 May 2020 09:10:56 -0700 Subject: [PATCH 148/197] Update frontends/verilog/verilog_parser.y Co-authored-by: Alberto Gonzalez <61295559+boqwxp@users.noreply.github.com> --- frontends/verilog/verilog_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index fd4ff68a9..ae7a3f4aa 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2216,7 +2216,7 @@ simple_behavioral_stmt: behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | non_opt_delay behavioral_stmt | - simple_behavioral_stmt ';' | ';' | + attr simple_behavioral_stmt ';' | ';' | attr hierarchical_id { AstNode *node = new AstNode(AST_TCALL); node->str = *$2; From 4f0f32116956782059d415a13ac52bf056634d6f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 21 May 2020 21:39:13 -0700 Subject: [PATCH 149/197] abc9_ops: update comment --- passes/techmap/abc9_ops.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 10c980f73..8d55b18a0 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -547,7 +547,7 @@ void mark_scc(RTLIL::Module *module) // For every unique SCC found, (arbitrarily) find the first // cell in the component, and replace its output connections // with a new wire driven by the old connection but with a - // special (* abc9_scc *) attribute set (which is used by + // special (* abc9_keep *) attribute set (which is used by // write_xaiger to break this wire into PI and POs) pool ids_seen; for (auto cell : module->cells()) { From 281c96856aec2fac0aa79a52484068f7e386b586 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 22 May 2020 17:44:05 +0000 Subject: [PATCH 150/197] cxxrtl: get rid of -O5 aka `opt_clean -purge` optimization level. This isn't actually necessary anymore after scheduling was improved, and `clean -purge` disrupts the mapping between wires in the input RTLIL netlist and the output CXXRTL code. --- backends/cxxrtl/cxxrtl.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc index f3ed3f623..549404184 100644 --- a/backends/cxxrtl/cxxrtl.cc +++ b/backends/cxxrtl/cxxrtl.cc @@ -2306,10 +2306,7 @@ struct CxxrtlBackend : public Backend { log(" like -O3, and localize public wires not marked (*keep*) if possible.\n"); log("\n"); log(" -O5\n"); - log(" like -O4, and run `opt_clean -purge` first.\n"); - log("\n"); - log(" -O6\n"); - log(" like -O5, and run `proc; flatten` first.\n"); + log(" like -O4, and run `proc; flatten` first.\n"); log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -2343,13 +2340,10 @@ struct CxxrtlBackend : public Backend { extra_args(f, filename, args, argidx); switch (opt_level) { - case 6: + case 5: worker.max_opt_level = true; worker.run_proc_flatten = true; YS_FALLTHROUGH - case 5: - worker.run_opt_clean_purge = true; - YS_FALLTHROUGH case 4: worker.localize_public = true; YS_FALLTHROUGH From aea0fd5ed4f5f56b81c43fe410efced194ef6472 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Sat, 25 Apr 2020 04:12:02 +0000 Subject: [PATCH 151/197] qbfsat: Add bisection mode and make it the default. Also adds `-nooptimize` and reorganizes `qbfsat.cc` a bit. --- passes/sat/qbfsat.cc | 292 ++++++++++++++++++++++++++++++------------- 1 file changed, 206 insertions(+), 86 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index d99ca1b53..0484b57b3 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/celltypes.h" +#include "kernel/consteval.h" #include "kernel/log.h" #include "kernel/rtlil.h" #include "kernel/register.h" @@ -43,13 +44,13 @@ struct QbfSolutionType { dict hole_to_value; bool sat; bool unknown; //true if neither 'sat' nor 'unsat' - bool success; //true if exit code 0 - QbfSolutionType() : sat(false), unknown(true), success(false) {} + QbfSolutionType() : sat(false), unknown(true) {} }; struct QbfSolveOptions { bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg; + bool nooptimize, nobisection; bool sat, unsat, show_smtbmc; std::string specialize_soln_file; std::string write_soln_soln_file; @@ -57,12 +58,14 @@ struct QbfSolveOptions { size_t argidx; QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false), nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false), - sat(false), unsat(false), show_smtbmc(false), argidx(0) {}; + nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false), + argidx(0) {}; }; void recover_solution(QbfSolutionType &sol) { YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED"); YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available"); + YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\""); YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)"); #ifndef NDEBUG YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+"); @@ -86,6 +89,10 @@ void recover_solution(QbfSolutionType &sol) { sat_regex_found = true; else if (YS_REGEX_NS::regex_search(x, unsat_regex)) unsat_regex_found = true; + else if (YS_REGEX_NS::regex_search(x, memout_regex)) { + sol.unknown = true; + log_warning("solver ran out of memory\n"); + } } #ifndef NDEBUG log_assert(!sol.unknown && sol.sat? sat_regex_found : true); @@ -107,6 +114,40 @@ dict get_hole_loc_name_map(RTLIL::Module *module, cons return hole_loc_to_name; } +pool validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) { + bool found_input = false; + bool found_hole = false; + bool found_1bit_output = false; + bool found_assert_assume = false; + pool input_wires; + for (auto wire : module->wires()) { + if (wire->port_input) { + found_input = true; + input_wires.insert(wire->name.str()); + } + if (wire->port_output && wire->width == 1) + found_1bit_output = true; + } + for (auto cell : module->cells()) { + if (cell->type == "$allconst") + found_input = true; + if (cell->type == "$anyconst") + found_hole = true; + if (cell->type.in("$assert", "$assume")) + found_assert_assume = true; + } + if (!found_input) + log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n"); + if (!found_hole) + log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n"); + if (!found_1bit_output && !found_assert_assume) + log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n"); + if (!found_assert_assume && !opt.assume_outputs) + log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n"); + + return input_wires; +} + void write_solution(RTLIL::Module *module, const QbfSolutionType &sol, const std::string &file) { std::ofstream fout(file.c_str()); if (!fout) @@ -164,7 +205,7 @@ void specialize_from_file(RTLIL::Module *module, const std::string &file) { } } -void specialize(RTLIL::Module *module, const QbfSolutionType &sol) { +void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = false) { dict hole_loc_to_name = get_hole_loc_name_map(module, sol); pool anyconsts_to_remove; for (auto cell : module->cells()) @@ -189,7 +230,8 @@ void specialize(RTLIL::Module *module, const QbfSolutionType &sol) { log_assert(wire->width > 0 && GetSize(hole_value) == wire->width); #endif - log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str()); + if (!quiet) + log("Specializing %s with %s = %d'b%s.\n", module->name.c_str(), hole_name.c_str(), wire->width, hole_value.c_str()); std::vector value_bv; value_bv.reserve(wire->width); for (char c : hole_value) @@ -219,7 +261,6 @@ void dump_model(RTLIL::Module *module, const QbfSolutionType &sol) { value_bv.emplace_back(c == '1'? RTLIL::S1 : RTLIL::S0); std::reverse(value_bv.begin(), value_bv.end()); } - } void allconstify_inputs(RTLIL::Module *module, const pool &input_wires) { @@ -280,86 +321,155 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) { module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1); } -QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { +QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, const std::string &tempdir_name, const bool quiet = false, const int iter_num = 0) { + //Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 ]` QbfSolutionType ret; const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc"; + const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2"; + const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s z3 -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; const std::string smtbmc_warning = "z3: WARNING:"; const bool show_smtbmc = opt.show_smtbmc; - const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX"); - const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem.smt2"; -#ifndef NDEBUG - log_assert(mod->design != nullptr); -#endif Pass::call(mod->design, smt2_command); + + auto process_line = [&ret, &smtbmc_warning, &show_smtbmc, &quiet](const std::string &line) { + ret.stdout_lines.push_back(line.substr(0, line.size()-1)); //don't include trailing newline + auto warning_pos = line.find(smtbmc_warning); + if (warning_pos != std::string::npos) + log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str()); + else + if (show_smtbmc && !quiet) + log("smtbmc output: %s", line.c_str()); + }; log_header(mod->design, "Solving QBF-SAT problem.\n"); + if (!quiet) log("Launching \"%s\".\n", smtbmc_cmd.c_str()); + int retval = run_command(smtbmc_cmd, process_line); + if (retval == 0) { + ret.sat = true; + ret.unknown = false; + } else if (retval == 1) { + ret.sat = false; + ret.unknown = false; + } - //Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 ]` - { - const std::string cmd = yosys_smtbmc_exe + " -s z3 -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem.smt2 2>&1"; - auto process_line = [&ret, &smtbmc_warning, &show_smtbmc](const std::string &line) { - ret.stdout_lines.push_back(line.substr(0, line.size()-1)); //don't include trailing newline - auto warning_pos = line.find(smtbmc_warning); - if (warning_pos != std::string::npos) - log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str()); - else - if (show_smtbmc) - log("smtbmc output: %s", line.c_str()); - }; + recover_solution(ret); + return ret; +} - log("Launching \"%s\".\n", cmd.c_str()); - int retval = run_command(cmd, process_line); - if (retval == 0) { - ret.sat = true; - ret.unknown = false; - } else if (retval == 1) { - ret.sat = false; - ret.unknown = false; +QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { + QbfSolutionType ret, best_soln; + const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX"); + RTLIL::Module *module = mod; + RTLIL::Design *design = module->design; + std::string module_name = module->name.str(); + RTLIL::Wire *wire_to_optimize = nullptr; + RTLIL::IdString wire_to_optimize_name; + bool maximize = false; + log_assert(module->design != nullptr); + + Pass::call(design, "design -push-copy"); + + //Replace input wires with wires assigned $allconst cells: + pool input_wires = validate_design_and_get_inputs(module, opt); + allconstify_inputs(module, input_wires); + if (opt.assume_outputs) + assume_miter_outputs(module, opt); + + //Find the wire to be optimized, if any: + for (auto wire : module->wires()) + if (wire->get_bool_attribute("\\maximize") || wire->get_bool_attribute("\\minimize")) + wire_to_optimize = wire; + if (wire_to_optimize != nullptr) { + wire_to_optimize_name = wire_to_optimize->name; + maximize = wire_to_optimize->get_bool_attribute("\\maximize"); + } + + if (opt.nobisection || opt.nooptimize) { + if (wire_to_optimize != nullptr && opt.nooptimize) { + wire_to_optimize->set_bool_attribute("\\maximize", false); + wire_to_optimize->set_bool_attribute("\\minimize", false); + } + ret = call_qbf_solver(module, opt, tempdir_name, false, 0); + } else { + //Do the iterated bisection method: + unsigned int iter_num = 1; + unsigned int success = 0; + unsigned int failure = 0; + unsigned int cur_thresh = 0; + + log_assert(wire_to_optimize != nullptr); + log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), log_signal(wire_to_optimize)); + + //If maximizing, grow until we get a failure. Then bisect success and failure. + while (failure == 0 || success - failure > 1) { + Pass::call(design, "design -push-copy"); + log_header(design, "Preparing QBF-SAT problem.\n"); + + if (cur_thresh != 0) { + //Add thresholding logic (but not on the initial run when we don't have a sense of where to start): + RTLIL::SigSpec comparator = maximize? module->Ge(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false) + : module->Le(NEW_ID, module->wire(wire_to_optimize_name), RTLIL::Const(cur_thresh), false); + + module->addAssume(wire_to_optimize_name.str() + "__threshold", comparator, RTLIL::Const(1, 1)); + log("Trying to solve with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), cur_thresh); + } + + ret = call_qbf_solver(module, opt, tempdir_name, false, iter_num); + Pass::call(design, "design -pop"); + module = design->module(module_name); + + if (!ret.unknown && ret.sat) { + Pass::call(design, "design -push-copy"); + specialize(module, ret, true); + + RTLIL::SigSpec wire, value, undef; + RTLIL::SigSpec::parse_sel(wire, design, module, wire_to_optimize_name.str()); + + ConstEval ce(module); + value = wire; + if (!ce.eval(value, undef)) + log_cmd_error("Failed to evaluate signal %s: Missing value for %s.\n", log_signal(wire), log_signal(undef)); + log_assert(value.is_fully_const()); + success = value.as_const().as_int(); + best_soln = ret; + log("Problem is satisfiable with %s = %d.\n", wire_to_optimize_name.c_str(), success); + Pass::call(design, "design -pop"); + module = design->module(module_name); + + //sometimes this happens if we get an 'unknown' or timeout + if (!maximize && success < failure) + break; + else if (maximize && success > failure) + break; + } else { + //Treat 'unknown' as UNSAT + failure = cur_thresh; + if (failure == 0) { + log("Problem is NOT satisfiable.\n"); + break; + } + else + log("Problem is NOT satisfiable with %s %s %d.\n", wire_to_optimize_name.c_str(), (maximize? ">=" : "<="), failure); + } + + iter_num++; + cur_thresh = (maximize && failure == 0)? 2 * success //growth + : (success + failure) / 2; //bisection + } + if (success != 0 || failure != 0) { + log("Wire %s is %s at %d.\n", wire_to_optimize_name.c_str(), (maximize? "maximized" : "minimized"), success); + ret = best_soln; } } if(!opt.nocleanup) remove_directory(tempdir_name); - recover_solution(ret); + Pass::call(design, "design -pop"); return ret; } -pool validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) { - bool found_input = false; - bool found_hole = false; - bool found_1bit_output = false; - bool found_assert_assume = false; - pool input_wires; - for (auto wire : module->wires()) { - if (wire->port_input) { - found_input = true; - input_wires.insert(wire->name.str()); - } - if (wire->port_output && wire->width == 1) - found_1bit_output = true; - } - for (auto cell : module->cells()) { - if (cell->type == "$allconst") - found_input = true; - if (cell->type == "$anyconst") - found_hole = true; - if (cell->type.in("$assert", "$assume")) - found_assert_assume = true; - } - if (!found_input) - log_cmd_error("Can't perform QBF-SAT on a miter with no inputs!\n"); - if (!found_hole) - log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n"); - if (!found_1bit_output && !found_assert_assume) - log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n"); - if (!found_assert_assume && !opt.assume_outputs) - log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n"); - - return input_wires; -} - QbfSolveOptions parse_args(const std::vector &args) { QbfSolveOptions opt; for (opt.argidx = 1; opt.argidx < args.size(); opt.argidx++) { @@ -379,6 +489,14 @@ QbfSolveOptions parse_args(const std::vector &args) { opt.assume_neg = true; continue; } + else if (args[opt.argidx] == "-nooptimize") { + opt.nooptimize = true; + continue; + } + else if (args[opt.argidx] == "-nobisection") { + opt.nobisection = true; + continue; + } else if (args[opt.argidx] == "-sat") { opt.sat = true; continue; @@ -477,6 +595,17 @@ struct QbfSatPass : public Pass { log(" negative polarity signals and should always be low, for example like the\n"); log(" miters created with the `miter` command.\n"); log("\n"); + log(" -nooptimize\n"); + log(" Ignore \"\\minimize\" and \"\\maximize\" attributes, do not emit \"(maximize)\" or\n"); + log(" \"(minimize)\" in the SMTLIBv2, and generally make no attempt to optimize anything.\n"); + log("\n"); + log(" -nobisection\n"); + log(" If a wire is marked with the \"\\minimize\" or \"\\maximize\" attribute, do not\n"); + log(" attempt to optimize that value with the default iterated solving and threshold\n"); + log(" bisection approach. Instead, have yosys-smtbmc emit a \"(minimize)\" or \"(maximize)\"\n"); + log(" command in the SMTLIBv2 output and hope that the solver supports optimizing\n"); + log(" quantified bitvector problems.\n"); + log("\n"); log(" -sat\n"); log(" Generate an error if the solver does not return \"sat\".\n"); log("\n"); @@ -519,26 +648,16 @@ struct QbfSatPass : public Pass { if (!opt.specialize_from_file) { //Save the design to restore after modiyfing the current module. std::string module_name = module->name.str(); - Pass::call(design, "design -push-copy"); - - //Replace input wires with wires assigned $allconst cells. - pool input_wires = validate_design_and_get_inputs(module, opt); - allconstify_inputs(module, input_wires); - if (opt.assume_outputs) - assume_miter_outputs(module, opt); QbfSolutionType ret = qbf_solve(module, opt); - Pass::call(design, "design -pop"); module = design->module(module_name); - - if (ret.unknown) + if (ret.unknown) { log_warning("solver did not give an answer\n"); - else if (ret.sat) + if (opt.sat || opt.unsat) + log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT"); + } + else if (ret.sat) { print_qed(); - else - print_proof_failed(); - - if(!ret.unknown && ret.sat) { if (opt.write_solution) { write_solution(module, ret, opt.write_soln_soln_file); } @@ -550,10 +669,11 @@ struct QbfSatPass : public Pass { if (opt.unsat) log_cmd_error("expected problem to be UNSAT\n"); } - else if (!ret.unknown && !ret.sat && opt.sat) - log_cmd_error("expected problem to be SAT\n"); - else if (ret.unknown && (opt.sat || opt.unsat)) - log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT"); + else { + print_proof_failed(); + if (opt.sat) + log_cmd_error("expected problem to be SAT\n"); + } } else specialize_from_file(module, opt.specialize_soln_file); log_pop(); From ac41f8a9c7a89c176867dc217eb81bffa7c1aced Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Thu, 21 May 2020 23:20:44 +0000 Subject: [PATCH 152/197] qbfsat: Remove cruft inadvertently left untouched in commit 86fc49a9d60f9ad4cdeec93663e7245a9fdf60c6. --- passes/sat/qbfsat.cc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 0484b57b3..c42760488 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -23,19 +23,8 @@ #include "kernel/log.h" #include "kernel/rtlil.h" #include "kernel/register.h" -#include #include -#if defined(_WIN32) -# define WIFEXITED(x) 1 -# define WIFSIGNALED(x) 0 -# define WIFSTOPPED(x) 0 -# define WEXITSTATUS(x) ((x) & 0xff) -# define WTERMSIG(x) SIGTERM -#else -# include -#endif - USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN From 76e0cc82768957bd1dd473c559ec88ee2bd4d7bb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 23 May 2020 08:17:40 -0700 Subject: [PATCH 153/197] ecp5: cleanup unused +/ecp5/abc9_model.v --- techlibs/ecp5/Makefile.inc | 1 - techlibs/ecp5/abc9_model.v | 12 ------------ techlibs/ecp5/synth_ecp5.cc | 1 - 3 files changed, 14 deletions(-) delete mode 100644 techlibs/ecp5/abc9_model.v diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 9a337b2b6..9d564c78c 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -23,7 +23,6 @@ $(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)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc9_model.v)) EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk .SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk diff --git a/techlibs/ecp5/abc9_model.v b/techlibs/ecp5/abc9_model.v deleted file mode 100644 index b7ecd7358..000000000 --- a/techlibs/ecp5/abc9_model.v +++ /dev/null @@ -1,12 +0,0 @@ -// --------------------------------------- - -(* abc9_box *) -module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO); - specify - ($DO => DO) = 0; - (RAD[0] *> DO) = 141; - (RAD[1] *> DO) = 379; - (RAD[2] *> DO) = 275; - (RAD[3] *> DO) = 379; - endspecify -endmodule diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index e5c1f7550..aceb36abc 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -334,7 +334,6 @@ struct SynthEcp5Pass : public ScriptPass run("techmap -map +/ecp5/latches_map.v", "(skip if -asyncprld)"); if (abc9) { - run("read_verilog -icells -lib -specify +/ecp5/abc9_model.v"); std::string abc9_opts; if (nowidelut) abc9_opts += " -maxlut 4"; From d64df216302bab5b7c5047bbbcb0e3cd82f1ec2d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 24 May 2020 08:17:30 -0700 Subject: [PATCH 154/197] xaiger: do not derive cells --- backends/aiger/xaiger.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 69797ceaf..6b910eecd 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -248,6 +248,7 @@ struct XAigerWriter auto it = cell->attributes.find(ID::abc9_box_seq); if (it != cell->attributes.end()) { log_assert(!cell->has_keep_attr()); + log_assert(cell->parameters.empty()); int abc9_box_seq = it->second.as_int(); if (GetSize(box_list) <= abc9_box_seq) box_list.resize(abc9_box_seq+1); @@ -260,13 +261,6 @@ struct XAigerWriter continue; } - if (!cell->parameters.empty()) { - auto derived_type = inst_module->derive(design, cell->parameters); - inst_module = design->module(derived_type); - log_assert(inst_module); - log_assert(inst_module->get_blackbox_attribute()); - } - if (!timing.count(inst_module->name)) timing.setup_module(inst_module); auto &t = timing.at(inst_module->name).arrival; From 33b03ce904f6810437e27ca7a6df4fb1e966fc23 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 24 May 2020 08:48:23 -0700 Subject: [PATCH 155/197] xaiger: add testcase --- tests/various/xaiger.ys | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/various/xaiger.ys diff --git a/tests/various/xaiger.ys b/tests/various/xaiger.ys new file mode 100644 index 000000000..f612d2e18 --- /dev/null +++ b/tests/various/xaiger.ys @@ -0,0 +1,13 @@ +read_verilog < Date: Mon, 11 May 2020 09:33:11 -0700 Subject: [PATCH 156/197] tests: add #2037 testcase --- tests/verilog/bug2037.ys | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/verilog/bug2037.ys diff --git a/tests/verilog/bug2037.ys b/tests/verilog/bug2037.ys new file mode 100644 index 000000000..afe92022e --- /dev/null +++ b/tests/verilog/bug2037.ys @@ -0,0 +1,9 @@ +logger -expect warning "Attribute\(s\) attached to null statement\. Ignoring\." 1 +logger -expect-no-warnings +read_verilog < Date: Mon, 11 May 2020 09:33:19 -0700 Subject: [PATCH 157/197] verilog: fix #2037 by permitting (and freeing) attributes on null stmt --- frontends/verilog/verilog_parser.y | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index d39b72547..a0250439e 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2228,7 +2228,11 @@ simple_behavioral_stmt: behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | non_opt_delay behavioral_stmt | - attr simple_behavioral_stmt ';' | ';' | + attr simple_behavioral_stmt ';' | + attr ';' { + log_file_warning(current_filename, get_line_num(), "Attribute(s) attached to null statement. Ignoring.\n"); + free_attr($1); + } | attr hierarchical_id { AstNode *node = new AstNode(AST_TCALL); node->str = *$2; From 88bddb37c91e8fe136e5c9cc2ade20fadccd1946 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 11 May 2020 10:20:33 -0700 Subject: [PATCH 158/197] verilog: handle empty generate statement by removing gen_stmt_or_null... ... rule which causes a s/r conflict. Now we get an empty genblock, which should be okay. --- frontends/verilog/verilog_parser.y | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index a0250439e..eb7e136ae 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2440,7 +2440,7 @@ gen_case_item: } case_select { case_type_stack.push_back(0); SET_AST_NODE_LOC(ast_stack.back(), @2, @2); - } gen_stmt_or_null { + } gen_stmt_block { case_type_stack.pop_back(); ast_stack.pop_back(); }; @@ -2532,7 +2532,11 @@ module_gen_body: /* empty */; gen_stmt_or_module_body_stmt: - gen_stmt | module_body_stmt; + gen_stmt | module_body_stmt | + attr ';' { + log_file_warning(current_filename, get_line_num(), "Attribute(s) attached to null statement. Ignoring.\n"); + free_attr($1); + }; // this production creates the obligatory if-else shift/reduce conflict gen_stmt: @@ -2554,7 +2558,7 @@ gen_stmt: AstNode *block = new AstNode(AST_GENBLOCK); ast_stack.back()->children.push_back(block); ast_stack.push_back(block); - } gen_stmt_or_null { + } gen_stmt_block { ast_stack.pop_back(); } opt_gen_else { SET_AST_NODE_LOC(ast_stack.back(), @1, @7); @@ -2604,11 +2608,8 @@ gen_stmt_block: ast_stack.pop_back(); }; -gen_stmt_or_null: - gen_stmt_block | ';'; - opt_gen_else: - TOK_ELSE gen_stmt_or_null | /* empty */ %prec FAKE_THEN; + TOK_ELSE gen_stmt_block | /* empty */ %prec FAKE_THEN; expr: basic_expr { From 29d84339bf9ec8f1d2be3fa20f81843f3ee08324 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 11 May 2020 10:26:08 -0700 Subject: [PATCH 159/197] tests: add an generate-else test too --- tests/verilog/bug2037.ys | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/verilog/bug2037.ys b/tests/verilog/bug2037.ys index afe92022e..42c4b8f5d 100644 --- a/tests/verilog/bug2037.ys +++ b/tests/verilog/bug2037.ys @@ -7,3 +7,37 @@ module test (); if (y) (* foo *) ; endmodule EOT + + +design -reset +logger -expect warning "Attribute\(s\) attached to null statement\. Ignoring\." 3 # cumulative +logger -expect-no-warnings +read_verilog < Date: Thu, 14 May 2020 10:46:40 -0700 Subject: [PATCH 160/197] verilog: do not warn for attributes on null statements --- frontends/verilog/verilog_parser.y | 2 -- tests/verilog/bug2037.ys | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index eb7e136ae..475557af9 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2230,7 +2230,6 @@ behavioral_stmt: non_opt_delay behavioral_stmt | attr simple_behavioral_stmt ';' | attr ';' { - log_file_warning(current_filename, get_line_num(), "Attribute(s) attached to null statement. Ignoring.\n"); free_attr($1); } | attr hierarchical_id { @@ -2534,7 +2533,6 @@ module_gen_body: gen_stmt_or_module_body_stmt: gen_stmt | module_body_stmt | attr ';' { - log_file_warning(current_filename, get_line_num(), "Attribute(s) attached to null statement. Ignoring.\n"); free_attr($1); }; diff --git a/tests/verilog/bug2037.ys b/tests/verilog/bug2037.ys index 42c4b8f5d..eb4f0fac4 100644 --- a/tests/verilog/bug2037.ys +++ b/tests/verilog/bug2037.ys @@ -1,4 +1,3 @@ -logger -expect warning "Attribute\(s\) attached to null statement\. Ignoring\." 1 logger -expect-no-warnings read_verilog < Date: Thu, 14 May 2020 16:32:14 -0700 Subject: [PATCH 161/197] test: add attribute-before-stmt test from @nakengelhardt --- tests/verilog/bug2037.ys | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/verilog/bug2037.ys b/tests/verilog/bug2037.ys index eb4f0fac4..4b629ba92 100644 --- a/tests/verilog/bug2037.ys +++ b/tests/verilog/bug2037.ys @@ -41,3 +41,18 @@ module test (); endmodule EOT select -assert-none a:* + + +design -reset +read_verilog < Date: Thu, 21 May 2020 09:46:26 -0700 Subject: [PATCH 162/197] verilog: move attr from simple_behav_stmt to its children to attach --- frontends/verilog/verilog_parser.y | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 475557af9..c8223f41d 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2203,32 +2203,36 @@ assert_property: }; simple_behavioral_stmt: - lvalue '=' delay expr { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4); + attr lvalue '=' delay expr { + AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $5); ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @4); + SET_AST_NODE_LOC(node, @2, @5); + append_attr(node, $1); } | - lvalue TOK_INCREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_ADD, $1->clone(), AstNode::mkconst_int(1, true))); + attr lvalue TOK_INCREMENT { + AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true))); ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @2); + SET_AST_NODE_LOC(node, @2, @3); + append_attr(node, $1); } | - lvalue TOK_DECREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, new AstNode(AST_SUB, $1->clone(), AstNode::mkconst_int(1, true))); + attr lvalue TOK_DECREMENT { + AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_SUB, $2->clone(), AstNode::mkconst_int(1, true))); ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @2); + SET_AST_NODE_LOC(node, @2, @3); + append_attr(node, $1); } | - lvalue OP_LE delay expr { - AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4); + attr lvalue OP_LE delay expr { + AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @1, @4); + SET_AST_NODE_LOC(node, @2, @5); + append_attr(node, $1); }; // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | non_opt_delay behavioral_stmt | - attr simple_behavioral_stmt ';' | + simple_behavioral_stmt ';' | attr ';' { free_attr($1); } | From 5b81df57c8c6779077c69ed8247fce7647616ade Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 25 May 2020 09:47:08 -0700 Subject: [PATCH 163/197] xilinx: tidy up cells_sim.v a little --- techlibs/xilinx/cells_sim.v | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index d87cfe91b..f5850d8a2 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -3387,10 +3387,10 @@ module DSP48E1 ( reg signed [24:0] Dr; reg signed [17:0] Br1, Br2; reg signed [47:0] Cr; - reg [4:0] INMODEr = 5'b0; - reg [6:0] OPMODEr = 7'b0; - reg [3:0] ALUMODEr = 4'b0; - reg [2:0] CARRYINSELr = 3'b0; + reg [4:0] INMODEr; + reg [6:0] OPMODEr; + reg [3:0] ALUMODEr; + reg [2:0] CARRYINSELr; generate // Configurable A register @@ -3572,11 +3572,13 @@ module DSP48E1 ( // Carry in wire A24_xnor_B17d = A_MULT[24] ~^ B_MULT[17]; - reg CARRYINr = 1'b0, A24_xnor_B17 = 1'b0; + reg CARRYINr, A24_xnor_B17; generate + if (CARRYINREG == 1) initial CARRYINr = 1'b0; if (CARRYINREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) CARRYINr <= 1'b0; else if (CECARRYIN) CARRYINr <= CARRYIN; end else always @* CARRYINr = CARRYIN; + if (MREG == 1) initial A24_xnor_B17 = 1'b0; if (MREG == 1) begin always @(posedge CLK) if (RSTALLCARRYIN) A24_xnor_B17 <= 1'b0; else if (CEM) A24_xnor_B17 <= A24_xnor_B17d; end else always @* A24_xnor_B17 = A24_xnor_B17d; endgenerate From 60aa8049157eb4f0417022182aeb8c1581efe404 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 25 May 2020 10:07:58 -0700 Subject: [PATCH 164/197] tests: fix some test warnings --- tests/arch/xilinx/pmgen_xilinx_srl.ys | 2 +- tests/arch/xilinx/xilinx_srl.v | 2 +- tests/various/attrib07_func_call.v | 2 +- tests/various/constmsk_testmap.v | 2 +- tests/various/shregmap.v | 4 ++-- tests/verilog/bug2042-sv.ys | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/arch/xilinx/pmgen_xilinx_srl.ys b/tests/arch/xilinx/pmgen_xilinx_srl.ys index ea2f20487..e76fb20ab 100644 --- a/tests/arch/xilinx/pmgen_xilinx_srl.ys +++ b/tests/arch/xilinx/pmgen_xilinx_srl.ys @@ -1,6 +1,6 @@ read_verilog -icells < Date: Mon, 25 May 2020 09:35:41 -0700 Subject: [PATCH 165/197] tests: xilinx macc test to have initval, shorten BMC depth for runtime --- tests/arch/xilinx/macc.v | 12 ++++++------ tests/arch/xilinx/macc.ys | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/arch/xilinx/macc.v b/tests/arch/xilinx/macc.v index e36b2bab1..1645537fd 100644 --- a/tests/arch/xilinx/macc.v +++ b/tests/arch/xilinx/macc.v @@ -10,10 +10,10 @@ module macc # (parameter SIZEIN = 16, SIZEOUT = 40) ( output signed [SIZEOUT-1:0] accum_out ); // Declare registers for intermediate values -reg signed [SIZEIN-1:0] a_reg, b_reg; -reg sload_reg; -reg signed [2*SIZEIN-1:0] mult_reg; -reg signed [SIZEOUT-1:0] adder_out, old_result; +reg signed [SIZEIN-1:0] a_reg = 0, b_reg = 0; +reg sload_reg = 0; +reg signed [2*SIZEIN-1:0] mult_reg = 0; +reg signed [SIZEOUT-1:0] adder_out = 0, old_result; always @* /*(adder_out or sload_reg)*/ begin // Modification necessary to fix sim/synth mismatch if (sload_reg) old_result <= 0; @@ -50,10 +50,10 @@ module macc2 # (parameter SIZEIN = 16, SIZEOUT = 40) ( output overflow ); // Declare registers for intermediate values -reg signed [SIZEIN-1:0] a_reg, b_reg, a_reg2, b_reg2; +reg signed [SIZEIN-1:0] a_reg = 0, b_reg = 0, a_reg2 = 0, b_reg2 = 0; reg signed [2*SIZEIN-1:0] mult_reg = 0; reg signed [SIZEOUT:0] adder_out = 0; -reg overflow_reg; +reg overflow_reg = 0; always @(posedge clk) begin //if (ce) begin diff --git a/tests/arch/xilinx/macc.ys b/tests/arch/xilinx/macc.ys index bf2b36320..61a570f48 100644 --- a/tests/arch/xilinx/macc.ys +++ b/tests/arch/xilinx/macc.ys @@ -6,7 +6,7 @@ proc #equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad ### TODO equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx -noiopad miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -verify -prove-asserts -seq 10 -show-inputs -show-outputs miter +sat -verify -prove-asserts -seq 3 -show-inputs -show-outputs miter design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd macc # Constrain all select calls below inside the top module select -assert-count 1 t:BUFG @@ -20,7 +20,7 @@ proc #equiv_opt -assert -map +/xilinx/cells_sim.v synth_xilinx -noiopad ### TODO equiv_opt -run :prove -map +/xilinx/cells_sim.v synth_xilinx -noiopad miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -verify -prove-asserts -seq 10 -show-inputs -show-outputs miter +sat -verify -prove-asserts -seq 4 -show-inputs -show-outputs miter design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd macc2 # Constrain all select calls below inside the top module From 721283ac2a5724f72fd24a012c61e87e293f2b8a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 25 May 2020 10:53:49 -0700 Subject: [PATCH 166/197] blackbox: re-use existing Module::makeblackbox() method --- passes/cmds/blackbox.cc | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc index 5c0405f15..b8297cd77 100644 --- a/passes/cmds/blackbox.cc +++ b/passes/cmds/blackbox.cc @@ -48,31 +48,7 @@ struct BlackboxPass : public Pass { for (auto module : design->selected_whole_modules_warn()) { - pool remove_cells; - pool remove_wires; - - for (auto cell : module->cells()) - remove_cells.insert(cell); - - for (auto wire : module->wires()) - if (wire->port_id == 0) - remove_wires.insert(wire); - - for (auto it = module->memories.begin(); it != module->memories.end(); ++it) - delete it->second; - module->memories.clear(); - - for (auto it = module->processes.begin(); it != module->processes.end(); ++it) - delete it->second; - module->processes.clear(); - - module->new_connections(std::vector()); - - for (auto cell : remove_cells) - module->remove(cell); - - module->remove(remove_wires); - + module->makeblackbox(); module->set_bool_attribute(ID::blackbox); } } From 903456c267c84d6d924a96ddf4f2b4e2b5caec4a Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Thu, 30 Apr 2020 21:27:18 +0000 Subject: [PATCH 167/197] qbfsat: Add `-solver` option and allow choice of Z3 or Yices, making Yices the default. Ensures that "BV" is the logic whenever solving an exists-forall problem with Yices, moves the "(set-logic ...)" directive above any non-info line, sets the `ef-max-iters` parameter to a very high number when using Yices in exists-forall mode so as not to prematurely abandon difficult problems, and does not provide the incompatible "--incremental" Yices argument when in exists-forall mode. --- backends/smt2/smtio.py | 10 +++++-- passes/sat/qbfsat.cc | 67 +++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 69f59df79..7cb1e8968 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -172,7 +172,7 @@ class SmtIo: self.unroll = False if self.solver == "yices": - if self.noincr: + if self.noincr or self.forall: self.popen_vargs = ['yices-smt2'] + self.solver_opts else: self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts @@ -232,17 +232,21 @@ class SmtIo: if self.logic_uf: self.logic += "UF" if self.logic_bv: self.logic += "BV" if self.logic_dt: self.logic = "ALL" + if self.solver == "yices" and self.forall: self.logic = "BV" self.setup_done = True - for stmt in self.info_stmts: - self.write(stmt) + if self.forall and self.solver == "yices": + self.write("(set-option :yices-ef-max-iters 1000000000)") if self.produce_models: self.write("(set-option :produce-models true)") self.write("(set-logic %s)" % self.logic) + for stmt in self.info_stmts: + self.write(stmt) + def timestamp(self): secs = int(time() - self.start_time) return "## %3d:%02d:%02d " % (secs // (60*60), (secs // 60) % 60, secs % 60) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index c42760488..5ec20d621 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -41,6 +41,7 @@ struct QbfSolveOptions { bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg; bool nooptimize, nobisection; bool sat, unsat, show_smtbmc; + enum Solver{Z3, Yices} solver; std::string specialize_soln_file; std::string write_soln_soln_file; std::string dump_final_smt2_file; @@ -48,9 +49,19 @@ struct QbfSolveOptions { QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false), nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false), nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false), - argidx(0) {}; + solver(Yices), argidx(0) {}; }; +std::string get_solver_name(const QbfSolveOptions &opt) { + if (opt.solver == opt.Solver::Z3) + return "z3"; + else if (opt.solver == opt.Solver::Yices) + return "yices"; + else + log_cmd_error("unknown solver specified.\n"); + return ""; +} + void recover_solution(QbfSolutionType &sol) { YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED"); YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available"); @@ -315,19 +326,18 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, QbfSolutionType ret; const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc"; const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2"; - const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s z3 -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; const std::string smtbmc_warning = "z3: WARNING:"; - const bool show_smtbmc = opt.show_smtbmc; + const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (get_solver_name(opt)) + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; Pass::call(mod->design, smt2_command); - auto process_line = [&ret, &smtbmc_warning, &show_smtbmc, &quiet](const std::string &line) { + auto process_line = [&ret, &smtbmc_warning, &opt, &quiet](const std::string &line) { ret.stdout_lines.push_back(line.substr(0, line.size()-1)); //don't include trailing newline auto warning_pos = line.find(smtbmc_warning); if (warning_pos != std::string::npos) log_warning("%s", line.substr(warning_pos + smtbmc_warning.size() + 1).c_str()); else - if (show_smtbmc && !quiet) + if (opt.show_smtbmc && !quiet) log("smtbmc output: %s", line.c_str()); }; log_header(mod->design, "Solving QBF-SAT problem.\n"); @@ -486,6 +496,20 @@ QbfSolveOptions parse_args(const std::vector &args) { opt.nobisection = true; continue; } + else if (args[opt.argidx] == "-solver") { + if (args.size() <= opt.argidx + 1) + log_cmd_error("solver not specified.\n"); + else { + if (args[opt.argidx+1] == "z3") + opt.solver = opt.Solver::Z3; + else if (args[opt.argidx+1] == "yices") + opt.solver = opt.Solver::Yices; + else + log_cmd_error("Unknown solver \"%s\".\n", args[opt.argidx+1].c_str()); + opt.argidx++; + } + continue; + } else if (args[opt.argidx] == "-sat") { opt.sat = true; continue; @@ -563,21 +587,20 @@ struct QbfSatPass : public Pass { log("\n"); log(" qbfsat [options] [selection]\n"); log("\n"); - log("This command solves a 2QBF-SAT problem defined over the currently selected module.\n"); - log("Existentially-quantified variables are declared by assigning a wire \"$anyconst\".\n"); - log("Universally-quantified variables may be explicitly declared by assigning a wire\n"); - log("\"$allconst\", but module inputs will be treated as universally-quantified variables\n"); - log("by default.\n"); + log("This command solves an \"exists-forall\" 2QBF-SAT problem defined over the currently\n"); + log("selected module. Existentially-quantified variables are declared by assigning a wire\n"); + log("\"$anyconst\". Universally-quantified variables may be explicitly declared by assigning\n"); + log("a wire \"$allconst\", but module inputs will be treated as universally-quantified\n"); + log("variables by default.\n"); log("\n"); log(" -nocleanup\n"); - log(" Do not delete temporary files and directories. Useful for\n"); - log(" debugging.\n"); + log(" Do not delete temporary files and directories. Useful for debugging.\n"); log("\n"); log(" -dump-final-smt2 \n"); log(" Pass the --dump-smt2 option to yosys-smtbmc.\n"); log("\n"); log(" -assume-outputs\n"); - log(" Add an $assume cell for the conjunction of all one-bit module output wires.\n"); + log(" Add an \"$assume\" cell for the conjunction of all one-bit module output wires.\n"); log("\n"); log(" -assume-negative-polarity\n"); log(" When adding $assume cells for one-bit module output wires, assume they are\n"); @@ -586,15 +609,18 @@ struct QbfSatPass : public Pass { log("\n"); log(" -nooptimize\n"); log(" Ignore \"\\minimize\" and \"\\maximize\" attributes, do not emit \"(maximize)\" or\n"); - log(" \"(minimize)\" in the SMTLIBv2, and generally make no attempt to optimize anything.\n"); + log(" \"(minimize)\" in the SMT-LIBv2, and generally make no attempt to optimize anything.\n"); log("\n"); log(" -nobisection\n"); log(" If a wire is marked with the \"\\minimize\" or \"\\maximize\" attribute, do not\n"); log(" attempt to optimize that value with the default iterated solving and threshold\n"); log(" bisection approach. Instead, have yosys-smtbmc emit a \"(minimize)\" or \"(maximize)\"\n"); - log(" command in the SMTLIBv2 output and hope that the solver supports optimizing\n"); + log(" command in the SMT-LIBv2 output and hope that the solver supports optimizing\n"); log(" quantified bitvector problems.\n"); log("\n"); + log(" -solver \n"); + log(" Use a particular solver. Choose one of: \"z3\", \"yices\".\n"); + log("\n"); log(" -sat\n"); log(" Generate an error if the solver does not return \"sat\".\n"); log("\n"); @@ -605,15 +631,16 @@ struct QbfSatPass : public Pass { log(" Print the output from yosys-smtbmc.\n"); log("\n"); log(" -specialize\n"); - log(" Replace all \"$anyconst\" cells with constant values determined by the solver.\n"); + log(" If the problem is satisfiable, replace each \"$anyconst\" cell with its\n"); + log(" corresponding constant value from the model produced by the solver.\n"); log("\n"); log(" -specialize-from-file \n"); - log(" Do not run the solver, but instead only attempt to replace all \"$anyconst\"\n"); - log(" cells in the current module with values provided by the specified file.\n"); + log(" Do not run the solver, but instead only attempt to replace each \"$anyconst\"\n"); + log(" cell in the current module with a constant value provided by the specified file.\n"); log("\n"); log(" -write-solution \n"); - log(" Write the assignments discovered by the solver for all \"$anyconst\" cells\n"); - log(" to the specified file."); + log(" If the problem is satisfiable, write the corresponding constant value for each\n"); + log(" \"$anyconst\" cell from the model produced by the solver to the specified file."); log("\n"); log("\n"); } From 54570a39780f750aa7bfd616f12c58bcf121bbdf Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 25 May 2020 20:32:13 +0000 Subject: [PATCH 168/197] qbfsat: Move SMT2 info statements back to the top of the file. --- backends/smt2/smtio.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 7cb1e8968..62dfe7c11 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -236,6 +236,9 @@ class SmtIo: self.setup_done = True + for stmt in self.info_stmts: + self.write(stmt) + if self.forall and self.solver == "yices": self.write("(set-option :yices-ef-max-iters 1000000000)") @@ -244,9 +247,6 @@ class SmtIo: self.write("(set-logic %s)" % self.logic) - for stmt in self.info_stmts: - self.write(stmt) - def timestamp(self): secs = int(time() - self.start_time) return "## %3d:%02d:%02d " % (secs // (60*60), (secs // 60) % 60, secs % 60) From f9eef5e3f710684c8cfe5430190b5cf4f7c2e34e Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 1 May 2020 08:12:23 +0000 Subject: [PATCH 169/197] qbfsat: Add support for CVC4. --- passes/sat/qbfsat.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 5ec20d621..712a46cbc 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -41,7 +41,7 @@ struct QbfSolveOptions { bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg; bool nooptimize, nobisection; bool sat, unsat, show_smtbmc; - enum Solver{Z3, Yices} solver; + enum Solver{Z3, Yices, CVC4} solver; std::string specialize_soln_file; std::string write_soln_soln_file; std::string dump_final_smt2_file; @@ -57,6 +57,8 @@ std::string get_solver_name(const QbfSolveOptions &opt) { return "z3"; else if (opt.solver == opt.Solver::Yices) return "yices"; + else if (opt.solver == opt.Solver::CVC4) + return "cvc4"; else log_cmd_error("unknown solver specified.\n"); return ""; @@ -504,6 +506,8 @@ QbfSolveOptions parse_args(const std::vector &args) { opt.solver = opt.Solver::Z3; else if (args[opt.argidx+1] == "yices") opt.solver = opt.Solver::Yices; + else if (args[opt.argidx+1] == "cvc4") + opt.solver = opt.Solver::CVC4; else log_cmd_error("Unknown solver \"%s\".\n", args[opt.argidx+1].c_str()); opt.argidx++; @@ -619,7 +623,7 @@ struct QbfSatPass : public Pass { log(" quantified bitvector problems.\n"); log("\n"); log(" -solver \n"); - log(" Use a particular solver. Choose one of: \"z3\", \"yices\".\n"); + log(" Use a particular solver. Choose one of: \"z3\", \"yices\", and \"cvc4\".\n"); log("\n"); log(" -sat\n"); log(" Generate an error if the solver does not return \"sat\".\n"); From 9847a4eea8b6d758c06d3d95f2bfe84c57774364 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 1 May 2020 23:17:35 +0000 Subject: [PATCH 170/197] smtbmc and qbfsat: Add timeout option to set solver timeouts for Z3, Yices, and CVC4. --- backends/smt2/smtbmc.py | 5 ++-- backends/smt2/smtio.py | 35 ++++++++++++++++++++-- passes/sat/qbfsat.cc | 66 +++++++++++++++++++++++++++++++++-------- 3 files changed, 88 insertions(+), 18 deletions(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index cc3ebb129..03f001bfd 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1557,8 +1557,9 @@ else: # not tempind, covermode smt_assert(get_constr_expr(constr_asserts, i)) print_msg("Solving for step %d.." % (last_check_step)) - if smt_check_sat() != "sat": - print("%s No solution found!" % smt.timestamp()) + status = smt_check_sat() + if status != "sat": + print("%s No solution found! (%s)" % (smt.timestamp(), status)) retstatus = "FAILED" break diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 62dfe7c11..d24fbf809 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -121,6 +121,7 @@ class SmtIo: self.logic_bv = True self.logic_dt = False self.forall = False + self.timeout = 0 self.produce_models = True self.smt2cache = [list()] self.p = None @@ -135,6 +136,7 @@ class SmtIo: self.debug_file = opts.debug_file self.dummy_file = opts.dummy_file self.timeinfo = opts.timeinfo + self.timeout = opts.timeout self.unroll = opts.unroll self.noincr = opts.noincr self.info_stmts = opts.info_stmts @@ -147,6 +149,7 @@ class SmtIo: self.debug_file = None self.dummy_file = None self.timeinfo = os.name != "nt" + self.timeout = 0 self.unroll = False self.noincr = False self.info_stmts = list() @@ -176,18 +179,28 @@ class SmtIo: self.popen_vargs = ['yices-smt2'] + self.solver_opts else: self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts + if self.timeout != 0: + self.popen_vargs.append('-t') + self.popen_vargs.append('%d' % self.timeout); if self.solver == "z3": self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts + if self.timeout != 0: + self.popen_vargs.append('-T:%d' % self.timeout); if self.solver == "cvc4": if self.noincr: self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts else: self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts + if self.timeout != 0: + self.popen_vargs.append('--tlimit=%d000' % self.timeout); if self.solver == "mathsat": self.popen_vargs = ['mathsat'] + self.solver_opts + if self.timeout != 0: + print('timeout option is not supported for mathsat.') + sys.exit(1) if self.solver == "boolector": if self.noincr: @@ -195,6 +208,9 @@ class SmtIo: else: self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts self.unroll = True + if self.timeout != 0: + print('timeout option is not supported for boolector.') + sys.exit(1) if self.solver == "abc": if len(self.solver_opts) > 0: @@ -204,6 +220,9 @@ class SmtIo: self.logic_ax = False self.unroll = True self.noincr = True + if self.timeout != 0: + print('timeout option is not supported for abc.') + sys.exit(1) if self.solver == "dummy": assert self.dummy_file is not None @@ -449,6 +468,10 @@ class SmtIo: fields = stmt.split() + if fields[1] == "yosys-smt2-timeout": + self.timeout = int(fields[2]) + assert self.timeout > 0 + if fields[1] == "yosys-smt2-nomem": if self.logic is None: self.logic_ax = False @@ -710,7 +733,7 @@ class SmtIo: if self.forall: result = self.read() - while result not in ["sat", "unsat", "unknown"]: + while result not in ["sat", "unsat", "unknown", "timeout", "interrupted", ""]: print("%s %s: %s" % (self.timestamp(), self.solver, result)) result = self.read() else: @@ -721,7 +744,7 @@ class SmtIo: print("(check-sat)", file=self.debug_file) self.debug_file.flush() - if result not in ["sat", "unsat"]: + if result not in ["sat", "unsat", "unknown", "timeout", "interrupted"]: if result == "": print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True) else: @@ -931,7 +954,7 @@ class SmtIo: class SmtOpts: def __init__(self): self.shortopts = "s:S:v" - self.longopts = ["unroll", "noincr", "noprogress", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"] + self.longopts = ["unroll", "noincr", "noprogress", "timeout=", "dump-smt2=", "logic=", "dummy=", "info=", "nocomments"] self.solver = "yices" self.solver_opts = list() self.debug_print = False @@ -940,6 +963,7 @@ class SmtOpts: self.unroll = False self.noincr = False self.timeinfo = os.name != "nt" + self.timeout = 0 self.logic = None self.info_stmts = list() self.nocomments = False @@ -949,6 +973,8 @@ class SmtOpts: self.solver = a elif o == "-S": self.solver_opts.append(a) + elif o == "--timeout": + self.timeout = int(a) elif o == "-v": self.debug_print = True elif o == "--unroll": @@ -980,6 +1006,9 @@ class SmtOpts: -S pass as command line argument to the solver + --timeout + set the solver timeout to the specified value (in seconds). + --logic use the specified SMT2 logic (e.g. QF_AUFBV) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 712a46cbc..d6dbf8ef4 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -42,6 +42,7 @@ struct QbfSolveOptions { bool nooptimize, nobisection; bool sat, unsat, show_smtbmc; enum Solver{Z3, Yices, CVC4} solver; + int timeout; std::string specialize_soln_file; std::string write_soln_soln_file; std::string dump_final_smt2_file; @@ -49,7 +50,7 @@ struct QbfSolveOptions { QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false), nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false), nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false), - solver(Yices), argidx(0) {}; + solver(Yices), timeout(0), argidx(0) {}; }; std::string get_solver_name(const QbfSolveOptions &opt) { @@ -67,6 +68,11 @@ std::string get_solver_name(const QbfSolveOptions &opt) { void recover_solution(QbfSolutionType &sol) { YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED"); YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available"); + YS_REGEX_TYPE unsat_regex2 = YS_REGEX_COMPILE("Status: FAILED"); + YS_REGEX_TYPE timeout_regex = YS_REGEX_COMPILE("No solution found! \\(timeout\\)"); + YS_REGEX_TYPE timeout_regex2 = YS_REGEX_COMPILE("No solution found! \\(interrupted\\)"); + YS_REGEX_TYPE unknown_regex = YS_REGEX_COMPILE("No solution found! \\(unknown\\)"); + YS_REGEX_TYPE unknown_regex2 = YS_REGEX_COMPILE("Unexpected EOF response from solver"); YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\""); YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)"); #ifndef NDEBUG @@ -87,14 +93,40 @@ void recover_solution(QbfSolutionType &sol) { #endif sol.hole_to_value[loc] = val; } - else if (YS_REGEX_NS::regex_search(x, sat_regex)) + else if (YS_REGEX_NS::regex_search(x, sat_regex)) { sat_regex_found = true; - else if (YS_REGEX_NS::regex_search(x, unsat_regex)) + sol.sat = true; + sol.unknown = false; + } + else if (YS_REGEX_NS::regex_search(x, unsat_regex)) { unsat_regex_found = true; + sol.sat = false; + sol.unknown = false; + } else if (YS_REGEX_NS::regex_search(x, memout_regex)) { sol.unknown = true; log_warning("solver ran out of memory\n"); } + else if (YS_REGEX_NS::regex_search(x, timeout_regex)) { + sol.unknown = true; + log_warning("solver timed out\n"); + } + else if (YS_REGEX_NS::regex_search(x, timeout_regex2)) { + sol.unknown = true; + log_warning("solver timed out\n"); + } + else if (YS_REGEX_NS::regex_search(x, unknown_regex)) { + sol.unknown = true; + log_warning("solver returned \"unknown\"\n"); + } + else if (YS_REGEX_NS::regex_search(x, unsat_regex2)) { + unsat_regex_found = true; + sol.sat = false; + sol.unknown = false; + } + else if (YS_REGEX_NS::regex_search(x, unknown_regex2)) { + sol.unknown = true; + } } #ifndef NDEBUG log_assert(!sol.unknown && sol.sat? sat_regex_found : true); @@ -329,7 +361,7 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc"; const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2"; const std::string smtbmc_warning = "z3: WARNING:"; - const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (get_solver_name(opt)) + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; + const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (get_solver_name(opt)) + (opt.timeout != 0? stringf(" --timeout %d", opt.timeout) : "") + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; Pass::call(mod->design, smt2_command); @@ -344,14 +376,7 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, }; log_header(mod->design, "Solving QBF-SAT problem.\n"); if (!quiet) log("Launching \"%s\".\n", smtbmc_cmd.c_str()); - int retval = run_command(smtbmc_cmd, process_line); - if (retval == 0) { - ret.sat = true; - ret.unknown = false; - } else if (retval == 1) { - ret.sat = false; - ret.unknown = false; - } + run_command(smtbmc_cmd, process_line); recover_solution(ret); return ret; @@ -514,6 +539,19 @@ QbfSolveOptions parse_args(const std::vector &args) { } continue; } + else if (args[opt.argidx] == "-timeout") { + if (args.size() <= opt.argidx + 1) + log_cmd_error("timeout not specified.\n"); + else { + int timeout = atoi(args[opt.argidx+1].c_str()); + if (timeout > 0) + opt.timeout = timeout; + else + log_cmd_error("timeout must be greater than 0.\n"); + opt.argidx++; + } + continue; + } else if (args[opt.argidx] == "-sat") { opt.sat = true; continue; @@ -625,6 +663,9 @@ struct QbfSatPass : public Pass { log(" -solver \n"); log(" Use a particular solver. Choose one of: \"z3\", \"yices\", and \"cvc4\".\n"); log("\n"); + log(" -timeout \n"); + log(" Set the per-iteration timeout in seconds.\n"); + log("\n"); log(" -sat\n"); log(" Generate an error if the solver does not return \"sat\".\n"); log("\n"); @@ -672,7 +713,6 @@ struct QbfSatPass : public Pass { QbfSolutionType ret = qbf_solve(module, opt); module = design->module(module_name); if (ret.unknown) { - log_warning("solver did not give an answer\n"); if (opt.sat || opt.unsat) log_cmd_error("expected problem to be %s\n", opt.sat? "SAT" : "UNSAT"); } From 8f87ccec9b6ed3c9bb8280830b506b28324a60d8 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Tue, 26 May 2020 11:51:06 +0100 Subject: [PATCH 171/197] Use c_str(), not str() for IdString/std::string == and != operators These operators work by fetching the string from the global string table and then comparing with the std::string that was passed in as rhs. Using str() means that we create a std::string (strlen; malloc; memcpy), compare for equality (another memcmp if they have the same length) and then finally free the string. Using c_str() means that we pass the const char* straight to std::string's equality operator. This ends up as a call to std::string::compare (the const char* flavour), which is essentially strcmp. --- kernel/rtlil.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 11c45bbec..10bfc13f2 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -296,8 +296,8 @@ namespace RTLIL // The methods below are just convenience functions for better compatibility with std::string. - bool operator==(const std::string &rhs) const { return str() == rhs; } - bool operator!=(const std::string &rhs) const { return str() != rhs; } + bool operator==(const std::string &rhs) const { return c_str() == rhs; } + bool operator!=(const std::string &rhs) const { return c_str() != rhs; } bool operator==(const char *rhs) const { return strcmp(c_str(), rhs) == 0; } bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } From 17b5f23f20d6cadc8ce6220e457880720aae4866 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 22 May 2020 16:59:24 +0100 Subject: [PATCH 172/197] Use default copy constructor for RTLIL::SigBit There was a handwritten copy constructor, which I'm not sure was actually legal C++ (it unconditionally read from the 'data' member of a union, which wouldn't have been written if wire was true). It was also a bit less efficient than the constructor you get from the compiler by default (which is allowed to just copy the memory). This gives a marginal (~0.25%) decrease in code size when compiled with GCC 9.3. --- kernel/rtlil.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 11c45bbec..4a23a2d06 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -721,7 +721,7 @@ struct RTLIL::SigBit SigBit(const RTLIL::SigChunk &chunk); SigBit(const RTLIL::SigChunk &chunk, int index); SigBit(const RTLIL::SigSpec &sig); - SigBit(const RTLIL::SigBit &sigbit); + SigBit(const RTLIL::SigBit &sigbit) = default; RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default; bool operator <(const RTLIL::SigBit &other) const; @@ -1494,7 +1494,6 @@ inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_as inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } -inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){ if (wire) offset = sigbit.offset; } inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { if (wire == other.wire) From 7ff306ccdb47415e3a483adad87076327399434f Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Tue, 26 May 2020 15:19:39 +0100 Subject: [PATCH 173/197] Minor optimisation in Module::wire() and Module::cell() The existing code does a search to figure out whether id is in the dict (with the call to count()), and then looks it up again to get the result (with the call to at()). This version calls find() instead, avoiding the double lookup. Code size increases slightly (6kb). I think this is because the contents of find() are getting inlined, and then inlined into lots of the callsites for cell() and wire(). Looking at the compiled code before this patch, you just get a (non-inlined) call to count() followed by a call to at(). After the patch, the contents of find() have been inlined (so you see do_hash, then do_lookup). The result for each function is about 30 bytes / 40% bigger, which presumably also enlarges call-sites that inline it. --- kernel/rtlil.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 11c45bbec..76c5b5304 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1134,8 +1134,14 @@ public: return design->selected_member(name, member->name); } - RTLIL::Wire* wire(RTLIL::IdString id) { return wires_.count(id) ? wires_.at(id) : nullptr; } - RTLIL::Cell* cell(RTLIL::IdString id) { return cells_.count(id) ? cells_.at(id) : nullptr; } + RTLIL::Wire* wire(RTLIL::IdString id) { + auto it = wires_.find(id); + return it == wires_.end() ? nullptr : it->second; + } + RTLIL::Cell* cell(RTLIL::IdString id) { + auto it = cells_.find(id); + return it == cells_.end() ? nullptr : it->second; + } RTLIL::ObjRange wires() { return RTLIL::ObjRange(&wires_, &refcount_wires_); } RTLIL::ObjRange cells() { return RTLIL::ObjRange(&cells_, &refcount_cells_); } From 6aa0f72ae9e47c81441a2cecef18b7f90671ec6d Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 22 May 2020 14:29:42 +0100 Subject: [PATCH 174/197] Silence spurious warning in Verilog lexer when compiling with GCC The chosen value shouldn't have any effect. I considered something clearly wrong like -1, but there's no checking inside the generated lexer, and I suspect this will cause even weirder bugs if triggered than just setting it to INITIAL. --- frontends/verilog/verilog_lexer.l | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index f6a3ac4db..65a2e9a78 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -128,7 +128,9 @@ static bool isUserType(std::string &s) %x BASED_CONST %% - int comment_caller; + // Initialise comment_caller to something to avoid a "maybe undefined" + // warning from GCC. + int comment_caller = INITIAL; "`file_push "[^\n]* { fn_stack.push_back(current_filename); From e9c07e2bdad6baa550b8fcf460ac624bd1879415 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 May 2020 06:00:40 +0000 Subject: [PATCH 175/197] cxxrtl: add missing parts of commit 281c9685. --- backends/cxxrtl/cxxrtl.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc index 549404184..998fe8dbc 100644 --- a/backends/cxxrtl/cxxrtl.cc +++ b/backends/cxxrtl/cxxrtl.cc @@ -513,7 +513,6 @@ struct CxxrtlWorker { bool elide_public = false; bool localize_internal = false; bool localize_public = false; - bool run_opt_clean_purge = false; bool run_proc_flatten = false; bool max_opt_level = false; @@ -2046,7 +2045,7 @@ struct CxxrtlWorker { } if (has_feedback_arcs || has_buffered_wires) { // Although both non-feedback buffered combinatorial wires and apparent feedback wires may be eliminated - // by optimizing the design, if after `opt_clean -purge` there are any feedback wires remaining, it is very + // by optimizing the design, if after `proc; flatten` there are any feedback wires remaining, it is very // likely that these feedback wires are indicative of a true logic loop, so they get emphasized in the message. const char *why_pessimistic = nullptr; if (has_feedback_arcs) @@ -2106,15 +2105,13 @@ struct CxxrtlWorker { if (has_sync_init || has_packed_mem) check_design(design, has_sync_init, has_packed_mem); log_assert(!(has_sync_init || has_packed_mem)); - if (run_opt_clean_purge) - Pass::call(design, "opt_clean -purge"); log_pop(); analyze_design(design); } }; struct CxxrtlBackend : public Backend { - static const int DEFAULT_OPT_LEVEL = 6; + static const int DEFAULT_OPT_LEVEL = 5; CxxrtlBackend() : Backend("cxxrtl", "convert design to C++ RTL simulation") { } void help() YS_OVERRIDE @@ -2340,6 +2337,7 @@ struct CxxrtlBackend : public Backend { extra_args(f, filename, args, argidx); switch (opt_level) { + // the highest level here must match DEFAULT_OPT_LEVEL case 5: worker.max_opt_level = true; worker.run_proc_flatten = true; From 0bf6b164be05e8dc0cb6d129455d38121f625da0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 May 2020 21:37:32 +0000 Subject: [PATCH 176/197] cxxrtl: make logging a little bit nicer. --- backends/cxxrtl/cxxrtl.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc index 998fe8dbc..0cceecbba 100644 --- a/backends/cxxrtl/cxxrtl.cc +++ b/backends/cxxrtl/cxxrtl.cc @@ -2008,6 +2008,7 @@ struct CxxrtlWorker { log("Module `%s' contains feedback arcs through wires:\n", log_id(module)); for (auto wire : feedback_wires) log(" %s\n", log_id(wire)); + log("\n"); } for (auto wire : module->wires()) { @@ -2039,6 +2040,7 @@ struct CxxrtlWorker { log("Module `%s' contains buffered combinatorial wires:\n", log_id(module)); for (auto wire : buffered_wires) log(" %s\n", log_id(wire)); + log("\n"); } eval_converges[module] = feedback_wires.empty() && buffered_wires.empty(); @@ -2052,7 +2054,6 @@ struct CxxrtlWorker { why_pessimistic = "feedback wires"; else if (has_buffered_wires) why_pessimistic = "buffered combinatorial wires"; - log("\n"); log_warning("Design contains %s, which require delta cycles during evaluation.\n", why_pessimistic); if (!max_opt_level) log("Increasing the optimization level may eliminate %s from the design.\n", why_pessimistic); @@ -2086,26 +2087,33 @@ struct CxxrtlWorker { void prepare_design(RTLIL::Design *design) { + bool did_anything = false; bool has_sync_init, has_packed_mem; log_push(); check_design(design, has_sync_init, has_packed_mem); if (run_proc_flatten) { Pass::call(design, "proc"); Pass::call(design, "flatten"); + did_anything = true; } else if (has_sync_init) { // We're only interested in proc_init, but it depends on proc_prune and proc_clean, so call those // in case they weren't already. (This allows `yosys foo.v -o foo.cc` to work.) Pass::call(design, "proc_prune"); Pass::call(design, "proc_clean"); Pass::call(design, "proc_init"); + did_anything = true; } - if (has_packed_mem) + if (has_packed_mem) { Pass::call(design, "memory_unpack"); + did_anything = true; + } // Recheck the design if it was modified. if (has_sync_init || has_packed_mem) check_design(design, has_sync_init, has_packed_mem); log_assert(!(has_sync_init || has_packed_mem)); log_pop(); + if (did_anything) + log_spacer(); analyze_design(design); } }; From b8365547e9ba1fb018ba66d519d6f02d6d7580a6 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Wed, 27 May 2020 04:07:34 +0000 Subject: [PATCH 177/197] misc: Add `printattrs` command. --- passes/cmds/Makefile.inc | 1 + passes/cmds/printattrs.cc | 79 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 passes/cmds/printattrs.cc diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index a88980eaf..53bfd40c6 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -39,3 +39,4 @@ OBJS += passes/cmds/bugpoint.o endif OBJS += passes/cmds/scratchpad.o OBJS += passes/cmds/logger.o +OBJS += passes/cmds/printattrs.o diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc new file mode 100644 index 000000000..78cf1eeff --- /dev/null +++ b/passes/cmds/printattrs.cc @@ -0,0 +1,79 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Alberto Gonzalez + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct PrintAttrsPass : public Pass { + PrintAttrsPass() : Pass("printattrs", "print attributes of selected objects") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" printattrs [selection]\n"); + log("\n"); + log("Print all attributes of the selected objects.\n"); + log("\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + size_t argidx = 1; + extra_args(args, argidx, design); + + unsigned int indent = 0; + for (auto mod : design->selected_modules()) + { + + if (design->selected_whole_module(mod)) { + log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(mod->name)); + indent += 2; + for (auto &it : mod->attributes) + log("%s(* %s=\"%s\" %s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(it.first), it.second.decode_string().c_str(), it.second.as_string().c_str()); + } + + for (auto cell : mod->selected_cells()) { + log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(cell->name)); + indent += 2; + for (auto &it : cell->attributes) { + log("%s(* %s=\"%s\" %s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(it.first), it.second.decode_string().c_str(), it.second.as_string().c_str()); + } + indent -= 2; + } + + for (auto wire : mod->selected_wires()) { + log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(wire->name)); + indent += 2; + for (auto &it : wire->attributes) { + log("%s(* %s=\"%s\" %s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(it.first), it.second.decode_string().c_str(), it.second.as_string().c_str()); + } + indent -= 2; + } + + if (design->selected_whole_module(mod)) + indent -= 2; + } + + log("\n"); + } +} PrintAttrsPass; + +PRIVATE_NAMESPACE_END From e50e4ee285e8c3989cdf983640451aebd7e6e152 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Wed, 27 May 2020 07:40:40 +0000 Subject: [PATCH 178/197] printattrs: Use `flags` to pretty-print the `RTLIL::Const` appropriately. Co-Authored-By: whitequark --- passes/cmds/printattrs.cc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc index 78cf1eeff..7f86823e3 100644 --- a/passes/cmds/printattrs.cc +++ b/passes/cmds/printattrs.cc @@ -34,6 +34,16 @@ struct PrintAttrsPass : public Pass { log("\n"); log("\n"); } + + static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) { + if (x.flags == RTLIL::CONST_FLAG_STRING) + log("%s(* %s=\"%s\" *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(s), x.decode_string().c_str()); + else if (x.flags == RTLIL::CONST_FLAG_NONE) + log("%s(* %s=%s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(s), x.as_string().c_str()); + else + log_assert(x.flags == RTLIL::CONST_FLAG_STRING || x.flags == RTLIL::CONST_FLAG_NONE); //intended to fail + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx = 1; @@ -42,29 +52,26 @@ struct PrintAttrsPass : public Pass { unsigned int indent = 0; for (auto mod : design->selected_modules()) { - if (design->selected_whole_module(mod)) { log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(mod->name)); indent += 2; for (auto &it : mod->attributes) - log("%s(* %s=\"%s\" %s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(it.first), it.second.decode_string().c_str(), it.second.as_string().c_str()); + log_const(it.first, it.second, indent); } for (auto cell : mod->selected_cells()) { log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(cell->name)); indent += 2; - for (auto &it : cell->attributes) { - log("%s(* %s=\"%s\" %s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(it.first), it.second.decode_string().c_str(), it.second.as_string().c_str()); - } + for (auto &it : cell->attributes) + log_const(it.first, it.second, indent); indent -= 2; } for (auto wire : mod->selected_wires()) { log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(wire->name)); indent += 2; - for (auto &it : wire->attributes) { - log("%s(* %s=\"%s\" %s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(it.first), it.second.decode_string().c_str(), it.second.as_string().c_str()); - } + for (auto &it : wire->attributes) + log_const(it.first, it.second, indent); indent -= 2; } From 6228b10c9f354afaa009491b061583e8a686fbd8 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Wed, 27 May 2020 07:58:10 +0000 Subject: [PATCH 179/197] printattrs: Add test. --- tests/various/printattr.ys | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/various/printattr.ys diff --git a/tests/various/printattr.ys b/tests/various/printattr.ys new file mode 100644 index 000000000..afc6d8eb6 --- /dev/null +++ b/tests/various/printattr.ys @@ -0,0 +1,14 @@ +logger -expect log ".*cells_not_processed=[01]* .*" 1 +logger -expect log ".*src=.< Date: Wed, 27 May 2020 23:15:07 +0000 Subject: [PATCH 180/197] printattrs: Refactor indentation string building for clarity. Co-Authored-By: whitequark --- passes/cmds/printattrs.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc index 7f86823e3..d4d57fd85 100644 --- a/passes/cmds/printattrs.cc +++ b/passes/cmds/printattrs.cc @@ -35,11 +35,17 @@ struct PrintAttrsPass : public Pass { log("\n"); } + static std::string get_indent_str(const unsigned int indent) { + //Build the format string (e.g. "%4s") + std::string format_str = stringf("%%%ds", indent); + return stringf(format_str.c_str(), " "); //Use the format string with " " as %s + } + static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) { if (x.flags == RTLIL::CONST_FLAG_STRING) - log("%s(* %s=\"%s\" *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(s), x.decode_string().c_str()); + log("%s(* %s=\"%s\" *)\n", get_indent_str(indent).c_str(), log_id(s), x.decode_string().c_str()); else if (x.flags == RTLIL::CONST_FLAG_NONE) - log("%s(* %s=%s *)\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(s), x.as_string().c_str()); + log("%s(* %s=%s *)\n", get_indent_str(indent).c_str(), log_id(s), x.as_string().c_str()); else log_assert(x.flags == RTLIL::CONST_FLAG_STRING || x.flags == RTLIL::CONST_FLAG_NONE); //intended to fail } @@ -53,14 +59,14 @@ struct PrintAttrsPass : public Pass { for (auto mod : design->selected_modules()) { if (design->selected_whole_module(mod)) { - log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(mod->name)); + log("%s%s\n", get_indent_str(indent).c_str(), log_id(mod->name)); indent += 2; for (auto &it : mod->attributes) log_const(it.first, it.second, indent); } for (auto cell : mod->selected_cells()) { - log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(cell->name)); + log("%s%s\n", get_indent_str(indent).c_str(), log_id(cell->name)); indent += 2; for (auto &it : cell->attributes) log_const(it.first, it.second, indent); @@ -68,7 +74,7 @@ struct PrintAttrsPass : public Pass { } for (auto wire : mod->selected_wires()) { - log("%s%s\n", stringf(stringf("%%%ds", indent).c_str(), " ").c_str(), log_id(wire->name)); + log("%s%s\n", get_indent_str(indent).c_str(), log_id(wire->name)); indent += 2; for (auto &it : wire->attributes) log_const(it.first, it.second, indent); From 5896ffd56f8d0653c9f7a71f18570d093fe669e8 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Thu, 28 May 2020 05:30:00 +0000 Subject: [PATCH 181/197] printattrs: Simplify `get_indent_str()`. Co-Authored-By: Xiretza --- passes/cmds/printattrs.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/passes/cmds/printattrs.cc b/passes/cmds/printattrs.cc index d4d57fd85..80dbfa259 100644 --- a/passes/cmds/printattrs.cc +++ b/passes/cmds/printattrs.cc @@ -36,9 +36,7 @@ struct PrintAttrsPass : public Pass { } static std::string get_indent_str(const unsigned int indent) { - //Build the format string (e.g. "%4s") - std::string format_str = stringf("%%%ds", indent); - return stringf(format_str.c_str(), " "); //Use the format string with " " as %s + return stringf("%*s", indent, ""); } static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) { From 1158bbf7dbd4d6c6efea1622ff72592d13b2f607 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Thu, 28 May 2020 11:39:44 +0100 Subject: [PATCH 182/197] Fix small typos in documentation for hierarchy command --- passes/hierarchy/hierarchy.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 95d74d1eb..f99d1509d 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -574,9 +574,9 @@ struct HierarchyPass : public Pass { log("\n"); log("In parametric designs, a module might exists in several variations with\n"); log("different parameter values. This pass looks at all modules in the current\n"); - log("design an re-runs the language frontends for the parametric modules as\n"); + log("design and re-runs the language frontends for the parametric modules as\n"); log("needed. It also resolves assignments to wired logic data types (wand/wor),\n"); - log("resolves positional module parameters, unroll array instances, and more.\n"); + log("resolves positional module parameters, unrolls array instances, and more.\n"); log("\n"); log(" -check\n"); log(" also check the design hierarchy. this generates an error when\n"); From 17163cf43a6b6eec9aac44f6a4463dda54b8ed68 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 8 Apr 2020 19:30:47 +0200 Subject: [PATCH 183/197] Add flooring modulo operator The $div and $mod cells use truncating division semantics (rounding towards 0), as defined by e.g. Verilog. Another rounding mode, flooring (rounding towards negative infinity), can be used in e.g. VHDL. The new $modfloor cell provides this flooring modulo (also known as "remainder" in several languages, but this name is ambiguous). This commit also fixes the handling of $mod in opt_expr, which was previously optimized as if it was $modfloor. --- backends/btor/btor.cc | 14 +++-- backends/btor/test_cells.sh | 2 +- backends/firrtl/firrtl.cc | 1 + backends/smt2/smt2.cc | 10 ++++ backends/smv/smv.cc | 5 +- backends/smv/test_cells.sh | 4 +- backends/verilog/verilog_backend.cc | 34 +++++++++++++ kernel/calc.cc | 25 +++++++++ kernel/celledges.cc | 2 +- kernel/celltypes.h | 3 +- kernel/rtlil.cc | 3 +- kernel/rtlil.h | 3 ++ kernel/satgen.h | 31 +++++++---- manual/PRESENTATION_Prog.tex | 2 +- passes/cmds/stat.cc | 2 +- passes/memory/memory_share.cc | 1 + passes/opt/opt_expr.cc | 33 ++++++++++-- passes/opt/opt_share.cc | 4 +- passes/opt/share.cc | 4 +- passes/opt/wreduce.cc | 4 +- passes/tests/test_cell.cc | 3 +- techlibs/common/simlib.v | 48 ++++++++++++++++++ techlibs/common/techmap.v | 79 +++++++++++++++++++++++++++-- 23 files changed, 280 insertions(+), 37 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 14c8484e8..2816d3246 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -266,20 +266,26 @@ struct BtorWorker goto okay; } - if (cell->type.in(ID($div), ID($mod))) + if (cell->type.in(ID($div), ID($mod), ID($modfloor))) { + bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false; + bool b_signed = cell->hasParam(ID::B_SIGNED) ? cell->getParam(ID::B_SIGNED).as_bool() : false; + string btor_op; if (cell->type == ID($div)) btor_op = "div"; + // "rem" = truncating modulo if (cell->type == ID($mod)) btor_op = "rem"; + // "mod" = flooring modulo + if (cell->type == ID($modfloor)) { + // "umod" doesn't exist because it's the same as "urem" + btor_op = a_signed || b_signed ? "mod" : "rem"; + } log_assert(!btor_op.empty()); int width = GetSize(cell->getPort(ID::Y)); width = std::max(width, GetSize(cell->getPort(ID::A))); width = std::max(width, GetSize(cell->getPort(ID::B))); - bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false; - bool b_signed = cell->hasParam(ID::B_SIGNED) ? cell->getParam(ID::B_SIGNED).as_bool() : false; - int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed); int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed); diff --git a/backends/btor/test_cells.sh b/backends/btor/test_cells.sh index e0f1a0514..e8d35acf8 100644 --- a/backends/btor/test_cells.sh +++ b/backends/btor/test_cells.sh @@ -6,7 +6,7 @@ rm -rf test_cells.tmp mkdir -p test_cells.tmp cd test_cells.tmp -../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod' +../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$modfloor' for fn in test_*.il; do ../../../yosys -p " diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index a90b0b87a..b1d8500bb 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -585,6 +585,7 @@ struct FirrtlWorker firrtl_is_signed = a_signed | b_signed; firrtl_width = a_width; } else if (cell->type == ID($mod)) { + // "rem" = truncating modulo primop = "rem"; firrtl_width = min(a_width, b_width); } else if (cell->type.in(ID($and), ID($_AND_))) { diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 3e67e55f2..26f17bcb3 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -590,7 +590,17 @@ struct Smt2Worker if (cell->type == ID($sub)) return export_bvop(cell, "(bvsub A B)"); if (cell->type == ID($mul)) return export_bvop(cell, "(bvmul A B)"); if (cell->type == ID($div)) return export_bvop(cell, "(bvUdiv A B)", 'd'); + // "rem" = truncating modulo if (cell->type == ID($mod)) return export_bvop(cell, "(bvUrem A B)", 'd'); + // "mod" = flooring modulo + if (cell->type == ID($modfloor)) { + // bvumod doesn't exist because it's the same as bvurem + if (cell->getParam(ID::A_SIGNED).as_bool()) { + return export_bvop(cell, "(bvsmod A B)", 'd'); + } else { + return export_bvop(cell, "(bvurem A B)", 'd'); + } + } if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool)) && 2*GetSize(cell->getPort(ID::A).chunks()) < GetSize(cell->getPort(ID::A))) { diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc index 7113ebc97..2fc7099f4 100644 --- a/backends/smv/smv.cc +++ b/backends/smv/smv.cc @@ -358,7 +358,8 @@ struct SmvWorker continue; } - if (cell->type.in(ID($div), ID($mod))) + // SMV has a "mod" operator, but its semantics don't seem to be well-defined - to be safe, don't generate it at all + if (cell->type.in(ID($div)/*, ID($mod), ID($modfloor)*/)) { int width_y = GetSize(cell->getPort(ID::Y)); int width = max(width_y, GetSize(cell->getPort(ID::A))); @@ -366,7 +367,7 @@ struct SmvWorker string expr_a, expr_b, op; if (cell->type == ID($div)) op = "/"; - if (cell->type == ID($mod)) op = "mod"; + //if (cell->type == ID($mod)) op = "mod"; if (cell->getParam(ID::A_SIGNED).as_bool()) { diff --git a/backends/smv/test_cells.sh b/backends/smv/test_cells.sh index 63de465c0..ae832ce00 100644 --- a/backends/smv/test_cells.sh +++ b/backends/smv/test_cells.sh @@ -7,8 +7,8 @@ mkdir -p test_cells.tmp cd test_cells.tmp # don't test $mul to reduce runtime -# don't test $div and $mod to reduce runtime and avoid "div by zero" message -../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod' +# don't test $div/$mod/$modfloor to reduce runtime and avoid "div by zero" message +../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod /$modfloor' cat > template.txt << "EOT" %module main diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 11b2ae10f..368b76793 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -740,6 +740,40 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) #undef HANDLE_UNIOP #undef HANDLE_BINOP + if (cell->type == ID($modfloor)) + { + // wire truncated = $signed(A) % $signed(B); + // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated); + + if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) { + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_b = cell->getPort(ID::B); + + std::string temp_id = next_auto_id(); + f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str()); + dump_cell_expr_port(f, cell, "A", true); + f << stringf(" %% "); + dump_attributes(f, "", cell->attributes, ' '); + dump_cell_expr_port(f, cell, "B", true); + f << stringf(";\n"); + + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort(ID::Y)); + f << stringf(" = ("); + dump_sigspec(f, sig_a.extract(sig_a.size()-1)); + f << stringf(" == "); + dump_sigspec(f, sig_b.extract(sig_b.size()-1)); + f << stringf(") || %s == 0 ? %s : ", temp_id.c_str(), temp_id.c_str()); + dump_cell_expr_port(f, cell, "B", true); + f << stringf(" + $signed(%s);\n", temp_id.c_str()); + return true; + } else { + // same as truncating modulo + dump_cell_expr_binop(f, indent, cell, "%"); + return true; + } + } + if (cell->type == ID($shift)) { f << stringf("%s" "assign ", indent.c_str()); diff --git a/kernel/calc.cc b/kernel/calc.cc index 4a4840771..38a529128 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -489,6 +489,7 @@ RTLIL::Const RTLIL::const_mul(const RTLIL::Const &arg1, const RTLIL::Const &arg2 return big2const(y, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } +// truncating division RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; @@ -502,6 +503,7 @@ RTLIL::Const RTLIL::const_div(const RTLIL::Const &arg1, const RTLIL::Const &arg2 return big2const(result_neg ? -(a / b) : (a / b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } +// truncating modulo RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; @@ -515,6 +517,29 @@ RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2 return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } +RTLIL::Const RTLIL::const_modfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + int undef_bit_pos = -1; + BigInteger a = const2big(arg1, signed1, undef_bit_pos); + BigInteger b = const2big(arg2, signed2, undef_bit_pos); + if (b.isZero()) + return RTLIL::Const(RTLIL::State::Sx, result_len); + + BigInteger::Sign a_sign = a.getSign(); + BigInteger::Sign b_sign = b.getSign(); + a = a_sign == BigInteger::negative ? -a : a; + b = b_sign == BigInteger::negative ? -b : b; + BigInteger truncated = a_sign == BigInteger::negative ? -(a % b) : (a % b); + BigInteger modulo; + + if (truncated == 0 || (a_sign == b_sign)) { + modulo = truncated; + } else { + modulo = b_sign == BigInteger::negative ? truncated - b : truncated + b; + } + return big2const(modulo, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); +} + RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; diff --git a/kernel/celledges.cc b/kernel/celledges.cc index 54e0168e2..488ee9d02 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -187,7 +187,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL return true; } - // FIXME: $mul $div $mod $slice $concat + // FIXME: $mul $div $mod $modfloor $slice $concat // FIXME: $lut $sop $alu $lcu $macc $fa return false; diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 450865ce9..37c251f7e 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -114,7 +114,7 @@ struct CellTypes ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), + ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow), ID($logic_and), ID($logic_or), ID($concat), ID($macc) }; @@ -304,6 +304,7 @@ struct CellTypes HANDLE_CELL_TYPE(mul) HANDLE_CELL_TYPE(div) HANDLE_CELL_TYPE(mod) + HANDLE_CELL_TYPE(modfloor) HANDLE_CELL_TYPE(pow) HANDLE_CELL_TYPE(pos) HANDLE_CELL_TYPE(neg) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 196e301b6..f2480ba5a 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -948,7 +948,7 @@ namespace { return; } - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) { + if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow))) { param_bool(ID::A_SIGNED); param_bool(ID::B_SIGNED); port(ID::A, param(ID::A_WIDTH)); @@ -1949,6 +1949,7 @@ DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), ID($sub)) DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul)) DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div)) DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod)) +DEF_METHOD(ModFloor, max(sig_a.size(), sig_b.size()), ID($modfloor)) DEF_METHOD(LogicAnd, 1, ID($logic_and)) DEF_METHOD(LogicOr, 1, ID($logic_or)) #undef DEF_METHOD diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 423c0b4bd..6bb759928 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -466,6 +466,7 @@ namespace RTLIL RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_modfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); @@ -1204,6 +1205,7 @@ public: RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); @@ -1303,6 +1305,7 @@ public: RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = ""); RTLIL::SigSpec LogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = ""); diff --git a/kernel/satgen.h b/kernel/satgen.h index 88b84b7e6..1d257aa2c 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -279,7 +279,7 @@ struct SatGen bool arith_undef_handled = false; bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); - if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod)) || is_arith_compare)) + if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor)) || is_arith_compare)) { std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); @@ -293,7 +293,7 @@ struct SatGen int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); int undef_y_bit = ez->OR(undef_any_a, undef_any_b); - if (cell->type.in(ID($div), ID($mod))) { + if (cell->type.in(ID($div), ID($mod), ID($modfloor))) { std::vector b = importSigSpec(cell->getPort(ID::B), timestep); undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); } @@ -935,7 +935,7 @@ struct SatGen return true; } - if (cell->type.in(ID($div), ID($mod))) + if (cell->type.in(ID($div), ID($mod), ID($modfloor))) { std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); @@ -970,16 +970,28 @@ struct SatGen } std::vector y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); + + // modulo calculation + std::vector modulo_trunc; + int floored_eq_trunc; + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + modulo_trunc = ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf); + // floor == trunc when sgn(a) == sgn(b) or trunc == 0 + floored_eq_trunc = ez->OR(ez->IFF(a.back(), b.back()), ez->NOT(ez->expression(ezSAT::OpOr, modulo_trunc))); + } else { + modulo_trunc = chain_buf; + floored_eq_trunc = ez->CONST_TRUE; + } + if (cell->type == ID($div)) { if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); else ez->assume(ez->vec_eq(y_tmp, y_u)); - } else { - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf))); - else - ez->assume(ez->vec_eq(y_tmp, chain_buf)); + } else if (cell->type == ID($mod)) { + ez->assume(ez->vec_eq(y_tmp, modulo_trunc)); + } else if (cell->type == ID($modfloor)) { + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b)))); } if (ignore_div_by_zero) { @@ -996,7 +1008,8 @@ struct SatGen div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE); div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); } - } else { + } else if (cell->type.in(ID($mod), ID($modfloor))) { + // a mod 0 = a int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex index b85eda892..4652731e9 100644 --- a/manual/PRESENTATION_Prog.tex +++ b/manual/PRESENTATION_Prog.tex @@ -307,7 +307,7 @@ cell name from the internal cell library: \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont] $not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor $reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod -$pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff +$modfloor $pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff $dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_ $_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_ $_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_ diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 6c4bc0e5b..e979685e0 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -109,7 +109,7 @@ struct statdata_t ID($lut), ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), ID($alu))) { + ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow), ID($alu))) { int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0; int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0; diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc index 477246687..c9ac03a6a 100644 --- a/passes/memory/memory_share.cc +++ b/passes/memory/memory_share.cc @@ -715,6 +715,7 @@ struct MemoryShareWorker cone_ct.cell_types.erase(ID($mul)); cone_ct.cell_types.erase(ID($mod)); cone_ct.cell_types.erase(ID($div)); + cone_ct.cell_types.erase(ID($modfloor)); cone_ct.cell_types.erase(ID($pow)); cone_ct.cell_types.erase(ID($shl)); cone_ct.cell_types.erase(ID($shr)); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 777a24777..1b33435b1 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -864,7 +864,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons skip_fine_alu: if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), - ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) + ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow))) { RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec(); @@ -883,7 +883,7 @@ skip_fine_alu: if (0) { found_the_x_bit: cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", - "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str()); + "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$modfloor", "$pow", cell->type.str()); if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); else @@ -1469,6 +1469,7 @@ skip_identity: FOLD_2ARG_CELL(mul) FOLD_2ARG_CELL(div) FOLD_2ARG_CELL(mod) + FOLD_2ARG_CELL(modfloor) FOLD_2ARG_CELL(pow) FOLD_1ARG_CELL(pos) @@ -1583,9 +1584,11 @@ skip_identity: } } - if (!keepdc && cell->type.in(ID($div), ID($mod))) + if (!keepdc && cell->type.in(ID($div), ID($mod), ID($modfloor))) { + bool a_signed = cell->parameters[ID::A_SIGNED].as_bool(); bool b_signed = cell->parameters[ID::B_SIGNED].as_bool(); + SigSpec sig_a = assign_map(cell->getPort(ID::A)); SigSpec sig_b = assign_map(cell->getPort(ID::B)); SigSpec sig_y = assign_map(cell->getPort(ID::Y)); @@ -1628,11 +1631,13 @@ skip_identity: cell->setPort(ID::B, new_b); cell->check(); } - else + else if (cell->type.in(ID($mod), ID($modfloor))) { cover("opt.opt_expr.mod_mask"); - log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", + bool is_truncating = cell->type == ID($mod); + log_debug("Replacing %s-modulo-by-%d cell `%s' in module `%s' with bitmask.\n", + is_truncating ? "truncating" : "flooring", b_val, cell->name.c_str(), module->name.c_str()); std::vector new_b = RTLIL::SigSpec(State::S1, i); @@ -1643,6 +1648,24 @@ skip_identity: cell->type = ID($and); cell->parameters[ID::B_WIDTH] = GetSize(new_b); cell->setPort(ID::B, new_b); + + // truncating modulo has the same masked bits as flooring modulo, but + // the sign bits are those of A (except when R=0) + if (is_truncating && a_signed) { + Wire *flooring = module->addWire(NEW_ID, sig_y.size()); + cell->setPort(ID::Y, flooring); + SigSpec truncating = SigSpec(flooring).extract(0, i); + + Wire *rem_nonzero = module->addWire(NEW_ID); + module->addReduceOr(NEW_ID, truncating, rem_nonzero); + SigSpec a_sign = sig_a[sig_a.size()-1]; + Wire *extend_bit = module->addWire(NEW_ID); + module->addAnd(NEW_ID, a_sign, rem_nonzero, extend_bit); + + truncating.append(extend_bit); + module->addPos(NEW_ID, truncating, sig_y, true); + } + cell->check(); } diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc index 1f69c98f4..b08a8172f 100644 --- a/passes/opt/opt_share.cc +++ b/passes/opt/opt_share.cc @@ -103,7 +103,7 @@ bool cell_supported(RTLIL::Cell *cell) if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci) return true; - } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($concat))) { + } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($concat))) { return true; } @@ -130,7 +130,7 @@ bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b) RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name) { - if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($concat), SHIFT_OPS) && port_name == ID::B) + if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($modfloor), ID($concat), SHIFT_OPS) && port_name == ID::B) return port_name; return ""; diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 2839507b0..1c8942df0 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -376,7 +376,7 @@ struct ShareWorker continue; } - if (cell->type.in(ID($mul), ID($div), ID($mod))) { + if (cell->type.in(ID($mul), ID($div), ID($mod), ID($modfloor))) { if (config.opt_aggressive || cell->parameters.at(ID::Y_WIDTH).as_int() >= 4) shareable_cells.insert(cell); continue; @@ -1133,6 +1133,7 @@ struct ShareWorker cone_ct.cell_types.erase(ID($mul)); cone_ct.cell_types.erase(ID($mod)); cone_ct.cell_types.erase(ID($div)); + cone_ct.cell_types.erase(ID($modfloor)); cone_ct.cell_types.erase(ID($pow)); cone_ct.cell_types.erase(ID($shl)); cone_ct.cell_types.erase(ID($shr)); @@ -1512,6 +1513,7 @@ struct SharePass : public Pass { config.generic_bin_ops.insert(ID($sub)); config.generic_bin_ops.insert(ID($div)); config.generic_bin_ops.insert(ID($mod)); + config.generic_bin_ops.insert(ID($modfloor)); // config.generic_bin_ops.insert(ID($pow)); config.generic_uni_ops.insert(ID($logic_not)); diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 195400bf0..17b957d23 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -37,7 +37,7 @@ struct WreduceConfig ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($pow), + ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($modfloor), ID($pow), ID($mux), ID($pmux), ID($dff), ID($adff) }); @@ -545,7 +545,7 @@ struct WreducePass : public Pass { } } - if (c->type.in(ID($div), ID($mod), ID($pow))) + if (c->type.in(ID($div), ID($mod), ID($modfloor), ID($pow))) { SigSpec A = c->getPort(ID::A); int original_a_width = GetSize(A); diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index cdbe922b2..bc5ff598e 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -264,7 +264,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->setPort(ID::Y, wire); } - if (muxdiv && cell_type.in(ID($div), ID($mod))) { + if (muxdiv && cell_type.in(ID($div), ID($mod), ID($modfloor))) { auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort(ID::B)); auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort(ID::Y))); module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort(ID::Y)); @@ -839,6 +839,7 @@ struct TestCellPass : public Pass { cell_types[ID($mul)] = "ABSY"; cell_types[ID($div)] = "ABSY"; cell_types[ID($mod)] = "ABSY"; + cell_types[ID($modfloor)] = "ABSY"; // cell_types[ID($pow)] = "ABsY"; cell_types[ID($logic_not)] = "ASY"; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 2cdddeabb..57fc07caa 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1021,6 +1021,14 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $mod (A, B, Y) +//- +//- Modulo/remainder of division with truncated result (rounded towards 0). +//- +//- Invariant: $div(A, B) * B + $mod(A, B) == A +//- module \$mod (A, B, Y); parameter A_SIGNED = 0; @@ -1043,6 +1051,46 @@ endgenerate endmodule +// -------------------------------------------------------- + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $modfloor (A, B, Y) +//- +//- Modulo/remainder of division with floored result (rounded towards negative infinity). +//- +//- Invariant: $divfloor(A, B) * B + $modfloor(A, B) == A +//- +module \$modfloor (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +generate + if (A_SIGNED && B_SIGNED) begin:BLOCK1 + localparam WIDTH = B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; + wire [WIDTH-1:0] B_buf, Y_trunc; + assign B_buf = $signed(B); + assign Y_trunc = $signed(A) % $signed(B); + // flooring mod is the same as truncating mod for positive division results (A and B have + // the same sign), as well as when there's no remainder. + // For all other cases, they behave as `floor - trunc = B` + assign Y = (A[A_WIDTH-1] == B[B_WIDTH-1]) || Y_trunc == 0 ? Y_trunc : $signed(B_buf) + $signed(Y_trunc); + end else begin:BLOCK2 + // no difference between truncating and flooring for unsigned + assign Y = A % B; + end +endgenerate + +endmodule + // -------------------------------------------------------- `ifndef SIMLIB_NOPOW diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index c1efc378b..95223180d 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -364,7 +364,8 @@ module \$__div_mod_u (A, B, Y, R); end endgenerate endmodule -module \$__div_mod (A, B, Y, R); +// truncating signed division/modulo +module \$__div_mod_trunc (A, B, Y, R); parameter A_SIGNED = 0; parameter B_SIGNED = 0; parameter A_WIDTH = 1; @@ -420,7 +421,7 @@ module _90_div (A, B, Y); (* force_downto *) output [Y_WIDTH-1:0] Y; - \$__div_mod #( + \$__div_mod_trunc #( .A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), @@ -448,7 +449,79 @@ module _90_mod (A, B, Y); (* force_downto *) output [Y_WIDTH-1:0] Y; - \$__div_mod #( + \$__div_mod_trunc #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) div_mod ( + .A(A), + .B(B), + .R(Y) + ); +endmodule + +// flooring signed division/modulo +module \$__div_mod_floor (A, B, Y, R); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + localparam WIDTH = + A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : + B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y, R; + + wire [WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + + wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u, R_s; + assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf; + assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf; + + \$__div_mod_u #( + .WIDTH(WIDTH) + ) div_mod_u ( + .A(A_buf_u), + .B(B_buf_u), + .Y(Y_u), + .R(R_u) + ); + + // For negative results, if there was a remainder, subtract one to turn + // the round towards 0 into a round towards -inf + assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? (R_u == 0 ? -Y_u : -Y_u-1) : Y_u; + + // truncating modulo + assign R_s = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u; + // Flooring modulo differs from truncating modulo only if it is nonzero and + // A and B have different signs - then `floor - trunc = B` + assign R = (R_s != 0) && A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? $signed(B_buf) + $signed(R_s) : R_s; +endmodule + +(* techmap_celltype = "$modfloor" *) +module _90_modfloor (A, B, Y); + 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] Y; + + \$__div_mod_floor #( .A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), From edd8ff2c0778d97808869488cc7394151456c4ca Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 21 Apr 2020 12:51:58 +0200 Subject: [PATCH 184/197] Add flooring division operator The $div and $mod cells use truncating division semantics (rounding towards 0), as defined by e.g. Verilog. Another rounding mode, flooring (rounding towards negative infinity), can be used in e.g. VHDL. The new $divfloor cell provides this flooring division. This commit also fixes the handling of $div in opt_expr, which was previously optimized as if it was $divfloor. --- backends/btor/test_cells.sh | 2 +- backends/smv/test_cells.sh | 4 +-- backends/verilog/verilog_backend.cc | 55 +++++++++++++++++++++++++++++ kernel/calc.cc | 22 ++++++++++++ kernel/celledges.cc | 2 +- kernel/celltypes.h | 3 +- kernel/rtlil.cc | 3 +- kernel/rtlil.h | 3 ++ kernel/satgen.h | 21 ++++++++--- manual/PRESENTATION_Prog.tex | 2 +- passes/cmds/stat.cc | 2 +- passes/memory/memory_share.cc | 1 + passes/opt/opt_expr.cc | 31 ++++++++++++---- passes/opt/opt_share.cc | 4 +-- passes/opt/share.cc | 4 ++- passes/opt/wreduce.cc | 4 +-- passes/tests/test_cell.cc | 3 +- techlibs/common/simlib.v | 43 ++++++++++++++++++++++ techlibs/common/techmap.v | 28 +++++++++++++++ 19 files changed, 213 insertions(+), 24 deletions(-) diff --git a/backends/btor/test_cells.sh b/backends/btor/test_cells.sh index e8d35acf8..3f077201a 100644 --- a/backends/btor/test_cells.sh +++ b/backends/btor/test_cells.sh @@ -6,7 +6,7 @@ rm -rf test_cells.tmp mkdir -p test_cells.tmp cd test_cells.tmp -../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$modfloor' +../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$divfloor /$modfloor' for fn in test_*.il; do ../../../yosys -p " diff --git a/backends/smv/test_cells.sh b/backends/smv/test_cells.sh index ae832ce00..145b9c33b 100644 --- a/backends/smv/test_cells.sh +++ b/backends/smv/test_cells.sh @@ -7,8 +7,8 @@ mkdir -p test_cells.tmp cd test_cells.tmp # don't test $mul to reduce runtime -# don't test $div/$mod/$modfloor to reduce runtime and avoid "div by zero" message -../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod /$modfloor' +# don't test $div/$mod/$divfloor/$modfloor to reduce runtime and avoid "div by zero" message +../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod /$divfloor /$modfloor' cat > template.txt << "EOT" %module main diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 368b76793..4f44a053a 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -740,6 +740,61 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) #undef HANDLE_UNIOP #undef HANDLE_BINOP + if (cell->type == ID($divfloor)) + { + // wire [MAXLEN+1:0] _0_, _1_, _2_; + // assign _0_ = $signed(A); + // assign _1_ = $signed(B); + // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1)); + // assign Y = $signed(_2_) / $signed(_1_); + + if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) { + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_b = cell->getPort(ID::B); + + std::string buf_a = next_auto_id(); + std::string buf_b = next_auto_id(); + std::string buf_num = next_auto_id(); + int size_a = GetSize(sig_a); + int size_b = GetSize(sig_b); + int size_y = GetSize(cell->getPort(ID::Y)); + int size_max = std::max(size_a, std::max(size_b, size_y)); + + // intentionally one wider than maximum width + f << stringf("%s" "wire [%d:0] %s, %s, %s;\n", indent.c_str(), size_max, buf_a.c_str(), buf_b.c_str(), buf_num.c_str()); + f << stringf("%s" "assign %s = ", indent.c_str(), buf_a.c_str()); + dump_cell_expr_port(f, cell, "A", true); + f << stringf(";\n"); + f << stringf("%s" "assign %s = ", indent.c_str(), buf_b.c_str()); + dump_cell_expr_port(f, cell, "B", true); + f << stringf(";\n"); + + f << stringf("%s" "assign %s = ", indent.c_str(), buf_num.c_str()); + f << stringf("("); + dump_sigspec(f, sig_a.extract(sig_a.size()-1)); + f << stringf(" == "); + dump_sigspec(f, sig_b.extract(sig_b.size()-1)); + f << stringf(") || "); + dump_sigspec(f, sig_a); + f << stringf(" == 0 ? %s : ", buf_a.c_str()); + f << stringf("$signed(%s - (", buf_a.c_str()); + dump_sigspec(f, sig_b.extract(sig_b.size()-1)); + f << stringf(" ? %s + 1 : %s - 1));\n", buf_b.c_str(), buf_b.c_str()); + + + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort(ID::Y)); + f << stringf(" = $signed(%s) / ", buf_num.c_str()); + dump_attributes(f, "", cell->attributes, ' '); + f << stringf("$signed(%s);\n", buf_b.c_str()); + return true; + } else { + // same as truncating division + dump_cell_expr_binop(f, indent, cell, "/"); + return true; + } + } + if (cell->type == ID($modfloor)) { // wire truncated = $signed(A) % $signed(B); diff --git a/kernel/calc.cc b/kernel/calc.cc index 38a529128..ae18809d3 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -517,6 +517,28 @@ RTLIL::Const RTLIL::const_mod(const RTLIL::Const &arg1, const RTLIL::Const &arg2 return big2const(result_neg ? -(a % b) : (a % b), result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); } +RTLIL::Const RTLIL::const_divfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + int undef_bit_pos = -1; + BigInteger a = const2big(arg1, signed1, undef_bit_pos); + BigInteger b = const2big(arg2, signed2, undef_bit_pos); + if (b.isZero()) + return RTLIL::Const(RTLIL::State::Sx, result_len); + + bool result_pos = (a.getSign() == BigInteger::negative) == (b.getSign() == BigInteger::negative); + a = a.getSign() == BigInteger::negative ? -a : a; + b = b.getSign() == BigInteger::negative ? -b : b; + BigInteger result; + + if (result_pos || a == 0) { + result = a / b; + } else { + // bigint division with negative numbers is wonky, make sure we only negate at the very end + result = -((a + b - 1) / b); + } + return big2const(result, result_len >= 0 ? result_len : max(arg1.bits.size(), arg2.bits.size()), min(undef_bit_pos, 0)); +} + RTLIL::Const RTLIL::const_modfloor(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; diff --git a/kernel/celledges.cc b/kernel/celledges.cc index 488ee9d02..314e7c77e 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -187,7 +187,7 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL return true; } - // FIXME: $mul $div $mod $modfloor $slice $concat + // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat // FIXME: $lut $sop $alu $lcu $macc $fa return false; diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 37c251f7e..db54436cb 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -114,7 +114,7 @@ struct CellTypes ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow), + ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($logic_and), ID($logic_or), ID($concat), ID($macc) }; @@ -304,6 +304,7 @@ struct CellTypes HANDLE_CELL_TYPE(mul) HANDLE_CELL_TYPE(div) HANDLE_CELL_TYPE(mod) + HANDLE_CELL_TYPE(divfloor) HANDLE_CELL_TYPE(modfloor) HANDLE_CELL_TYPE(pow) HANDLE_CELL_TYPE(pos) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index f2480ba5a..ca4201b53 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -948,7 +948,7 @@ namespace { return; } - if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow))) { + if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) { param_bool(ID::A_SIGNED); param_bool(ID::B_SIGNED); port(ID::A, param(ID::A_WIDTH)); @@ -1949,6 +1949,7 @@ DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), ID($sub)) DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul)) DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div)) DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod)) +DEF_METHOD(DivFloor, max(sig_a.size(), sig_b.size()), ID($divfloor)) DEF_METHOD(ModFloor, max(sig_a.size(), sig_b.size()), ID($modfloor)) DEF_METHOD(LogicAnd, 1, ID($logic_and)) DEF_METHOD(LogicOr, 1, ID($logic_or)) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 6bb759928..140813326 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -466,6 +466,7 @@ namespace RTLIL RTLIL::Const const_sub (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mul (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_div (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_divfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_modfloor (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_mod (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_pow (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); @@ -1205,6 +1206,7 @@ public: RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + RTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); @@ -1305,6 +1307,7 @@ public: RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Pow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool a_signed = false, bool b_signed = false, const std::string &src = ""); diff --git a/kernel/satgen.h b/kernel/satgen.h index 1d257aa2c..3929a8708 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -279,7 +279,7 @@ struct SatGen bool arith_undef_handled = false; bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); - if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor)) || is_arith_compare)) + if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor)) || is_arith_compare)) { std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); @@ -293,7 +293,7 @@ struct SatGen int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); int undef_y_bit = ez->OR(undef_any_a, undef_any_b); - if (cell->type.in(ID($div), ID($mod), ID($modfloor))) { + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { std::vector b = importSigSpec(cell->getPort(ID::B), timestep); undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); } @@ -935,7 +935,7 @@ struct SatGen return true; } - if (cell->type.in(ID($div), ID($mod), ID($modfloor))) + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); @@ -990,6 +990,19 @@ struct SatGen ez->assume(ez->vec_eq(y_tmp, y_u)); } else if (cell->type == ID($mod)) { ez->assume(ez->vec_eq(y_tmp, modulo_trunc)); + } else if (cell->type == ID($divfloor)) { + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite( + ez->XOR(a.back(), b.back()), + ez->vec_neg(ez->vec_ite( + ez->vec_reduce_or(modulo_trunc), + ez->vec_add(y_u, ez->vec_const_unsigned(1, y_u.size())), + y_u + )), + y_u + ))); + else + ez->assume(ez->vec_eq(y_tmp, y_u)); } else if (cell->type == ID($modfloor)) { ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b)))); } @@ -998,7 +1011,7 @@ struct SatGen ez->assume(ez->expression(ezSAT::OpOr, b)); } else { std::vector div_zero_result; - if (cell->type == ID($div)) { + if (cell->type.in(ID($div), ID($divfloor))) { if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { std::vector all_ones(y.size(), ez->CONST_TRUE); std::vector only_first_one(y.size(), ez->CONST_FALSE); diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex index 4652731e9..a9416f82a 100644 --- a/manual/PRESENTATION_Prog.tex +++ b/manual/PRESENTATION_Prog.tex @@ -307,7 +307,7 @@ cell name from the internal cell library: \begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{6pt}{7pt}\selectfont] $not $pos $neg $and $or $xor $xnor $reduce_and $reduce_or $reduce_xor $reduce_xnor $reduce_bool $shl $shr $sshl $sshr $lt $le $eq $ne $eqx $nex $ge $gt $add $sub $mul $div $mod -$modfloor $pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff +$divfloor $modfloor $pow $logic_not $logic_and $logic_or $mux $pmux $slice $concat $lut $assert $sr $dff $dffsr $adff $dlatch $dlatchsr $memrd $memwr $mem $fsm $_NOT_ $_AND_ $_OR_ $_XOR_ $_MUX_ $_SR_NN_ $_SR_NP_ $_SR_PN_ $_SR_PP_ $_DFF_N_ $_DFF_P_ $_DFF_NN0_ $_DFF_NN1_ $_DFF_NP0_ $_DFF_NP1_ $_DFF_PN0_ $_DFF_PN1_ $_DFF_PP0_ $_DFF_PP1_ $_DFFSR_NNN_ $_DFFSR_NNP_ $_DFFSR_NPN_ $_DFFSR_NPP_ $_DFFSR_PNN_ diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index e979685e0..30436d829 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -109,7 +109,7 @@ struct statdata_t ID($lut), ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow), ID($alu))) { + ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) { int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0; int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0; diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc index c9ac03a6a..e11958bd6 100644 --- a/passes/memory/memory_share.cc +++ b/passes/memory/memory_share.cc @@ -716,6 +716,7 @@ struct MemoryShareWorker cone_ct.cell_types.erase(ID($mod)); cone_ct.cell_types.erase(ID($div)); cone_ct.cell_types.erase(ID($modfloor)); + cone_ct.cell_types.erase(ID($divfloor)); cone_ct.cell_types.erase(ID($pow)); cone_ct.cell_types.erase(ID($shl)); cone_ct.cell_types.erase(ID($shr)); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 1b33435b1..e5b8bda95 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -864,7 +864,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons skip_fine_alu: if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), - ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow))) + ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) { RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec(); @@ -883,7 +883,7 @@ skip_fine_alu: if (0) { found_the_x_bit: cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", - "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$modfloor", "$pow", cell->type.str()); + "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell->type.str()); if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); else @@ -1469,6 +1469,7 @@ skip_identity: FOLD_2ARG_CELL(mul) FOLD_2ARG_CELL(div) FOLD_2ARG_CELL(mod) + FOLD_2ARG_CELL(divfloor) FOLD_2ARG_CELL(modfloor) FOLD_2ARG_CELL(pow) @@ -1584,7 +1585,7 @@ skip_identity: } } - if (!keepdc && cell->type.in(ID($div), ID($mod), ID($modfloor))) + if (!keepdc && cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { bool a_signed = cell->parameters[ID::A_SIGNED].as_bool(); bool b_signed = cell->parameters[ID::B_SIGNED].as_bool(); @@ -1613,11 +1614,13 @@ skip_identity: for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++) if (b_val == (1 << i)) { - if (cell->type == ID($div)) + if (cell->type.in(ID($div), ID($divfloor))) { cover("opt.opt_expr.div_shift"); - log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", + bool is_truncating = cell->type == ID($div); + log_debug("Replacing %s-divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", + is_truncating ? "truncating" : "flooring", b_val, cell->name.c_str(), module->name.c_str(), i); std::vector new_b = RTLIL::SigSpec(i, 6); @@ -1625,10 +1628,26 @@ skip_identity: while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) new_b.pop_back(); - cell->type = ID($shr); + cell->type = ID($sshr); cell->parameters[ID::B_WIDTH] = GetSize(new_b); cell->parameters[ID::B_SIGNED] = false; cell->setPort(ID::B, new_b); + + // Truncating division is the same as flooring division, except when + // the result is negative and there is a remainder - then trunc = floor + 1 + if (is_truncating && a_signed) { + Wire *flooring = module->addWire(NEW_ID, sig_y.size()); + cell->setPort(ID::Y, flooring); + + Wire *result_neg = module->addWire(NEW_ID); + module->addXor(NEW_ID, sig_a[sig_a.size()-1], sig_b[sig_b.size()-1], result_neg); + Wire *rem_nonzero = module->addWire(NEW_ID); + module->addReduceOr(NEW_ID, sig_a.extract(0, i), rem_nonzero); + Wire *should_add = module->addWire(NEW_ID); + module->addAnd(NEW_ID, result_neg, rem_nonzero, should_add); + module->addAdd(NEW_ID, flooring, should_add, sig_y); + } + cell->check(); } else if (cell->type.in(ID($mod), ID($modfloor))) diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc index b08a8172f..cbace7bac 100644 --- a/passes/opt/opt_share.cc +++ b/passes/opt/opt_share.cc @@ -103,7 +103,7 @@ bool cell_supported(RTLIL::Cell *cell) if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci) return true; - } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($concat))) { + } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($concat))) { return true; } @@ -130,7 +130,7 @@ bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b) RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name) { - if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($modfloor), ID($concat), SHIFT_OPS) && port_name == ID::B) + if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($concat), SHIFT_OPS) && port_name == ID::B) return port_name; return ""; diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 1c8942df0..988253edf 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -376,7 +376,7 @@ struct ShareWorker continue; } - if (cell->type.in(ID($mul), ID($div), ID($mod), ID($modfloor))) { + if (cell->type.in(ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor))) { if (config.opt_aggressive || cell->parameters.at(ID::Y_WIDTH).as_int() >= 4) shareable_cells.insert(cell); continue; @@ -1134,6 +1134,7 @@ struct ShareWorker cone_ct.cell_types.erase(ID($mod)); cone_ct.cell_types.erase(ID($div)); cone_ct.cell_types.erase(ID($modfloor)); + cone_ct.cell_types.erase(ID($divfloor)); cone_ct.cell_types.erase(ID($pow)); cone_ct.cell_types.erase(ID($shl)); cone_ct.cell_types.erase(ID($shr)); @@ -1513,6 +1514,7 @@ struct SharePass : public Pass { config.generic_bin_ops.insert(ID($sub)); config.generic_bin_ops.insert(ID($div)); config.generic_bin_ops.insert(ID($mod)); + config.generic_bin_ops.insert(ID($divfloor)); config.generic_bin_ops.insert(ID($modfloor)); // config.generic_bin_ops.insert(ID($pow)); diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 17b957d23..f60f2f8a8 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -37,7 +37,7 @@ struct WreduceConfig ID($and), ID($or), ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($modfloor), ID($pow), + ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($mux), ID($pmux), ID($dff), ID($adff) }); @@ -545,7 +545,7 @@ struct WreducePass : public Pass { } } - if (c->type.in(ID($div), ID($mod), ID($modfloor), ID($pow))) + if (c->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) { SigSpec A = c->getPort(ID::A); int original_a_width = GetSize(A); diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index bc5ff598e..c6801007d 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -264,7 +264,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->setPort(ID::Y, wire); } - if (muxdiv && cell_type.in(ID($div), ID($mod), ID($modfloor))) { + if (muxdiv && cell_type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort(ID::B)); auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort(ID::Y))); module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort(ID::Y)); @@ -839,6 +839,7 @@ struct TestCellPass : public Pass { cell_types[ID($mul)] = "ABSY"; cell_types[ID($div)] = "ABSY"; cell_types[ID($mod)] = "ABSY"; + cell_types[ID($divfloor)] = "ABSY"; cell_types[ID($modfloor)] = "ABSY"; // cell_types[ID($pow)] = "ABsY"; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 57fc07caa..125b8e013 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -997,6 +997,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $div (A, B, Y) +//- +//- Division with truncated result (rounded towards 0). +//- module \$div (A, B, Y); parameter A_SIGNED = 0; @@ -1053,6 +1059,43 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $divfloor (A, B, Y) +//- +//- Division with floored result (rounded towards negative infinity). +//- +module \$divfloor (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +generate + if (A_SIGNED && B_SIGNED) begin:BLOCK1 + localparam WIDTH = + A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : + B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; + wire [WIDTH:0] A_buf, B_buf, N_buf; + assign A_buf = $signed(A); + assign B_buf = $signed(B); + assign N_buf = (A[A_WIDTH-1] == B[B_WIDTH-1]) || A == 0 ? A_buf : $signed(A_buf - (B[B_WIDTH-1] ? B_buf+1 : B_buf-1)); + assign Y = $signed(N_buf) / $signed(B_buf); + end else begin:BLOCK2 + assign Y = A / B; + end +endgenerate + +endmodule + +// -------------------------------------------------------- + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $modfloor (A, B, Y) diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 95223180d..eafe8d4da 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -506,6 +506,34 @@ module \$__div_mod_floor (A, B, Y, R); assign R = (R_s != 0) && A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? $signed(B_buf) + $signed(R_s) : R_s; endmodule +(* techmap_celltype = "$divfloor" *) +module _90_divfloor (A, B, Y); + 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] Y; + + \$__div_mod_floor #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) div_mod ( + .A(A), + .B(B), + .Y(Y) + ); +endmodule + (* techmap_celltype = "$modfloor" *) module _90_modfloor (A, B, Y); parameter A_SIGNED = 0; From 6a2bac21d3c60ba8b499122e7583f1d5bf2d088f Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 21 Apr 2020 16:37:29 +0200 Subject: [PATCH 185/197] Expand tests/simple/constmuldivmod.v --- tests/simple/constmuldivmod.v | 42 ++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/simple/constmuldivmod.v b/tests/simple/constmuldivmod.v index d1d8be862..5dd8f9295 100644 --- a/tests/simple/constmuldivmod.v +++ b/tests/simple/constmuldivmod.v @@ -1,4 +1,4 @@ -module constmuldivmod(input [7:0] A, input [2:0] mode, output reg [7:0] Y); +module constmuldivmod(input [7:0] A, input [5:0] mode, output reg [7:0] Y); always @* begin case (mode) 0: Y = A / 8'd0; @@ -21,6 +21,46 @@ module constmuldivmod(input [7:0] A, input [2:0] mode, output reg [7:0] Y); 13: Y = A % 8'd8; 14: Y = A * 8'd8; + 15: Y = $signed(A) / $signed(8'd0); + 16: Y = $signed(A) % $signed(8'd0); + 17: Y = $signed(A) * $signed(8'd0); + + 18: Y = $signed(A) / $signed(8'd1); + 19: Y = $signed(A) % $signed(8'd1); + 20: Y = $signed(A) * $signed(8'd1); + + 21: Y = $signed(A) / $signed(8'd2); + 22: Y = $signed(A) % $signed(8'd2); + 23: Y = $signed(A) * $signed(8'd2); + + 24: Y = $signed(A) / $signed(8'd4); + 25: Y = $signed(A) % $signed(8'd4); + 26: Y = $signed(A) * $signed(8'd4); + + 27: Y = $signed(A) / $signed(8'd8); + 28: Y = $signed(A) % $signed(8'd8); + 29: Y = $signed(A) * $signed(8'd8); + + 30: Y = $signed(A) / $signed(-8'd0); + 31: Y = $signed(A) % $signed(-8'd0); + 32: Y = $signed(A) * $signed(-8'd0); + + 33: Y = $signed(A) / $signed(-8'd1); + 34: Y = $signed(A) % $signed(-8'd1); + 35: Y = $signed(A) * $signed(-8'd1); + + 36: Y = $signed(A) / $signed(-8'd2); + 37: Y = $signed(A) % $signed(-8'd2); + 38: Y = $signed(A) * $signed(-8'd2); + + 39: Y = $signed(A) / $signed(-8'd4); + 40: Y = $signed(A) % $signed(-8'd4); + 41: Y = $signed(A) * $signed(-8'd4); + + 42: Y = $signed(A) / $signed(-8'd8); + 43: Y = $signed(A) % $signed(-8'd8); + 44: Y = $signed(A) * $signed(-8'd8); + default: Y = 8'd16 * A; endcase end From 7c89738382a6262852781511882c1191423bdc39 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sat, 2 May 2020 11:24:19 +0200 Subject: [PATCH 186/197] Add comments for mod/div semantics to rtlil.h --- kernel/rtlil.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 140813326..a418c9996 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1204,7 +1204,9 @@ public: RTLIL::Cell* addAdd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addSub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addMul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + // truncating division RTLIL::Cell* addDiv (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); + // truncating modulo RTLIL::Cell* addMod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addDivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); @@ -1305,7 +1307,9 @@ public: RTLIL::SigSpec Add (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Sub (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec Mul (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + // truncating division RTLIL::SigSpec Div (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); + // truncating modulo RTLIL::SigSpec Mod (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec DivFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); RTLIL::SigSpec ModFloor (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = ""); From c34cb90a209f609376a7a527a31925993b981011 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sat, 2 May 2020 11:30:30 +0200 Subject: [PATCH 187/197] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 3b36c3182..638ce558b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -66,6 +66,7 @@ Yosys 0.9 .. Yosys 0.9-dev - Added "design -delete" - Added "select -unset" - Use YosysHQ/abc instead of upstream berkeley-abc/abc + - Added $divfloor and $modfloor cells Yosys 0.8 .. Yosys 0.9 ---------------------- From f88bef767263590c94e157d0989afa91db3ccdb0 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 28 May 2020 22:11:44 +0200 Subject: [PATCH 188/197] Document division and modulo cells --- manual/CHAPTER_CellLib.tex | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 55abd9b96..32c530582 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -139,6 +139,8 @@ Verilog & Cell Type \\ \lstinline[language=Verilog]; Y = A * B; & {\tt \$mul} \\ \lstinline[language=Verilog]; Y = A / B; & {\tt \$div} \\ \lstinline[language=Verilog]; Y = A % B; & {\tt \$mod} \\ +\multicolumn{1}{c}{\tt [N/A]} & {\tt \$divfloor} \\ +\multicolumn{1}{c}{\tt [N/A]} & {\tt \$modfoor} \\ \lstinline[language=Verilog]; Y = A ** B; & {\tt \$pow} \\ \end{tabular} \caption{Cell types for binary operators with their corresponding Verilog expressions.} @@ -161,6 +163,27 @@ For the binary cells that output a logical value ({\tt \$logic\_and}, {\tt \$log {\tt \$gt}), when the \B{Y\_WIDTH} parameter is greater than 1, the output is zero-extended, and only the least significant bit varies. +Division and modulo cells are available in two rounding modes. The original {\tt \$div} and {\tt \$mod} +cells are based on truncating division, and correspond to the semantics of the verilog {\tt /} and +{\tt \%} operators. The {\tt \$divfloor} and {\tt \$modfloor} cells represent flooring division and +flooring modulo, the latter of which is also known as ``remainder'' in several languages. See +table~\ref{tab:CellLib_divmod} for a side-by-side comparison between the different semantics. + +\begin{table}[h] +\hfil +\begin{tabular}{lr|rr|rr} +\multirow{2}{*}{Division} & \multirow{2}{*}{Result} & \multicolumn{2}{c|}{Truncating} & \multicolumn{2}{c}{Flooring} \\ + & & {\tt \$div} & {\tt \$mod} & {\tt \$divfloor} & {\tt \$modfloor} \\ +\hline +{\tt -10 / 3} & {\tt -3.3} & {\tt -3} & {\tt -1} & {\tt -4} & {\tt 2} \\ +{\tt 10 / -3} & {\tt -3.3} & {\tt -3} & {\tt 1} & {\tt -4} & {\tt -2} \\ +{\tt -10 / -3} & {\tt 3.3} & {\tt 3} & {\tt -1} & {\tt 3} & {\tt -1} \\ +{\tt 10 / 3} & {\tt 3.3} & {\tt 3} & {\tt 1} & {\tt 3} & {\tt 1} \\ +\end{tabular} +\caption{Comparison between different rounding modes for division and modulo cells.} +\label{tab:CellLib_divmod} +\end{table} + \subsection{Multiplexers} Multiplexers are generated by the Verilog HDL frontend for {\tt From efa7424fb93943d746a344d08e5e879d983709e9 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 27 May 2020 05:20:39 +0000 Subject: [PATCH 189/197] Restrict RTLIL::IdString to not contain whitespace or control chars. This is an existing invariant (most backends can't cope with these) but one that was not checked or documented. --- kernel/rtlil.h | 8 +++++--- manual/CHAPTER_Overview.tex | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 11c45bbec..898c54a3a 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -150,9 +150,6 @@ namespace RTLIL if (!p[0]) return 0; - log_assert(p[0] == '$' || p[0] == '\\'); - log_assert(p[1] != 0); - auto it = global_id_index_.find((char*)p); if (it != global_id_index_.end()) { #ifndef YOSYS_NO_IDS_REFCNT @@ -165,6 +162,11 @@ namespace RTLIL return it->second; } + log_assert(p[0] == '$' || p[0] == '\\'); + log_assert(p[1] != 0); + for (const char *c = p; *c; c++) + log_assert((unsigned)*c > (unsigned)' '); + #ifndef YOSYS_NO_IDS_REFCNT if (global_free_idx_list_.empty()) { if (global_id_storage_.empty()) { diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex index be37d8d39..ac0f48e47 100644 --- a/manual/CHAPTER_Overview.tex +++ b/manual/CHAPTER_Overview.tex @@ -184,9 +184,12 @@ may hold important information for Yosys developers can be used without disturbing external tools. For example the Verilog backend assigns names in the form {\tt \_{\it integer}\_}. \end{itemize} -In order to avoid programming errors, the RTLIL data structures check if all -identifiers start with either a backslash or a dollar sign and generate a -runtime error if this rule is violated. +Whitespace and control characters (any character with an ASCII code 32 or less) are not allowed +in RTLIL identifiers; most frontends and backends cannot support these characters in identifiers. + +In order to avoid programming errors, the RTLIL data structures check if all identifiers start +with either a backslash or a dollar sign, and contain no whitespace or control characters. +Violating these rules results in a runtime error. All RTLIL identifiers are case sensitive. From 13b2963dedebf86129574192b0d4719956e93d82 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 18 May 2020 03:18:42 +0000 Subject: [PATCH 190/197] ilang_lexer: fix check for out of range literal. Commit ca70a104 did not use a correct check. --- frontends/ilang/ilang_lexer.l | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l index 62f53d18e..3362ed641 100644 --- a/frontends/ilang/ilang_lexer.l +++ b/frontends/ilang/ilang_lexer.l @@ -91,8 +91,10 @@ USING_YOSYS_NAMESPACE [0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; } -?[0-9]+ { char *end = nullptr; + errno = 0; long value = strtol(yytext, &end, 10); - if (end != yytext + strlen(yytext)) + 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) From ea30465107a148454f19226e44b242de73d200dd Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Fri, 29 May 2020 21:30:24 +0000 Subject: [PATCH 191/197] smtbmc: Remove superfluous `yosys-smt2-timeout` file macro. Co-Authored-By: clairexen --- backends/smt2/smtio.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index d24fbf809..9f7c8c6d9 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -468,10 +468,6 @@ class SmtIo: fields = stmt.split() - if fields[1] == "yosys-smt2-timeout": - self.timeout = int(fields[2]) - assert self.timeout > 0 - if fields[1] == "yosys-smt2-nomem": if self.logic is None: self.logic_ax = False From 71072d1945b76107a4adc84f6666d100beca6ced Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 1 Jun 2020 10:30:03 +0200 Subject: [PATCH 192/197] Support asymmetric memories for verific frontend --- frontends/verific/verific.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index fe4bda68e..cb0368fd5 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -974,6 +974,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se module->memories[memory->name] = memory; int number_of_bits = net->Size(); + number_of_bits = 1 << ceil_log2(number_of_bits); int bits_in_word = number_of_bits; FOREACH_PORTREF_OF_NET(net, si, pr) { if (pr->GetInst()->Type() == OPER_READ_PORT) { @@ -1265,9 +1266,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->OutputSize()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0) - log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); - for (int i = 0; i < numchunks; i++) { RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; @@ -1295,9 +1293,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->Input2Size()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0) - log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name()); - for (int i = 0; i < numchunks; i++) { RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; From 0a88f002e50c0196175303068bcb3875a01d2c57 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 1 Jun 2020 13:48:19 +0200 Subject: [PATCH 193/197] allow range for mux test --- tests/arch/ice40/mux.ys | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/arch/ice40/mux.ys b/tests/arch/ice40/mux.ys index 99822391d..2b661fd6b 100644 --- a/tests/arch/ice40/mux.ys +++ b/tests/arch/ice40/mux.ys @@ -35,6 +35,7 @@ proc equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module -select -assert-count 11 t:SB_LUT4 +select -assert-min 11 t:SB_LUT4 +select -assert-max 12 t:SB_LUT4 select -assert-none t:SB_LUT4 %% t:* %D From 68d747f76769ce6e517cc72263ccc89ef5dff43f Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 2 Jun 2020 22:19:34 +0000 Subject: [PATCH 194/197] techmap: use +/techmap.v instead of an ad-hoc code generator. --- passes/techmap/.gitignore | 1 - passes/techmap/Makefile.inc | 12 ------------ passes/techmap/techmap.cc | 4 +--- 3 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 passes/techmap/.gitignore diff --git a/passes/techmap/.gitignore b/passes/techmap/.gitignore deleted file mode 100644 index e6dcc6bc0..000000000 --- a/passes/techmap/.gitignore +++ /dev/null @@ -1 +0,0 @@ -techmap.inc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 1802ba0de..873286608 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -45,18 +45,6 @@ OBJS += passes/techmap/flowmap.o OBJS += passes/techmap/extractinv.o endif -GENFILES += passes/techmap/techmap.inc - -passes/techmap/techmap.inc: techlibs/common/techmap.v - $(Q) mkdir -p $(dir $@) - $(P) echo "// autogenerated from $<" > $@.new - $(Q) echo "static char stdcells_code[] = {" >> $@.new - $(Q) od -v -td1 -An $< | $(SED) -e 's/[0-9][0-9]*/&,/g' >> $@.new - $(Q) echo "0};" >> $@.new - $(Q) mv $@.new $@ - -passes/techmap/techmap.o: passes/techmap/techmap.inc - ifeq ($(DISABLE_SPAWN),0) TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE) EXTRA_OBJS += passes/techmap/filterlib.o diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 6ac1d1113..fc24c33b0 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -27,7 +27,6 @@ #include #include "simplemap.h" -#include "passes/techmap/techmap.inc" YOSYS_NAMESPACE_BEGIN @@ -1282,8 +1281,7 @@ struct TechmapPass : public Pass { RTLIL::Design *map = new RTLIL::Design; if (map_files.empty()) { - std::istringstream f(stdcells_code); - Frontend::frontend_call(map, &f, "", verilog_frontend); + Frontend::frontend_call(map, nullptr, "+/techmap.v", verilog_frontend); } else { for (auto &fn : map_files) if (fn.compare(0, 1, "%") == 0) { From f3e86bb32a745d300df38173b41347263696ed4b Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 2 Jun 2020 22:34:01 +0000 Subject: [PATCH 195/197] techmap: simplify. `rewrite_filename` is already called in `Frontend::extra_args`. --- passes/techmap/techmap.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index fc24c33b0..0d7c10d0c 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1293,13 +1293,7 @@ struct TechmapPass : public Pass { if (!map->module(mod->name)) map->add(mod->clone()); } else { - std::ifstream f; - rewrite_filename(fn); - f.open(fn.c_str()); - yosys_input_files.insert(fn); - if (f.fail()) - log_cmd_error("Can't open map file `%s'\n", fn.c_str()); - Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend)); + Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend)); } } From 0a74368bfc1d4fadaf9efb5eb28f9e706dfdf6c9 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 2 Jun 2020 23:17:46 +0000 Subject: [PATCH 196/197] techmap: use C++11 default member initializers. NFC. --- passes/techmap/techmap.cc | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 0d7c10d0c..9227385b3 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -80,22 +80,12 @@ struct TechmapWorker typedef dict> TechmapWires; - bool extern_mode; - bool assert_mode; - bool flatten_mode; - bool recursive_mode; - bool autoproc_mode; - bool ignore_wb; - - TechmapWorker() - { - extern_mode = false; - assert_mode = false; - flatten_mode = false; - recursive_mode = false; - autoproc_mode = false; - ignore_wb = false; - } + bool extern_mode = false; + bool assert_mode = false; + bool flatten_mode = false; + bool recursive_mode = false; + bool autoproc_mode = false; + bool ignore_wb = false; std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) { From fb5b070e7e9e22b02a3ee94217c8ae20cef41f0b Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 3 Jun 2020 01:44:06 +0000 Subject: [PATCH 197/197] techmap: remove dead variable. NFC. --- passes/techmap/techmap.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 9227385b3..c88f7bd0a 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -268,7 +268,6 @@ struct TechmapWorker tpl_written_bits.insert(bit); SigMap port_signal_map; - SigSig port_signal_assign; for (auto &it : cell->connections()) {