244 lines
6.3 KiB
C++
244 lines
6.3 KiB
C++
#include "accumulation.h"
|
|
|
|
#include <iostream>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
static std::size_t next_global_target_uid = 0;
|
|
|
|
std::unordered_map<std::size_t, TARGET> targets;
|
|
std::unordered_map<std::string, DPIN> global_dpins;
|
|
std::unordered_map<std::string, CU> units;
|
|
|
|
static bool global_target_field_cmp(const TARGET& a, const TARGET& b) {
|
|
// TODO
|
|
return true;
|
|
}
|
|
|
|
static bool global_target_cmp(const TARGET& a, const TARGET& b) {
|
|
// Note -> Later, use hash of type (generated by pinpoint plugin)
|
|
|
|
if (a.name != b.name)
|
|
return false;
|
|
|
|
if (a.size != b.size || !global_target_field_cmp(a, b)) {
|
|
std::cerr << "WARNING: Got different definitions of \"" << a.name << "\" -> detached randomization" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static std::size_t accumulate_global_target(TARGET&& target) {
|
|
for (const auto& [guid, gtarget] : targets) {
|
|
if (global_target_cmp(gtarget, target))
|
|
return guid;
|
|
}
|
|
|
|
std::size_t guid = next_global_target_uid++;
|
|
targets.emplace(guid, std::move(target));
|
|
return guid;
|
|
}
|
|
|
|
/*
|
|
<sourcefile>.spslr:
|
|
|
|
SPSLR <CU filename> <CU uid symbol>
|
|
target <name> <local uid> <size> <field count>
|
|
f <offset> <size> <alignment> <flags>
|
|
f <offset> <size> <alignment> <flags>
|
|
...
|
|
ipin <label> <target uid> <field offset>
|
|
ipin <label> <target uid> <field offset>
|
|
ipin <label> <target uid> <field offset>
|
|
...
|
|
dpin <local/global> <symbol> <offset> <level> <target uid>
|
|
dpin <local/global> <symbol> <offset> <level> <target uid>
|
|
...
|
|
*/
|
|
static bool accumulate_file(const fs::path& path) {
|
|
std::ifstream infile(path);
|
|
if (!infile)
|
|
return false;
|
|
|
|
std::string hdr_line;
|
|
if (!std::getline(infile, hdr_line))
|
|
return false;
|
|
|
|
std::istringstream hdr_iss(hdr_line);
|
|
|
|
std::string hdr_magic, hdr_cu_file, hdr_cu_uid;
|
|
|
|
if (!(hdr_iss >> hdr_magic) || hdr_magic != "SPSLR")
|
|
return false;
|
|
|
|
if (!(hdr_iss >> hdr_cu_file) || !(hdr_iss >> hdr_cu_uid))
|
|
return false;
|
|
|
|
std::cout << "Parsing " << path << std::endl;
|
|
std::cout << " Source file -> " << hdr_cu_file << std::endl;
|
|
std::cout << " Unit UID -> " << hdr_cu_uid << std::endl;
|
|
|
|
if (units.contains(hdr_cu_uid)) {
|
|
std::cerr << "Duplicate unit UID -> " << hdr_cu_uid << std::endl;
|
|
return false;
|
|
}
|
|
|
|
units.emplace(hdr_cu_uid, CU{});
|
|
CU& cu = units.at(hdr_cu_uid);
|
|
|
|
std::string line;
|
|
while (std::getline(infile, line)) {
|
|
if (line.empty())
|
|
continue;
|
|
|
|
std::istringstream iss(line);
|
|
std::string type;
|
|
|
|
if (!(iss >> type))
|
|
return false;
|
|
|
|
if (type == "target") {
|
|
TARGET target;
|
|
|
|
std::size_t local_uid, field_count;
|
|
|
|
if (!(iss >> target.name) || !(iss >> local_uid) || !(iss >> target.size) || !(iss >> field_count)) {
|
|
std::cerr << "Invalid target line" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
if (cu.local_targets.contains(local_uid)) {
|
|
std::cerr << "Duplicate local target uid -> " << local_uid << std::endl;
|
|
return false;
|
|
}
|
|
|
|
for (std::size_t i = 0; i < field_count; i++) {
|
|
std::string fline;
|
|
if (!std::getline(infile, fline)) {
|
|
std::cerr << "Missing field declaration line!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
std::istringstream fiss(fline);
|
|
|
|
std::string ftype;
|
|
if (!(fiss >> ftype) || ftype != "f") {
|
|
std::cerr << "Missing field declaration line, got \"" << ftype << "\" instead!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
FIELD field;
|
|
if (!(fiss >> field.offset) || !(fiss >> field.size) || !(fiss >> field.alignment) || !(fiss >> field.flags)) {
|
|
std::cerr << "Failed to parse field declaration line!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// Note -> could do sanity checks here
|
|
|
|
if (target.fields.contains(field.offset)) {
|
|
std::cerr << "Duplicate field offset!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
target.fields.emplace(field.offset, field);
|
|
}
|
|
|
|
auto fit = target.fields.begin();
|
|
for (std::size_t i = 0; i < field_count; i++) {
|
|
fit->second.idx = i;
|
|
fit++;
|
|
}
|
|
|
|
std::size_t global_target_uid = accumulate_global_target(std::move(target));
|
|
cu.local_targets.emplace(local_uid, global_target_uid);
|
|
continue;
|
|
} else if (type == "ipin") {
|
|
IPIN ipin;
|
|
if (!(iss >> ipin.symbol) || !(iss >> ipin.local_target) || !(iss >> ipin.field_offset)) {
|
|
std::cerr << "Failed to parse ipin declaration!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
if (cu.ipins.contains(ipin.symbol)) {
|
|
std::cerr << "Duplicate ipin for symbol \"" << ipin.symbol << "\"!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
cu.ipins.emplace(ipin.symbol, ipin);
|
|
continue;
|
|
} else if (type == "dpin") {
|
|
std::string symbol;
|
|
std::string scope;
|
|
DPIN::COMPONENT comp;
|
|
std::size_t local_target;
|
|
|
|
if (!(iss >> scope) || !(iss >> symbol) || !(iss >> comp.offset) ||
|
|
!(iss >> comp.level) || !(iss >> local_target)) {
|
|
std::cerr << "Failed to parse dpin declaration!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
if (scope == "l" || scope == "L") {
|
|
if (!cu.dpins.contains(symbol))
|
|
cu.dpins.emplace(symbol, DPIN{ .symbol=symbol });
|
|
|
|
DPIN& dpin = cu.dpins.at(symbol);
|
|
|
|
if (!cu.local_targets.contains(local_target)) {
|
|
std::cerr << "Local datapin references target that has not yet been parsed!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
comp.target = local_target;
|
|
dpin.components.push_back(comp);
|
|
} else if (scope == "g" || scope == "G") {
|
|
if (!global_dpins.contains(symbol))
|
|
global_dpins.emplace(symbol, DPIN{ .symbol=symbol });
|
|
|
|
DPIN& dpin = global_dpins.at(symbol);
|
|
|
|
if (!cu.local_targets.contains(local_target)) {
|
|
std::cerr << "Global datapin references target that has not yet been parsed!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
comp.target = cu.local_targets.at(local_target);
|
|
dpin.components.push_back(comp);
|
|
} else {
|
|
std::cerr << "Unexpected scope of dpin (\"" << scope << "\"), expected \"l\" or \"g\"!" << std::endl;
|
|
return false;
|
|
}
|
|
|
|
continue;
|
|
} else {
|
|
std::cerr << "Invalid spslr file line beginning: \"" << type << "\"" << std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool accumulate(const std::string& spslr_dir) {
|
|
fs::path spslr_root { spslr_dir };
|
|
|
|
if (!fs::exists(spslr_root) || !fs::is_directory(spslr_root))
|
|
return false;
|
|
|
|
for (const auto& dir_entry : fs::recursive_directory_iterator(spslr_root)) {
|
|
if (!dir_entry.is_regular_file())
|
|
continue;
|
|
|
|
if (!dir_entry.path().string().ends_with(".spslr"))
|
|
continue;
|
|
|
|
if (!accumulate_file(dir_entry.path()))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|