| #include "Database.hpp" | |
| #include "Chip.hpp" | |
| #include "Tile.hpp" | |
| #include "Util.hpp" | |
| #include "BitDatabase.hpp" | |
| #include <iostream> | |
| #include <boost/optional.hpp> | |
| #include <boost/property_tree/ptree.hpp> | |
| #include <boost/property_tree/json_parser.hpp> | |
| #include <stdexcept> | |
| #include <mutex> | |
| namespace pt = boost::property_tree; | |
| namespace Trellis { | |
| static string db_root = ""; | |
| static pt::ptree devices_info; | |
| // Cache Tilegrid data, to save time parsing it again | |
| static map<string, pt::ptree> tilegrid_cache; | |
| static mutex tilegrid_cache_mutex; | |
| void load_database(string root) { | |
| db_root = root; | |
| pt::read_json(root + "/" + "devices.json", devices_info); | |
| } | |
| // Iterate through all family and device permutations | |
| // T should return true in case of a match | |
| template<typename T> | |
| boost::optional<DeviceLocator> find_device_generic(T f) { | |
| for (const pt::ptree::value_type &family : devices_info.get_child("families")) { | |
| for (const pt::ptree::value_type &dev : family.second.get_child("devices")) { | |
| bool res = f(dev.first, dev.second); | |
| if (res) | |
| return boost::make_optional(DeviceLocator{family.first, dev.first}); | |
| } | |
| } | |
| return boost::optional<DeviceLocator>(); | |
| } | |
| DeviceLocator find_device_by_name(string name) { | |
| auto found = find_device_generic([name](const string &n, const pt::ptree &p) -> bool { | |
| UNUSED(p); | |
| return n == name; | |
| }); | |
| if (!found) | |
| throw runtime_error("no device in database with name " + name); | |
| return *found; | |
| } | |
| // Hex is not allowed in JSON, to avoid an ugly decimal integer use a string instead | |
| // But we need to parse this back to a uint32_t | |
| uint32_t parse_uint32(string str) { | |
| return uint32_t(strtoul(str.c_str(), nullptr, 0)); | |
| } | |
| DeviceLocator find_device_by_idcode(uint32_t idcode) { | |
| auto found = find_device_generic([idcode](const string &n, const pt::ptree &p) -> bool { | |
| UNUSED(n); | |
| return parse_uint32(p.get<string>("idcode")) == idcode; | |
| }); | |
| if (!found) | |
| throw runtime_error("no device in database with IDCODE " + uint32_to_hexstr(idcode)); | |
| return *found; | |
| } | |
| ChipInfo get_chip_info(const DeviceLocator &part) { | |
| pt::ptree dev = devices_info.get_child("families").get_child(part.family).get_child("devices").get_child( | |
| part.device); | |
| ChipInfo ci; | |
| ci.family = part.family; | |
| ci.name = part.device; | |
| ci.num_frames = dev.get<int>("frames"); | |
| ci.bits_per_frame = dev.get<int>("bits_per_frame"); | |
| ci.pad_bits_after_frame = dev.get<int>("pad_bits_after_frame"); | |
| ci.pad_bits_before_frame = dev.get<int>("pad_bits_before_frame"); | |
| ci.idcode = parse_uint32(dev.get<string>("idcode")); | |
| ci.max_row = dev.get<int>("max_row"); | |
| ci.max_col = dev.get<int>("max_col"); | |
| ci.col_bias = dev.get<int>("col_bias"); | |
| return ci; | |
| } | |
| GlobalsInfo get_global_info(const DeviceLocator &part) { | |
| string glbdata_path = db_root + "/" + part.family + "/" + part.device + "/globals.json"; | |
| pt::ptree glb_parsed; | |
| pt::read_json(glbdata_path, glb_parsed); | |
| GlobalsInfo glbs; | |
| for (const pt::ptree::value_type &quad : glb_parsed.get_child("quadrants")) { | |
| GlobalRegion rg; | |
| rg.name = quad.first; | |
| rg.x0 = quad.second.get<int>("x0"); | |
| rg.x1 = quad.second.get<int>("x1"); | |
| rg.y0 = quad.second.get<int>("y0"); | |
| rg.y1 = quad.second.get<int>("y1"); | |
| glbs.quadrants.push_back(rg); | |
| } | |
| for (const pt::ptree::value_type &tap : glb_parsed.get_child("taps")) { | |
| TapSegment ts; | |
| assert(tap.first[0] == 'C'); | |
| ts.tap_col = stoi(tap.first.substr(1)); | |
| ts.lx0 = tap.second.get<int>("lx0"); | |
| ts.lx1 = tap.second.get<int>("lx1"); | |
| ts.rx0 = tap.second.get<int>("rx0"); | |
| ts.rx1 = tap.second.get<int>("rx1"); | |
| glbs.tapsegs.push_back(ts); | |
| } | |
| for (const pt::ptree::value_type &spine : glb_parsed.get_child("spines")) { | |
| SpineSegment ss; | |
| ss.quadrant = spine.first.substr(0, 2); | |
| ss.tap_col = stoi(spine.first.substr(2)); | |
| ss.spine_row = spine.second.get<int>("y"); | |
| ss.spine_col = spine.second.get<int>("x"); | |
| glbs.spinesegs.push_back(ss); | |
| } | |
| return glbs; | |
| } | |
| vector<TileInfo> get_device_tilegrid(const DeviceLocator &part) { | |
| vector <TileInfo> tilesInfo; | |
| assert(db_root != ""); | |
| string tilegrid_path = db_root + "/" + part.family + "/" + part.device + "/tilegrid.json"; | |
| { | |
| ChipInfo info = get_chip_info(part); | |
| lock_guard <mutex> lock(tilegrid_cache_mutex); | |
| if (tilegrid_cache.find(part.device) == tilegrid_cache.end()) { | |
| pt::ptree tg_parsed; | |
| pt::read_json(tilegrid_path, tg_parsed); | |
| tilegrid_cache[part.device] = tg_parsed; | |
| } | |
| const pt::ptree &tg = tilegrid_cache[part.device]; | |
| for (const pt::ptree::value_type &tile : tg) { | |
| TileInfo ti; | |
| ti.family = part.family; | |
| ti.device = part.device; | |
| ti.max_col = info.max_col; | |
| ti.max_row = info.max_row; | |
| ti.col_bias = info.col_bias; | |
| ti.name = tile.first; | |
| ti.num_frames = size_t(tile.second.get<int>("cols")); | |
| ti.bits_per_frame = size_t(tile.second.get<int>("rows")); | |
| ti.bit_offset = size_t(tile.second.get<int>("start_bit")); | |
| ti.frame_offset = size_t(tile.second.get<int>("start_frame")); | |
| ti.type = tile.second.get<string>("type"); | |
| for (const pt::ptree::value_type &site : tile.second.get_child("sites")) { | |
| SiteInfo si; | |
| si.type = site.second.get<string>("name"); | |
| si.col = site.second.get<int>("pos_col"); | |
| si.row = site.second.get<int>("pos_row"); | |
| ti.sites.push_back(si); | |
| } | |
| tilesInfo.push_back(ti); | |
| } | |
| } | |
| return tilesInfo; | |
| } | |
| static unordered_map<TileLocator, shared_ptr<TileBitDatabase>> bitdb_store; | |
| static mutex bitdb_store_mutex; | |
| shared_ptr<TileBitDatabase> get_tile_bitdata(const TileLocator &tile) { | |
| lock_guard <mutex> bitdb_store_lg(bitdb_store_mutex); | |
| if (bitdb_store.find(tile) == bitdb_store.end()) { | |
| assert(!db_root.empty()); | |
| string bitdb_path = db_root + "/" + tile.family + "/tiledata/" + tile.tiletype + "/bits.db"; | |
| shared_ptr <TileBitDatabase> bitdb{new TileBitDatabase(bitdb_path)}; | |
| bitdb_store[tile] = bitdb; | |
| return bitdb; | |
| } else { | |
| return bitdb_store.at(tile); | |
| } | |
| } | |
| } |