| #include "Chip.hpp" |
| #include "Tile.hpp" |
| #include "Database.hpp" |
| #include "Util.hpp" |
| #include "RoutingGraph.hpp" |
| #include "BitDatabase.hpp" |
| #include "Bels.hpp" |
| #include <algorithm> |
| #include <iostream> |
| using namespace std; |
| |
| namespace Trellis { |
| |
| Chip::Chip(string name) : Chip(get_chip_info(find_device_by_name(name))) |
| {} |
| |
| Chip::Chip(uint32_t idcode) : Chip(get_chip_info(find_device_by_idcode(idcode))) |
| {} |
| |
| Chip::Chip(const Trellis::ChipInfo &info) : info(info), cram(info.num_frames, info.bits_per_frame) |
| { |
| vector<TileInfo> allTiles = get_device_tilegrid(DeviceLocator{info.family, info.name}); |
| for (const auto &tile : allTiles) { |
| tiles[tile.name] = make_shared<Tile>(tile, *this); |
| int row, col; |
| tie(row, col) = tile.get_row_col(); |
| if (int(tiles_at_location.size()) <= row) { |
| tiles_at_location.resize(row+1); |
| } |
| if (int(tiles_at_location.at(row).size()) <= col) { |
| tiles_at_location.at(row).resize(col+1); |
| } |
| tiles_at_location.at(row).at(col).push_back(make_pair(tile.name, tile.type)); |
| } |
| global_data = get_global_info(DeviceLocator{info.family, info.name}); |
| } |
| |
| shared_ptr<Tile> Chip::get_tile_by_name(string name) |
| { |
| return tiles.at(name); |
| } |
| |
| vector<shared_ptr<Tile>> Chip::get_tiles_by_position(int row, int col) |
| { |
| vector<shared_ptr<Tile>> result; |
| for (const auto &tile : tiles) { |
| if (tile.second->info.get_row_col() == make_pair(row, col)) |
| result.push_back(tile.second); |
| } |
| return result; |
| } |
| |
| string Chip::get_tile_by_position_and_type(int row, int col, string type) { |
| for (const auto &tile : tiles_at_location.at(row).at(col)) { |
| if (tile.second == type) |
| return tile.first; |
| } |
| throw runtime_error(fmt("no suitable tile found at R" << row << "C" << col)); |
| } |
| |
| string Chip::get_tile_by_position_and_type(int row, int col, set<string> type) { |
| for (const auto &tile : tiles_at_location.at(row).at(col)) { |
| if (type.find(tile.second) != type.end()) |
| return tile.first; |
| } |
| throw runtime_error(fmt("no suitable tile found at R" << row << "C" << col)); |
| } |
| |
| |
| vector<shared_ptr<Tile>> Chip::get_tiles_by_type(string type) |
| { |
| vector<shared_ptr<Tile>> result; |
| for (const auto &tile : tiles) { |
| if (tile.second->info.type == type) |
| result.push_back(tile.second); |
| } |
| return result; |
| } |
| |
| vector<shared_ptr<Tile>> Chip::get_all_tiles() |
| { |
| vector<shared_ptr<Tile>> result; |
| for (const auto &tile : tiles) { |
| result.push_back(tile.second); |
| } |
| return result; |
| } |
| |
| int Chip::get_max_row() const |
| { |
| return info.max_row; |
| } |
| |
| int Chip::get_max_col() const |
| { |
| return info.max_col; |
| } |
| |
| ChipDelta operator-(const Chip &a, const Chip &b) |
| { |
| ChipDelta delta; |
| for (const auto &tile : a.tiles) { |
| CRAMDelta cd = tile.second->cram - b.tiles.at(tile.first)->cram; |
| if (!cd.empty()) |
| delta[tile.first] = cd; |
| } |
| return delta; |
| } |
| |
| shared_ptr<RoutingGraph> Chip::get_routing_graph() |
| { |
| shared_ptr<RoutingGraph> rg(new RoutingGraph(*this)); |
| //cout << "Building routing graph" << endl; |
| for (auto tile_entry : tiles) { |
| shared_ptr<Tile> tile = tile_entry.second; |
| //cout << " Tile " << tile->info.name << endl; |
| shared_ptr<TileBitDatabase> bitdb = get_tile_bitdata(TileLocator{info.family, info.name, tile->info.type}); |
| bitdb->add_routing(tile->info, *rg); |
| int x, y; |
| tie(y, x) = tile->info.get_row_col(); |
| // SLICE Bels |
| if (tile->info.type == "PLC2") { |
| for (int z = 0; z < 4; z++) |
| Bels::add_lc(*rg, x, y, z); |
| } |
| // PIO Bels |
| if (tile->info.type.find("PICL0") != string::npos || tile->info.type.find("PICR0") != string::npos) |
| for (int z = 0; z < 4; z++) { |
| Bels::add_pio(*rg, x, y, z); |
| Bels::add_iologic(*rg, x, y, z, false); |
| } |
| if (tile->info.type.find("PIOT0") != string::npos || (tile->info.type.find("PICB0") != string::npos && tile->info.type != "SPICB0")) |
| for (int z = 0; z < 2; z++) { |
| Bels::add_pio(*rg, x, y, z); |
| Bels::add_iologic(*rg, x, y, z, true); |
| } |
| // DCC Bels |
| if (tile->info.type == "LMID_0") |
| for (int z = 0; z < 14; z++) |
| Bels::add_dcc(*rg, x, y, "L", std::to_string(z)); |
| if (tile->info.type == "RMID_0") |
| for (int z = 0; z < 14; z++) |
| Bels::add_dcc(*rg, x, y, "R", std::to_string(z)); |
| if (tile->info.type == "TMID_0") |
| for (int z = 0; z < 12; z++) |
| Bels::add_dcc(*rg, x, y, "T", std::to_string(z)); |
| if (tile->info.type == "BMID_0V" || tile->info.type == "BMID_0H") |
| for (int z = 0; z < 16; z++) |
| Bels::add_dcc(*rg, x, y, "B", std::to_string(z)); |
| // RAM Bels |
| if (tile->info.type == "MIB_EBR0" || tile->info.type == "EBR_CMUX_UR" || tile->info.type == "EBR_CMUX_LR" |
| || tile->info.type == "EBR_CMUX_LR_25K") |
| Bels::add_bram(*rg, x, y, 0); |
| if (tile->info.type == "MIB_EBR2") |
| Bels::add_bram(*rg, x, y, 1); |
| if (tile->info.type == "MIB_EBR4") |
| Bels::add_bram(*rg, x, y, 2); |
| if (tile->info.type == "MIB_EBR6") |
| Bels::add_bram(*rg, x, y, 3); |
| // DSP Bels |
| if (tile->info.type == "MIB_DSP0") |
| Bels::add_mult18(*rg, x, y, 0); |
| if (tile->info.type == "MIB_DSP1") |
| Bels::add_mult18(*rg, x, y, 1); |
| if (tile->info.type == "MIB_DSP4") |
| Bels::add_mult18(*rg, x, y, 4); |
| if (tile->info.type == "MIB_DSP5") |
| Bels::add_mult18(*rg, x, y, 5); |
| if (tile->info.type == "MIB_DSP3") |
| Bels::add_alu54b(*rg, x, y, 3); |
| if (tile->info.type == "MIB_DSP7") |
| Bels::add_alu54b(*rg, x, y, 7); |
| // PLL Bels |
| if (tile->info.type == "PLL0_UL") |
| Bels::add_pll(*rg, "UL", x+1, y); |
| if (tile->info.type == "PLL0_LL") |
| Bels::add_pll(*rg, "LL", x, y-1); |
| if (tile->info.type == "PLL0_LR") |
| Bels::add_pll(*rg, "LR", x, y-1); |
| if (tile->info.type == "PLL0_UR") |
| Bels::add_pll(*rg, "UR", x-1, y); |
| // DCU and ancillary Bels |
| if (tile->info.type == "DCU0") { |
| Bels::add_dcu(*rg, x, y); |
| Bels::add_extref(*rg, x, y); |
| } |
| if (tile->info.type == "BMID_0H") |
| for (int z = 0; z < 2; z++) |
| Bels::add_pcsclkdiv(*rg, x, y-1, z); |
| // Config/system Bels |
| if (tile->info.type == "EFB0_PICB0") { |
| Bels::add_misc(*rg, "GSR", x, y-1); |
| Bels::add_misc(*rg, "JTAGG", x, y-1); |
| Bels::add_misc(*rg, "OSCG", x, y-1); |
| Bels::add_misc(*rg, "SEDGA", x, y-1); |
| } |
| if (tile->info.type == "DTR") |
| Bels::add_misc(*rg, "DTR", x, y-1); |
| if (tile->info.type == "EFB1_PICB1") |
| Bels::add_misc(*rg, "USRMCLK", x-5, y); |
| if (tile->info.type == "ECLK_L") { |
| Bels::add_ioclk_bel(*rg, "CLKDIVF", x-2, y, 0, 7); |
| Bels::add_ioclk_bel(*rg, "CLKDIVF", x-2, y, 1, 6); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y, 0, 7); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y, 1, 7); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y+1, 0, 6); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x-2, y+1, 1, 6); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y, 0, 7); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y, 1, 7); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y+1, 0, 6); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x-2, y+1, 1, 6); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y-1, 0); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y, 0); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y+1, 0); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x-2, y+2, 0); |
| } |
| if (tile->info.type == "ECLK_R") { |
| Bels::add_ioclk_bel(*rg, "CLKDIVF", x+2, y, 0); |
| Bels::add_ioclk_bel(*rg, "CLKDIVF", x+2, y, 1); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y, 0, 2); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y, 1, 2); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y+1, 0, 3); |
| Bels::add_ioclk_bel(*rg, "ECLKSYNCB", x+2, y+1, 1, 3); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y, 0, 2); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y, 1, 2); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y+1, 0, 3); |
| Bels::add_ioclk_bel(*rg, "TRELLIS_ECLKBUF", x+2, y+1, 1, 3); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y-1, 0); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y, 0); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y+1, 0); |
| Bels::add_ioclk_bel(*rg, "DLLDELD", x+2, y+2, 0); |
| } |
| if (tile->info.type == "DDRDLL_UL") |
| Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y-10, 0); |
| if (tile->info.type == "DDRDLL_ULA") |
| Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y-13, 0); |
| if (tile->info.type == "DDRDLL_UR") |
| Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y-10, 0); |
| if (tile->info.type == "DDRDLL_URA") |
| Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y-13, 0); |
| if (tile->info.type == "DDRDLL_LL") |
| Bels::add_ioclk_bel(*rg, "DDRDLL", x-2, y+13, 0); |
| if (tile->info.type == "DDRDLL_LR") |
| Bels::add_ioclk_bel(*rg, "DDRDLL", x+2, y+13, 0); |
| if (tile->info.type == "PICL0_DQS2" || tile->info.type == "PICR0_DQS2") |
| Bels::add_ioclk_bel(*rg, "DQSBUFM", x, y, 0); |
| |
| } |
| return rg; |
| } |
| |
| // Global network funcs |
| |
| bool GlobalRegion::matches(int row, int col) const { |
| return (row >= y0 && row <= y1 && col >= x0 && col <= x1); |
| } |
| |
| bool TapSegment::matches_left(int row, int col) const { |
| UNUSED(row); |
| return (col >= lx0 && col <= lx1); |
| } |
| |
| bool TapSegment::matches_right(int row, int col) const { |
| UNUSED(row); |
| return (col >= rx0 && col <= rx1); |
| } |
| |
| string GlobalsInfo::get_quadrant(int row, int col) const { |
| for (const auto &quad : quadrants) { |
| if (quad.matches(row, col)) |
| return quad.name; |
| } |
| throw runtime_error(fmt("R" << row << "C" << col << " matches no globals quadrant")); |
| } |
| |
| TapDriver GlobalsInfo::get_tap_driver(int row, int col) const { |
| for (const auto &seg : tapsegs) { |
| if (seg.matches_left(row, col)) { |
| TapDriver td; |
| td.dir = TapDriver::LEFT; |
| td.col = seg.tap_col; |
| return td; |
| } |
| if (seg.matches_right(row, col)) { |
| TapDriver td; |
| td.dir = TapDriver::RIGHT; |
| td.col = seg.tap_col; |
| return td; |
| } |
| } |
| throw runtime_error(fmt("R" << row << "C" << col << " matches no global TAP_DRIVE segment")); |
| } |
| |
| pair<int, int> GlobalsInfo::get_spine_driver(std::string quadrant, int col) { |
| for (const auto &seg : spinesegs) { |
| if (seg.quadrant == quadrant && seg.tap_col == col) { |
| return make_pair(seg.spine_row, seg.spine_col); |
| } |
| } |
| throw runtime_error(fmt(quadrant << "C" << col << " matches no global SPINE segment")); |
| } |
| |
| |
| } |