diff --git a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp index 6ac7de1a0cc..a3a0ccf20dd 100644 --- a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp +++ b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp @@ -191,6 +191,93 @@ static void add_segment_with_default_values(t_segment_inf& seg, std::string name seg.sb[1] = true; } +//** @brief Checks indexing of ports and pins of CLB hierarchy */ +static bool check_pbtype_ports_and_pins(t_pb_type* pb_type) { + + bool errors = false; + + int abs_pin_index = 0; + std::unordered_map index_by_type; + + index_by_type[IN_PORT] = 0; + index_by_type[OUT_PORT] = 0; + index_by_type[INOUT_PORT] = 0; + + // Check ports + for (int i=0; inum_ports; ++i) { + t_port* port = &pb_type->ports[i]; + + if (port == nullptr) { + VTR_LOG_ERROR("pb_type '%s' port #%d is NULL\n", pb_type->name, i); + errors = true; + continue; + } + + if (port->parent_pb_type != pb_type) { + VTR_LOG_ERROR("pb_type '%s' port #%d '%s' has wrong parent pb_type\n", + pb_type->name, i, port->name); + errors = true; + } + + if (port->index != i) { + VTR_LOG_ERROR("pb_type '%s' port #%d '%s' has wrong index (%d vs. %d)\n", + pb_type->name, i, port->name, port->index, i); + errors = true; + } + + if (port->absolute_first_pin_index != abs_pin_index) { + VTR_LOG_ERROR("pb_type '%s' port #%d '%s' has wrong absolute_first_pin_index (%d vs. %d)\n", + pb_type->name, i, port->name, port->absolute_first_pin_index, abs_pin_index); + errors = true; + } + + int type_index = index_by_type.at(port->type); + if (port->port_index_by_type != type_index) { + VTR_LOG_ERROR("pb_type '%s' port #%d '%s' has wrong port_index_by_type (%d vs. %d)\n", + pb_type->name, i, port->name, port->port_index_by_type, type_index); + errors = true; + } + + index_by_type[port->type] = type_index + 1; + abs_pin_index += port->num_pins; + } + + // Recurse + for (int i=0; inum_modes; ++i) { + t_mode* mode = &pb_type->modes[i]; + + if (mode == nullptr) { + VTR_LOG_ERROR("pb_type '%s' mode #%d is NULL\n", pb_type->name, i); + errors = true; + continue; + } + + if (mode->parent_pb_type != pb_type) { + VTR_LOG_ERROR("pb_type '%s' mode #%d has wrong parent_pb_type\n", pb_type->name, i); + errors = true; + } + + for (int j=0; jnum_pb_type_children; ++j) { + t_pb_type* child = &mode->pb_type_children[j]; + + if (child == nullptr) { + VTR_LOG_ERROR("pb_type '%s' mode #%d, child pb_type #%d is NULL\n", pb_type->name, i, j); + errors = true; + continue; + } + + if (child->parent_mode != mode) { + VTR_LOG_ERROR("pb_type '%s' mode #%d, child pb_type #%d has wrong parent_mode\n", pb_type->name, i, j); + errors = true; + } + + errors |= !check_pbtype_ports_and_pins(child); + } + } + + return !errors; +} + /****************** End Utility functions ******************/ struct ArchReader { @@ -527,7 +614,7 @@ struct ArchReader { auto bel = get_bel_reader(site, str(bel_pin.getBel())); auto bel_name = get_bel_name(site, bel); - auto bel_is_pad = is_pad(bel_name); + auto bel_is_pad = is_pad(str(bel.getName())); pad_exists |= bel_is_pad; all_inout_pins &= dir == INOUT; @@ -668,9 +755,11 @@ struct ArchReader { istr += out_suffix_; ostr += in_suffix_; } else if (pad_exists) { - if (out_bel_name == pad_bel_name) + if (out_bel_name == pad_bel_name) { ostr += in_suffix_; - else { // Create new wire to connect PAD output to the BELs input + } + + if (in_bel_name == pad_bel_name) { // Create new wire to connect PAD output to the BELs input ic_name = wire_name + "_" + pad_bel_pin_name + out_suffix_; istr = pad_bel_name + "." + pad_bel_pin_name + out_suffix_; } @@ -733,9 +822,10 @@ struct ArchReader { auto bel_name = bel.getName(); bool res = bel_cell_mappings_.find(bel_name) != bel_cell_mappings_.end(); + res |= is_pad(str(bel_name)); found |= res; - if (res || is_pad(str(bel_name))) + if (res) take_bels_.insert(bel_name); } @@ -749,6 +839,7 @@ struct ArchReader { auto bel_name = bel.getName(); bool res = bel_cell_mappings_.find(bel_name) != bel_cell_mappings_.end(); + res |= is_pad(str(bel_name)); found |= res; if (res || is_pad(str(bel_name))) @@ -986,6 +1077,8 @@ struct ArchReader { EMPTY.index = index; ltypes_.push_back(EMPTY); + bool errors = false; + for (auto site : siteTypeList) { auto bels = site.getBels(); @@ -1037,6 +1130,7 @@ struct ArchReader { // Add regular BELs int count = 0; for (auto bel : bels) { + auto category = bel.getCategory(); if (bel.getCategory() == SITE_PORT) continue; @@ -1089,9 +1183,100 @@ struct ArchReader { process_interconnects(mode, site); ltypes_.push_back(ltype); + +#ifdef VERBOSE + dump_pbtype(ltype.pb_type); +#endif + errors |= !check_pbtype_ports_and_pins(ltype.pb_type); + } + + VTR_ASSERT_MSG(!errors, "Found errors in pb_type modes, ports or pins!\n"); + if (!errors) { + VTR_LOG("pb_type modes, ports and pins check passed\n"); } } +#ifdef VERBOSE + /** @brief Dumps pb_type structure to log. For debugging purposes */ + void dump_pbtype (t_pb_type* pb_type, size_t indent=0) { + std::string pad(indent, ' '); + + VTR_LOG("%spb_type: '%s'\n", pad.c_str(), pb_type->name); + for (int i=0; inum_ports; ++i) { + auto* port = &pb_type->ports[i]; + std::string type_str; + + switch(port->type) + { + case IN_PORT: + type_str = std::string("input "); + break; + case OUT_PORT: + type_str = std::string("output"); + break; + case INOUT_PORT: + type_str = std::string("inout "); + break; + default: + type_str = std::string("??? "); + break; + } + + VTR_LOG("%s port: %s %s[%d:0]\n", pad.c_str(), + type_str.c_str(), + port->name, + port->num_pins - 1 + ); + } + + for (int i=0; inum_modes; ++i) { + dump_mode(&pb_type->modes[i], indent + 1); + } + } + + /** @brief Dumps pb_type mode structure to log. For debugging purposes */ + void dump_mode (t_mode* mode, size_t indent=0) { + std::string pad(indent, ' '); + + VTR_LOG("%smode: '%s'\n", pad.c_str(), mode->name); + + if (mode->num_pb_type_children) { + for(int i=0; inum_pb_type_children; ++i) { + dump_pbtype(&mode->pb_type_children[i], indent + 1); + } + } + + VTR_LOG("%s interconnect:\n", pad.c_str()); + for (int i=0; inum_interconnect; ++i) { + auto* ic = &mode->interconnect[i]; + std::string type_str; + + switch(ic->type) + { + case COMPLETE_INTERC: + type_str = std::string("compl."); + break; + case DIRECT_INTERC: + type_str = std::string("direct"); + break; + case MUX_INTERC: + type_str = std::string("mux "); + break; + default: + type_str = std::string("??? "); + break; + } + + VTR_LOG("%s %s '%s', '%s' -> '%s'\n", pad.c_str(), + type_str.c_str(), + ic->name, + ic->input_string, + ic->output_string + ); + } + } +#endif + /** @brief Processes a LUT element starting from the intermediate pb type */ 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 @@ -1237,11 +1422,21 @@ struct ArchReader { lut->model = get_model(arch_, std::string(MODEL_NAMES)); lut->num_ports = 2; + lut->num_pins = width + 1; + lut->num_output_pins = 1; + lut->num_input_pins = width; + lut->num_clock_pins = 0; + 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; + lut->ports[0].index = 0; + lut->ports[0].absolute_first_pin_index = 0; + + lut->ports[1].index = 1; + lut->ports[1].absolute_first_pin_index = width; // Set classes pb_type->class_type = LUT_CLASS; @@ -1284,126 +1479,156 @@ struct ArchReader { /** @brief Generates the leaf pb types for the PAD type */ 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; - pad->modes = new t_mode[2]; - // Add PAD pb_type ports + // Get bel pin information VTR_ASSERT(bel.getPins().size() == 1); - std::string pin = str(site.getBelPins()[bel.getPins()[0]].getName()); - std::string ipin = pin + in_suffix_; - std::string opin = pin + out_suffix_; + const auto& bel_pin = site.getBelPins()[bel.getPins()[0]]; + const std::string pin_name = str(bel_pin.getName()); + const auto pin_dir = bel_pin.getDir(); + + // Determine whether the pad is input-only, output-only or inout + // Output pad has input port and vice versa. + bool is_inp = false; + bool is_out = false; + switch (pin_dir) + { + case Netlist::Direction::INPUT: + is_out = true; + break; + case Netlist::Direction::OUTPUT: + is_inp = true; + break; + case Netlist::Direction::INOUT: + is_inp = true; + is_out = true; + break; + default: + VTR_ASSERT(false); + } + + // Init modes + pad->num_modes = (is_inp && is_out) ? 2 : 1; + size_t mode_idx = 0; + pad->modes = new t_mode[pad->num_modes]; + + // Add PAD pb_type port(s) + std::string ipin = pin_name + in_suffix_; + std::string opin = pin_name + out_suffix_; + + size_t num_ports = (is_inp && is_out) ? 2 : 1; + size_t port_idx = 0; + pad->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); - auto num_ports = 2; - auto ports = new t_port[num_ports]; - pad->ports = ports; pad->num_ports = pad->num_pins = num_ports; - pad->num_input_pins = 1; - pad->num_output_pins = 1; + pad->num_input_pins = (int)is_inp; + pad->num_output_pins = (int)is_out; - int pin_abs = 0; - int pin_count = 0; - for (auto dir : {IN_PORT, OUT_PORT}) { - int pins_dir_count = 0; - t_port* port = &ports[pin_count]; + std::vector port_types; + if (is_inp) port_types.push_back(OUT_PORT); // Input pad has output port + if (is_out) port_types.push_back(IN_PORT); // Output pad has input port + + for (auto dir : port_types) { + t_port* port = &pad->ports[port_idx]; port->parent_pb_type = pad; - port->index = pin_count++; - port->port_index_by_type = pins_dir_count++; - port->absolute_first_pin_index = pin_abs++; + port->index = port_idx; + port->port_index_by_type = 0; + port->absolute_first_pin_index = port_idx; port->equivalent = PortEquivalence::NONE; port->num_pins = 1; port->type = dir; port->is_clock = false; - bool is_input = dir == IN_PORT; + bool is_input = (dir == IN_PORT); port->name = is_input ? vtr::strdup(ipin.c_str()) : vtr::strdup(opin.c_str()); port->model_port = nullptr; port->port_class = vtr::strdup(nullptr); port->port_power = (t_port_power*)vtr::calloc(1, sizeof(t_port_power)); + + port_idx++; } // OPAD mode - auto omode = &pad->modes[0]; - omode->name = vtr::strdup("opad"); - omode->parent_pb_type = pad; - omode->index = 0; - omode->num_pb_type_children = 1; - omode->pb_type_children = new t_pb_type[1]; - - auto opad = new t_pb_type; - opad->name = vtr::strdup("opad"); - opad->num_pb = 1; - opad->parent_mode = omode; - - num_ports = 1; - opad->num_ports = num_ports; - opad->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); - opad->blif_model = vtr::strdup(MODEL_OUTPUT); - 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; + if (is_out) { + auto* omode = &pad->modes[mode_idx]; + omode->name = vtr::strdup("opad"); + omode->parent_pb_type = pad; + omode->index = mode_idx; + + omode->num_pb_type_children = 1; + omode->pb_type_children = new t_pb_type[1]; + auto* opad = &omode->pb_type_children[0]; + opad->name = vtr::strdup("opad"); + opad->num_pb = 1; + opad->parent_mode = omode; + + num_ports = 1; + opad->num_ports = num_ports; + opad->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); + opad->blif_model = vtr::strdup(MODEL_OUTPUT); + opad->model = get_model(arch_, std::string(MODEL_OUTPUT)); + + opad->ports[0] = get_generic_port(arch_, opad, IN_PORT, "outpad", MODEL_OUTPUT); + + omode->num_interconnect = 1; + omode->interconnect = new t_interconnect[1]; + auto* o_ic = &omode->interconnect[0]; + + std::string opad_istr = std::string(pad->name) + std::string(".") + ipin; + std::string opad_ostr = std::string(opad->name) + std::string(".outpad"); + std::string o_ic_name = std::string(pad->name) + std::string("_") + std::string(opad->name); + + o_ic->name = vtr::strdup(o_ic_name.c_str()); + o_ic->type = DIRECT_INTERC; + o_ic->parent_mode_index = mode_idx; + o_ic->parent_mode = omode; + o_ic->input_string = vtr::strdup(opad_istr.c_str()); + o_ic->output_string = vtr::strdup(opad_ostr.c_str()); + + mode_idx++; + } // IPAD mode - auto imode = &pad->modes[1]; - imode->name = vtr::strdup("ipad"); - imode->parent_pb_type = pad; - imode->index = 1; - imode->num_pb_type_children = 1; - imode->pb_type_children = new t_pb_type[1]; - - auto ipad = new t_pb_type; - ipad->name = vtr::strdup("ipad"); - ipad->num_pb = 1; - ipad->parent_mode = imode; - - num_ports = 1; - ipad->num_ports = num_ports; - ipad->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); - ipad->blif_model = vtr::strdup(MODEL_INPUT); - 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; - - omode->num_interconnect = num_pins; - omode->interconnect = new t_interconnect[num_pins]; - - imode->num_interconnect = num_pins; - imode->interconnect = new t_interconnect[num_pins]; - - std::string opad_istr = std::string(pad->name) + std::string(".") + ipin; - std::string opad_ostr = std::string(opad->name) + std::string(".outpad"); - std::string o_ic_name = std::string(pad->name) + std::string("_") + std::string(opad->name); - - std::string ipad_istr = std::string(ipad->name) + std::string(".inpad"); - 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]; - - o_ic->name = vtr::strdup(o_ic_name.c_str()); - o_ic->type = DIRECT_INTERC; - o_ic->parent_mode_index = 0; - o_ic->parent_mode = omode; - o_ic->input_string = vtr::strdup(opad_istr.c_str()); - o_ic->output_string = vtr::strdup(opad_ostr.c_str()); - - i_ic->name = vtr::strdup(i_ic_name.c_str()); - i_ic->type = DIRECT_INTERC; - i_ic->parent_mode_index = 0; - 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; + if (is_inp) { + auto* imode = &pad->modes[mode_idx]; + imode->name = vtr::strdup("ipad"); + imode->parent_pb_type = pad; + imode->index = mode_idx; + + imode->num_pb_type_children = 1; + imode->pb_type_children = new t_pb_type[1]; + auto* ipad = &imode->pb_type_children[0]; + + ipad->name = vtr::strdup("ipad"); + ipad->num_pb = 1; + ipad->parent_mode = imode; + + num_ports = 1; + ipad->num_ports = num_ports; + ipad->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); + ipad->blif_model = vtr::strdup(MODEL_INPUT); + ipad->model = get_model(arch_, std::string(MODEL_INPUT)); + + ipad->ports[0] = get_generic_port(arch_, ipad, OUT_PORT, "inpad", MODEL_INPUT); + + imode->num_interconnect = 1; + imode->interconnect = new t_interconnect[1]; + auto* i_ic = &imode->interconnect[0]; + + std::string ipad_istr = std::string(ipad->name) + std::string(".inpad"); + 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); + + i_ic->name = vtr::strdup(i_ic_name.c_str()); + i_ic->type = DIRECT_INTERC; + i_ic->parent_mode_index = mode_idx; + 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()); + + mode_idx++; + } } /** @brief Generates the leaf pb types for a generic intermediate block, with as many modes @@ -1649,16 +1874,17 @@ 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; pb_type->num_output_pins = 0; + pb_type->num_pins = 0; int pin_abs = 0; - int pin_count = 0; + int port_count = 0; for (auto dir : {IN_PORT, OUT_PORT}) { - int pins_dir_count = 0; + int ports_dir_count = 0; for (auto pin_tuple : pins) { std::string pin_name; PORTS pin_dir; @@ -1669,17 +1895,21 @@ struct ArchReader { continue; bool is_input = dir == IN_PORT; - pb_type->num_input_pins += is_input ? 1 : 0; - pb_type->num_output_pins += is_input ? 0 : 1; + pb_type->num_input_pins += is_input ? num_pins : 0; + pb_type->num_output_pins += is_input ? 0 : num_pins; + pb_type->num_pins += num_pins; auto port = get_generic_port(arch_, pb_type, dir, pin_name, /*string_model=*/"", num_pins); - ports[pin_count] = port; - port.index = pin_count++; - port.port_index_by_type = pins_dir_count++; - port.absolute_first_pin_index = pin_abs++; + port.index = port_count; + port.port_index_by_type = ports_dir_count++; + port.absolute_first_pin_index = pin_abs; if (!model.empty()) port.model_port = get_model_port(arch_, model, pin_name); + + pin_abs += num_pins; + + ports[port_count++] = port; } } } @@ -1764,7 +1994,7 @@ struct ArchReader { auto num_pp = pair.second.size(); pp_ic->num_annotations = num_pp; - pp_ic->annotations = new t_pin_to_pin_annotation[num_pp]; + pp_ic->annotations = (t_pin_to_pin_annotation*)vtr::calloc(num_pp, sizeof(t_pin_to_pin_annotation)); int idx = 0; for (auto pp_name : pair.second) @@ -1948,44 +2178,42 @@ struct ArchReader { sub_tile.capacity.set(type.capacity, type.capacity); type.capacity++; - int port_idx = 0; - int abs_first_pin_idx = 0; - int icount = 0; - int ocount = 0; - - std::unordered_map port_name_to_sub_tile_idx; - for (auto dir : {INPUT, OUTPUT}) { - int port_idx_by_type = 0; - for (auto pin : site.getPins()) { - if (pin.getDir() != dir) - continue; - - t_physical_tile_port port; - - port.name = vtr::strdup(str(pin.getName()).c_str()); - - sub_tile.sub_tile_to_tile_pin_indices.push_back(type.num_pins + port_idx); - - port_name_to_sub_tile_idx[str(pin.getName())] = port_idx; - port.index = port_idx++; - - port.absolute_first_pin_index = abs_first_pin_idx++; - port.port_index_by_type = port_idx_by_type++; + // Find ltype + t_logical_block_type* ltype = nullptr; + for (size_t i=0; ipb_type; - sub_tile.ports.push_back(port); + std::unordered_map port_name_to_sub_tile_idx; + for (int i=0; inum_ports; ++i) { + const t_port* pb_port = &pb_type->ports[i]; + + t_physical_tile_port phy_port; + phy_port.name = vtr::strdup(pb_port->name); + phy_port.type = pb_port->type; + phy_port.index = pb_port->index; + phy_port.port_index_by_type = pb_port->port_index_by_type; + phy_port.absolute_first_pin_index = pb_port->absolute_first_pin_index; + + for (int j=0; jnum_pins; ++j) { + sub_tile.sub_tile_to_tile_pin_indices.push_back(type.num_pins + pb_port->index + j); } + + port_name_to_sub_tile_idx[std::string(pb_port->name)] = pb_port->index; + sub_tile.ports.push_back(phy_port); } - auto pins_size = site.getPins().size(); - fill_sub_tile(type, sub_tile, pins_size, icount, ocount, &port_name_to_sub_tile_idx, &site_in_tile); + fill_sub_tile(type, sub_tile, + pb_type->num_pins, + pb_type->num_input_pins, // TODO: handle clock pins + pb_type->num_output_pins, + &port_name_to_sub_tile_idx, &site_in_tile); type.sub_tiles.emplace_back(sub_tile); } @@ -2104,7 +2332,9 @@ struct ArchReader { // Create constant models for (auto const_cell : const_cells) { t_model* model = new t_model; - model->index = arch_->models->index + 1; + + int last = (arch_->models == nullptr) ? -1 : arch_->models->index; + model->index = last + 1; model->never_prune = true; model->name = vtr::strdup(const_cell.first.c_str());