| // Copyright 2020 Project U-Ray Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <vector> |
| #include <iostream> |
| #include <map> |
| #include <string> |
| #include <fstream> |
| #include <stdexcept> |
| #include <iterator> |
| #include <stdarg.h> |
| #include <iomanip> |
| #include <filesystem> |
| #include <map> |
| #include <set> |
| #include <cassert> |
| #include "common.h" |
| |
| ChipData chip; |
| |
| struct Tile { |
| std::string name, type; |
| TileInstance *data; |
| std::set<int> set_bits; |
| std::set<int> unknown_bits; |
| std::set<std::string> matched_features; |
| }; |
| |
| std::vector<Tile> tiles; |
| std::unordered_map<std::string, int> tile_by_name; |
| |
| struct InverseTileBitMap { |
| int tile; |
| int offset_in_frame; |
| int offset_in_tile; |
| int size; |
| }; |
| |
| std::unordered_map<uint32_t, std::vector<InverseTileBitMap>> tiles_by_frame; |
| |
| void parse_bits(const std::string &filename) { |
| LineReader rd(filename); |
| for (auto &line : rd) { |
| assert(line.at(0) == 'F'); |
| const char *curr = line.c_str() + 1; |
| char *next = nullptr; |
| uint32_t frame = std::strtoul(curr, &next, 16); |
| assert(*next == 'W'); |
| curr = next + 1; |
| int word = std::strtol(curr, &next, 10); |
| curr = next + 1; |
| assert(*next == 'B'); |
| int bit = std::strtol(curr, &next, 10); |
| if (tiles_by_frame.count(frame)) { |
| int fb = word * 32 + bit; |
| for (auto &t : tiles_by_frame.at(frame)) { |
| if (fb >= t.offset_in_frame && fb < (t.offset_in_frame + t.size)) { |
| int tilebit = (fb - t.offset_in_frame) + t.offset_in_tile; |
| tiles[t.tile].set_bits.insert(tilebit); |
| tiles[t.tile].unknown_bits.insert(tilebit); |
| } |
| } |
| } |
| } |
| } |
| |
| // Currently have poor quality DBs for these tiles, |
| // skip outputting them |
| std::set<std::string> skip_tiles = { |
| "CLEL_L", "CLEM_R", "RCLK_INT_R", |
| }; |
| |
| |
| void setup_tiles() { |
| for (auto &tile : chip.tiles) { |
| auto &ti = tile.second; |
| if (skip_tiles.count(chip.tiletypes[ti.type].type)) |
| continue; |
| Tile t; |
| t.name = ti.name; |
| t.type = chip.tiletypes[ti.type].type; |
| t.data = &ti; |
| tile_by_name[ti.name] = int(tiles.size()); |
| |
| int off = 0; |
| for (auto &b : ti.bits) { |
| tiles_by_frame[b.frame_offset].push_back(InverseTileBitMap{int(tiles.size()), b.bit_offset, off, b.size}); |
| off += b.size; |
| } |
| |
| tiles.push_back(t); |
| |
| } |
| } |
| |
| |
| void process_tile(Tile &t) { |
| if (t.set_bits.empty()) |
| return; |
| auto &td = chip.load_tile_database(t.name); |
| for (const auto &feat : td.features) { |
| if (feat.second.empty()) |
| continue; |
| bool matched = true; |
| for (auto bit : feat.second) |
| if (!t.set_bits.count(bit)) { |
| matched = false; |
| break; |
| } |
| if (!matched) |
| continue; |
| t.matched_features.insert(feat.first); |
| for (auto bit : feat.second) |
| t.unknown_bits.erase(bit); |
| } |
| } |
| |
| int main(int argc, char *argv[]) { |
| if (argc < 3) { |
| std::cerr << "usage: explain dbdir/ bitstream.dump" << std::endl; |
| return 2; |
| } |
| chip.open(argv[1]); |
| setup_tiles(); |
| parse_bits(argv[2]); |
| for (auto &t : tiles) { |
| process_tile(t); |
| for (auto &f : t.matched_features) |
| std::cout << t.name << "." << f << std::endl; |
| for (auto b : t.unknown_bits) |
| std::cout << t.name << ".?" << b << std::endl; |
| if (!t.matched_features.empty() || !t.unknown_bits.empty()) |
| std::cout << std::endl; |
| } |
| } |