diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 22319ffb063..6e191650f34 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1743,6 +1743,20 @@ struct t_lut_bel { std::vector input_pins; std::string output_pin; + + bool operator==(const t_lut_bel& other) const { + return name == other.name && input_pins == other.input_pins && output_pin == other.output_pin; + } +}; + +struct t_lut_element { + std::string site_type; + int width; + std::vector lut_bels; + + bool operator==(const t_lut_element& other) const { + return site_type == other.site_type && width == other.width && lut_bels == other.lut_bels; + } }; /* Detailed routing architecture */ @@ -1780,7 +1794,7 @@ struct t_arch { // Luts std::vector lut_cells; - std::vector lut_bels; + std::unordered_map> lut_elements; //The name of the switch used for the input connection block (i.e. to //connect routing tracks to block pins). diff --git a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp index 3fc1e814bf8..b3c702214d8 100644 --- a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp +++ b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp @@ -50,6 +50,38 @@ struct t_bel_cell_mapping { /****************** Utility functions ******************/ +namespace vtr { +static char* stringf(const char* format, ...) { + // Initial buffer + const int initialSize = 80 + 1; + char* str = (char*)vtr::malloc(initialSize); + + // Init and copy args list + va_list va1, va2; + va_start(va1, format); + va_copy(va2, va1); + + // First attempt + int len = vsnprintf(str, initialSize, format, va1); + VTR_ASSERT(len >= 0); + + // The buffer was too small + if (len >= initialSize) { + str = (char*)vtr::realloc((void*)str, len + 1); + VTR_ASSERT(str != nullptr); + len = vsnprintf(str, len + 1, format, va2); + VTR_ASSERT(len >= 0); + VTR_ASSERT(len <= len); + } + + // Cleanup + va_end(va1); + va_end(va2); + + return str; +} +} // namespace vtr + /** * @brief The FPGA interchange timing model includes three different corners (min, typ and max) for each of the two * speed_models (slow and fast). @@ -285,18 +317,44 @@ struct ArchReader { return bel.getCategory() == Device::BELCategory::SITE_PORT ? str(site.getName()) : str(bel.getName()); } - bool is_lut(std::string name) { + bool is_lut(std::string name, const std::string site = std::string()) { for (auto cell : arch_->lut_cells) if (cell.name == name) return true; - for (auto bel : arch_->lut_bels) - if (bel.name == name) - return true; + for (const auto& it : arch_->lut_elements) { + if (!site.empty() && site != it.first) { + continue; + } + + for (const auto& lut_element : it.second) { + for (const auto& lut_bel : lut_element.lut_bels) { + if (lut_bel.name == name) { + return true; + } + } + } + } return false; } + t_lut_element* get_lut_element_for_bel(const std::string& site_type, const std::string& bel_name) { + if (!arch_->lut_elements.count(site_type)) { + return nullptr; + } + + for (auto& lut_element : arch_->lut_elements.at(site_type)) { + for (auto& lut_bel : lut_element.lut_bels) { + if (lut_bel.name == bel_name) { + return &lut_element; + } + } + } + + return nullptr; + } + bool is_pad(std::string name) { for (auto pad : pad_bels_) if (pad.bel_name == name) @@ -310,6 +368,7 @@ struct ArchReader { // - key: interconnect name // - value: (inputs string, outputs string, interconnect type) std::unordered_map> ics; + const std::string site_type = str(site.getName()); for (auto wire : site.getSiteWires()) { std::string wire_name = str(wire.getName()); @@ -369,6 +428,32 @@ struct ArchReader { auto in_bel_name = std::get<2>(out_pin_tuple); auto in_bel_pin_name = std::get<1>(out_pin_tuple); + // LUT bels are nested under pb_types which represent LUT + // elements. Check if a BEL belongs to a LUT element and + // adjust pb_type name in the interconnect accordingly. + auto get_lut_element_index = [&](const std::string& bel_name) { + auto lut_element = get_lut_element_for_bel(site_type, bel_name); + if (lut_element == nullptr) { + return -1; + } + + const auto& lut_elements = arch_->lut_elements.at(site_type); + auto it = std::find(lut_elements.begin(), lut_elements.end(), *lut_element); + VTR_ASSERT(it != lut_elements.end()); + return (int)std::distance(lut_elements.begin(), it); + }; + + int index = -1; + + index = get_lut_element_index(out_bel_name); + if (index >= 0) { + out_bel_name = "LUT" + std::to_string(index); + } + index = get_lut_element_index(in_bel_name); + if (index >= 0) { + in_bel_name = "LUT" + std::to_string(index); + } + std::string ostr = out_bel_name + "." + out_bel_pin_name; std::string istr = in_bel_name + "." + in_bel_pin_name; @@ -454,27 +539,25 @@ struct ArchReader { for (auto lut_elem : lut_def.getLutElements()) { for (auto lut : lut_elem.getLuts()) { + t_lut_element element; + element.site_type = lut_elem.getSite().cStr(); + element.width = lut.getWidth(); + for (auto bel : lut.getBels()) { t_lut_bel lut_bel; - - std::string name = bel.getName().cStr(); - lut_bel.name = name; - - // Check for duplicates - auto is_duplicate = [name](t_lut_bel l) { return l.name == name; }; - auto res = std::find_if(arch_->lut_bels.begin(), arch_->lut_bels.end(), is_duplicate); - if (res != arch_->lut_bels.end()) - continue; - + lut_bel.name = bel.getName().cStr(); std::vector ipins; + for (auto pin : bel.getInputPins()) ipins.push_back(pin.cStr()); lut_bel.input_pins = ipins; lut_bel.output_pin = bel.getOutputPin().cStr(); - arch_->lut_bels.push_back(lut_bel); + element.lut_bels.push_back(lut_bel); } + + arch_->lut_elements[element.site_type].push_back(element); } } } @@ -695,19 +778,43 @@ struct ArchReader { mode->name = vtr::strdup("default"); mode->disable_packing = false; - int bel_count = get_bel_type_count(site, Device::BELCategory::LOGIC); - mode->num_pb_type_children = bel_count; - mode->pb_type_children = new t_pb_type[bel_count]; + // Get LUT elements for this site + std::vector lut_elements; + if (arch_->lut_elements.count(name)) { + lut_elements = arch_->lut_elements.at(name); + } + // Count non-LUT BELs plus LUT elements + int block_count = 0; int count = 0; + + for (auto bel : site.getBels()) { + if (bel.getCategory() != Device::BELCategory::LOGIC) { + continue; + } + if (is_lut(str(bel.getName()), name)) { + continue; + } + block_count++; + } + block_count += lut_elements.size(); + + mode->num_pb_type_children = block_count; + mode->pb_type_children = new t_pb_type[mode->num_pb_type_children]; + + // Add regular BELs for (auto bel : bels) { - if (bel.getCategory() != Device::BELCategory::LOGIC) + if (bel.getCategory() != Device::BELCategory::LOGIC) { + continue; + } + if (is_lut(str(bel.getName()), name)) { continue; + } auto bel_name = str(bel.getName()); std::pair key(name, bel_name); - auto mid_pb_type = new t_pb_type; + auto mid_pb_type = &mode->pb_type_children[count++]; mid_pb_type->name = vtr::strdup(bel_name.c_str()); mid_pb_type->num_pb = 1; mid_pb_type->parent_mode = mode; @@ -716,14 +823,23 @@ struct ArchReader { if (!is_pad(bel_name)) process_block_ports(mid_pb_type, site, false); - if (is_lut(bel_name)) - process_lut_block(mid_pb_type); - else if (is_pad(bel_name)) + if (is_pad(bel_name)) process_pad_block(mid_pb_type, bel, site); else process_generic_block(mid_pb_type, bel); + } + + // Add LUT elements + for (size_t i = 0; i < lut_elements.size(); ++i) { + const auto& lut_element = lut_elements[i]; - mode->pb_type_children[count++] = *mid_pb_type; + auto mid_pb_type = &mode->pb_type_children[count++]; + mid_pb_type->name = vtr::stringf("LUT%d", i); + mid_pb_type->num_pb = 1; + mid_pb_type->parent_mode = mode; + mid_pb_type->blif_model = nullptr; + + process_lut_element(mid_pb_type, lut_element); } process_interconnects(mode, site); @@ -731,78 +847,177 @@ struct ArchReader { } } - void process_lut_block(t_pb_type* lut) { - lut->num_modes = 1; - lut->modes = new t_mode[1]; + void process_lut_element(t_pb_type* parent, const t_lut_element& lut_element) { + // Collect ports for the parent pb_type representing the whole LUT + // element + std::unordered_map> parent_ports; + for (const auto& lut_bel : lut_element.lut_bels) { + for (const auto& name : lut_bel.input_pins) { + parent_ports[name] = std::make_pair(IN_PORT, 1); + } + parent_ports[lut_bel.output_pin] = std::make_pair(OUT_PORT, 1); + } - // Check for duplicates - std::string lut_name = lut->name; - auto find_lut = [lut_name](t_lut_bel l) { return l.name == lut_name; }; - auto res = std::find_if(arch_->lut_bels.begin(), arch_->lut_bels.end(), find_lut); - VTR_ASSERT(res != arch_->lut_bels.end()); - auto lut_bel = *res; + // Create the ports + create_ports(parent, parent_ports); - auto mode = &lut->modes[0]; - mode->name = vtr::strdup("lut"); - mode->parent_pb_type = lut; - mode->index = 0; - mode->num_pb_type_children = 1; - mode->pb_type_children = new t_pb_type[1]; + // Make a single mode for each member LUT of the LUT element + parent->num_modes = (int)lut_element.lut_bels.size(); + parent->modes = new t_mode[parent->num_modes]; - auto new_leaf = new t_pb_type; - new_leaf->name = vtr::strdup("lut_child"); - new_leaf->num_pb = 1; - new_leaf->parent_mode = mode; + for (size_t i = 0; i < lut_element.lut_bels.size(); ++i) { + const t_lut_bel& lut_bel = lut_element.lut_bels[i]; + auto mode = &parent->modes[i]; - int num_ports = 2; - new_leaf->num_ports = num_ports; - new_leaf->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); - new_leaf->blif_model = vtr::strdup(MODEL_NAMES); - new_leaf->model = get_model(arch_, std::string(MODEL_NAMES)); + mode->name = vtr::strdup(lut_bel.name.c_str()); + mode->parent_pb_type = parent; + mode->index = i; - auto in_size = lut_bel.input_pins.size(); - new_leaf->ports[0] = get_generic_port(arch_, new_leaf, IN_PORT, "in", MODEL_NAMES, in_size); - new_leaf->ports[1] = get_generic_port(arch_, new_leaf, OUT_PORT, "out", MODEL_NAMES); + // Leaf pb_type block for the LUT + mode->num_pb_type_children = 1; + mode->pb_type_children = new t_pb_type[mode->num_pb_type_children]; - mode->pb_type_children[0] = *new_leaf; + auto pb_type = &mode->pb_type_children[0]; + pb_type->name = vtr::strdup(lut_bel.name.c_str()); + pb_type->num_pb = 1; + pb_type->parent_mode = mode; + pb_type->blif_model = nullptr; - // Num inputs + 1 (output pin) - int num_pins = in_size + 1; + process_lut_block(pb_type, lut_bel); - mode->num_interconnect = num_pins; - mode->interconnect = new t_interconnect[num_pins]; + // Mode interconnect + mode->num_interconnect = lut_bel.input_pins.size() + 1; + mode->interconnect = new t_interconnect[mode->num_interconnect]; - for (int i = 0; i < num_pins; i++) { - auto ic = new t_interconnect; + // Inputs + for (size_t j = 0; j < lut_bel.input_pins.size(); ++j) { + auto* ic = &mode->interconnect[j]; - std::stringstream istr; - std::stringstream ostr; - std::string input_string; - std::string output_string; + ic->type = DIRECT_INTERC; + ic->parent_mode = mode; + ic->parent_mode_index = mode->index; - if (i < num_pins - 1) { - istr << lut_bel.input_pins[i]; - ostr << "in[" << i << "]"; - input_string = std::string(lut->name) + std::string(".") + istr.str(); - output_string = std::string(new_leaf->name) + std::string(".") + ostr.str(); - } else { - istr << "out"; - ostr << lut_bel.output_pin; - input_string = std::string(new_leaf->name) + std::string(".") + istr.str(); - output_string = std::string(lut->name) + std::string(".") + ostr.str(); + ic->input_string = vtr::stringf("%s.%s", parent->name, lut_bel.input_pins[j].c_str()); + ic->output_string = vtr::stringf("%s.in[%d]", pb_type->name, j); + ic->name = vtr::stringf("%s_to_%s", + ic->input_string, + ic->output_string); } - std::string name = istr.str() + std::string("_") + ostr.str(); - ic->name = vtr::strdup(name.c_str()); + + // Output + auto* ic = &mode->interconnect[mode->num_interconnect - 1]; ic->type = DIRECT_INTERC; - ic->parent_mode_index = 0; ic->parent_mode = mode; - ic->input_string = vtr::strdup(input_string.c_str()); - ic->output_string = vtr::strdup(output_string.c_str()); + ic->parent_mode_index = mode->index; - mode->interconnect[i] = *ic; + ic->input_string = vtr::stringf("%s.out", pb_type->name); + ic->output_string = vtr::stringf("%s.%s", parent->name, lut_bel.output_pin.c_str()); + ic->name = vtr::stringf("%s_to_%s", + ic->input_string, + ic->output_string); } } + void process_lut_block(t_pb_type* pb_type, const t_lut_bel& lut_bel) { + // Create port list + size_t width = lut_bel.input_pins.size(); + + std::unordered_map> ports; + ports["in"] = std::make_pair(IN_PORT, width); + ports["out"] = std::make_pair(OUT_PORT, 1); + + create_ports(pb_type, ports); + + // Make two modes. One for LUT-thru and another for the actual LUT bel + pb_type->num_modes = 2; + pb_type->modes = new t_mode[pb_type->num_modes]; + + // ................................................ + // LUT-thru + t_mode* mode = &pb_type->modes[0]; + + // Mode + mode->name = vtr::strdup("wire"); + mode->parent_pb_type = pb_type; + mode->index = 0; + mode->num_pb_type_children = 0; + + // Mode interconnect + mode->num_interconnect = 1; + mode->interconnect = new t_interconnect[mode->num_interconnect]; + t_interconnect* ic = &mode->interconnect[0]; + + ic->input_string = vtr::stringf("%s.in", pb_type->name); + ic->output_string = vtr::stringf("%s.out", pb_type->name); + ic->name = vtr::strdup("passthrough"); + + ic->type = COMPLETE_INTERC; + ic->parent_mode = mode; + ic->parent_mode_index = mode->index; + + // ................................................ + // LUT BEL + mode = &pb_type->modes[1]; + + // Mode + mode->name = vtr::strdup("lut"); + mode->parent_pb_type = pb_type; + mode->index = 1; + + // Leaf pb_type + mode->num_pb_type_children = 1; + mode->pb_type_children = new t_pb_type[mode->num_pb_type_children]; + + auto lut = &mode->pb_type_children[0]; + lut->name = vtr::strdup("lut"); + lut->num_pb = 1; + lut->parent_mode = mode; + + lut->blif_model = vtr::strdup(MODEL_NAMES); + lut->model = get_model(arch_, std::string(MODEL_NAMES)); + + lut->num_ports = 2; + lut->ports = (t_port*)vtr::calloc(lut->num_ports, sizeof(t_port)); + lut->ports[0] = get_generic_port(arch_, lut, IN_PORT, "in", MODEL_NAMES, width); + lut->ports[1] = get_generic_port(arch_, lut, OUT_PORT, "out", MODEL_NAMES); + + lut->ports[0].equivalent = PortEquivalence::FULL; + + // Set classes + pb_type->class_type = LUT_CLASS; + lut->class_type = LUT_CLASS; + lut->ports[0].port_class = vtr::strdup("lut_in"); + lut->ports[1].port_class = vtr::strdup("lut_out"); + + // Mode interconnect + mode->num_interconnect = 2; + mode->interconnect = new t_interconnect[mode->num_interconnect]; + + // Input + ic = &mode->interconnect[0]; + ic->type = DIRECT_INTERC; + ic->parent_mode = mode; + ic->parent_mode_index = mode->index; + + ic->input_string = vtr::stringf("%s.in", pb_type->name); + ic->output_string = vtr::stringf("%s.in", lut->name); + ic->name = vtr::stringf("%s_to_%s", + ic->input_string, + ic->output_string); + + // Output + ic = &mode->interconnect[1]; + ic->type = DIRECT_INTERC; + ic->parent_mode = mode; + ic->parent_mode_index = mode->index; + + ic->input_string = vtr::stringf("%s.out", lut->name); + ic->output_string = vtr::stringf("%s.out", pb_type->name); + ic->name = vtr::stringf("%s_to_%s", + ic->input_string, + ic->output_string); + } + void process_pad_block(t_pb_type* pad, Device::BEL::Reader& bel, Device::SiteType::Reader& site) { // For now, hard-code two modes for pads, so that PADs can either be IPADs or OPADs pad->num_modes = 2; @@ -815,7 +1030,7 @@ struct ArchReader { std::string opin = pin + pad_out_suffix_; auto num_ports = 2; - auto ports = new t_port[num_ports]; + auto ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); pad->ports = ports; pad->num_ports = pad->num_pins = num_ports; pad->num_input_pins = 1; @@ -852,7 +1067,7 @@ struct ArchReader { omode->num_pb_type_children = 1; omode->pb_type_children = new t_pb_type[1]; - auto opad = new t_pb_type; + auto opad = &omode->pb_type_children[0]; opad->name = vtr::strdup("opad"); opad->num_pb = 1; opad->parent_mode = omode; @@ -864,7 +1079,6 @@ struct ArchReader { opad->model = get_model(arch_, std::string(MODEL_OUTPUT)); opad->ports[0] = get_generic_port(arch_, opad, IN_PORT, "outpad", MODEL_OUTPUT); - omode->pb_type_children[0] = *opad; // IPAD mode auto imode = &pad->modes[1]; @@ -874,7 +1088,7 @@ struct ArchReader { imode->num_pb_type_children = 1; imode->pb_type_children = new t_pb_type[1]; - auto ipad = new t_pb_type; + auto ipad = &imode->pb_type_children[0]; ipad->name = vtr::strdup("ipad"); ipad->num_pb = 1; ipad->parent_mode = imode; @@ -886,7 +1100,6 @@ struct ArchReader { ipad->model = get_model(arch_, std::string(MODEL_INPUT)); ipad->ports[0] = get_generic_port(arch_, ipad, OUT_PORT, "inpad", MODEL_INPUT); - imode->pb_type_children[0] = *ipad; // Handle interconnects int num_pins = 1; @@ -905,8 +1118,8 @@ struct ArchReader { std::string ipad_ostr = std::string(pad->name) + std::string(".") + opin; std::string i_ic_name = std::string(ipad->name) + std::string("_") + std::string(pad->name); - auto o_ic = new t_interconnect[num_pins]; - auto i_ic = new t_interconnect[num_pins]; + auto o_ic = &omode->interconnect[0]; + auto i_ic = &imode->interconnect[0]; o_ic->name = vtr::strdup(o_ic_name.c_str()); o_ic->type = DIRECT_INTERC; @@ -921,9 +1134,6 @@ struct ArchReader { i_ic->parent_mode = imode; i_ic->input_string = vtr::strdup(ipad_istr.c_str()); i_ic->output_string = vtr::strdup(ipad_ostr.c_str()); - - omode->interconnect[0] = *o_ic; - imode->interconnect[0] = *i_ic; } void process_generic_block(t_pb_type* pb_type, Device::BEL::Reader& bel) { @@ -1047,7 +1257,7 @@ struct ArchReader { std::unordered_set names; auto num_ports = pins.size(); - auto ports = new t_port[num_ports]; + auto ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); pb_type->ports = ports; pb_type->num_ports = pb_type->num_pins = num_ports; pb_type->num_input_pins = 0; @@ -1111,7 +1321,7 @@ struct ArchReader { auto outs = vtr::split(outputs, " "); auto ins = vtr::split(inputs, " "); ic->num_annotations = outs.size(); - ic->annotations = new t_pin_to_pin_annotation[outs.size()]; + ic->annotations = (t_pin_to_pin_annotation*)vtr::calloc(outs.size(), sizeof(t_pin_to_pin_annotation)); VTR_ASSERT(ins.size() == 1); // pack pattern @@ -1136,23 +1346,23 @@ struct ArchReader { } t_pin_to_pin_annotation get_pack_pattern(std::string ic_name, std::string input, std::string output) { - auto pp = new t_pin_to_pin_annotation; + t_pin_to_pin_annotation pp; std::string pp_name = ic_name + "_" + output; - pp->prop = (int*)vtr::calloc(1, sizeof(int)); - pp->value = (char**)vtr::calloc(1, sizeof(char*)); + pp.prop = (int*)vtr::calloc(1, sizeof(int)); + pp.value = (char**)vtr::calloc(1, sizeof(char*)); - pp->type = E_ANNOT_PIN_TO_PIN_PACK_PATTERN; - pp->format = E_ANNOT_PIN_TO_PIN_CONSTANT; - pp->prop[0] = (int)E_ANNOT_PIN_TO_PIN_PACK_PATTERN_NAME; - pp->value[0] = vtr::strdup(pp_name.c_str()); - pp->input_pins = vtr::strdup(input.c_str()); - pp->output_pins = vtr::strdup(output.c_str()); - pp->num_value_prop_pairs = 1; - pp->clock = nullptr; + pp.type = E_ANNOT_PIN_TO_PIN_PACK_PATTERN; + pp.format = E_ANNOT_PIN_TO_PIN_CONSTANT; + pp.prop[0] = (int)E_ANNOT_PIN_TO_PIN_PACK_PATTERN_NAME; + pp.value[0] = vtr::strdup(pp_name.c_str()); + pp.input_pins = vtr::strdup(input.c_str()); + pp.output_pins = vtr::strdup(output.c_str()); + pp.num_value_prop_pairs = 1; + pp.clock = nullptr; - return *pp; + return pp; } // Physical Tiles @@ -1533,10 +1743,10 @@ struct ArchReader { // the RR graph generation is correct. // This can be removed once the RR graph reader from the interchange // device is ready and functional. - int num_seg = 1; //wire_names.size(); + size_t num_seg = 1; //wire_names.size(); arch_->Segments.resize(num_seg); - uint32_t index = 0; + size_t index = 0; for (auto i : wire_names) { if (index >= num_seg) break; diff --git a/vpr/test/test_interchange_device.cpp b/vpr/test/test_interchange_device.cpp index ac939714f1a..58a58b32f19 100644 --- a/vpr/test/test_interchange_device.cpp +++ b/vpr/test/test_interchange_device.cpp @@ -80,8 +80,6 @@ TEST_CASE("read_interchange_luts", "[vpr]") { std::unordered_set lut_bel_pins = {"A1", "A2", "A3", "A4"}; REQUIRE(arch.lut_cells.size() == 4); - REQUIRE(arch.lut_bels.size() == 2); - for (auto lut_cell : arch.lut_cells) { CHECK(std::find(lut_cells.begin(), lut_cells.end(), lut_cell.name) != lut_cells.end()); REQUIRE(lut_cell.init_param == std::string("INIT")); @@ -89,11 +87,19 @@ TEST_CASE("read_interchange_luts", "[vpr]") { CHECK(std::find(lut_cell_pins.begin(), lut_cell_pins.end(), lut_pin) != lut_cell_pins.end()); } - for (auto lut_bel : arch.lut_bels) { - CHECK(std::find(lut_bels.begin(), lut_bels.end(), lut_bel.name) != lut_bels.end()); - REQUIRE(lut_bel.output_pin == std::string("O")); - for (auto lut_pin : lut_bel.input_pins) - CHECK(std::find(lut_bel_pins.begin(), lut_bel_pins.end(), lut_pin) != lut_bel_pins.end()); + for (const auto& it : arch.lut_elements) { + const auto& lut_elements = it.second; + + for (const auto& lut_element : lut_elements) { + REQUIRE(lut_element.lut_bels.size() == 1); + + for (auto lut_bel : lut_element.lut_bels) { + CHECK(std::find(lut_bels.begin(), lut_bels.end(), lut_bel.name) != lut_bels.end()); + REQUIRE(lut_bel.output_pin == std::string("O")); + for (auto lut_pin : lut_bel.input_pins) + CHECK(std::find(lut_bel_pins.begin(), lut_bel_pins.end(), lut_pin) != lut_bel_pins.end()); + } + } } }