blob: acc1d07b071c9aa0708c3f006e4ed610c28d1bc6 [file] [log] [blame]
// 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;
}
}