blob: 481e84247e9fe4a57f38ddc10d6b40442da8b0b7 [file] [log] [blame]
#ifndef COMMON_H
#define COMMON_H
#include <stdint.h>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <map>
#include <set>
#include <unordered_map>
#include <stdarg.h>
constexpr uint32_t kCrc32CastagnoliPolynomial = 0x82F63B78;
// From prjxray
// The CRC is calculated from each written data word and the current
// register address the data is written to.
// Extend the current CRC value with one register address (5bit) and
// frame data (32bit) pair and return the newly computed CRC value.
inline uint32_t icap_crc(uint32_t addr, uint32_t data, uint32_t prev) {
constexpr int kAddressBitWidth = 5;
constexpr int kDataBitWidth = 32;
uint64_t poly = static_cast<uint64_t>(kCrc32CastagnoliPolynomial) << 1;
uint64_t val = (static_cast<uint64_t>(addr) << 32) | data;
uint64_t crc = prev;
for (int i = 0; i < kAddressBitWidth + kDataBitWidth; i++) {
if ((val & 1) != (crc & 1))
crc ^= poly;
val >>= 1;
crc >>= 1;
}
return crc;
}
// From Yosys
inline std::string vstringf(const char *fmt, va_list ap)
{
std::string string;
char *str = NULL;
#if defined(_WIN32 )|| defined(__CYGWIN__)
int sz = 64, rc;
while (1) {
va_list apc;
va_copy(apc, ap);
str = (char*)realloc(str, sz);
rc = vsnprintf(str, sz, fmt, apc);
va_end(apc);
if (rc >= 0 && rc < sz)
break;
sz *= 2;
}
#else
if (vasprintf(&str, fmt, ap) < 0)
str = NULL;
#endif
if (str != NULL) {
string = str;
free(str);
}
return string;
}
inline std::string stringf(const char *fmt, ...)
{
std::string string;
va_list ap;
va_start(ap, fmt);
string = vstringf(fmt, ap);
va_end(ap);
return string;
}
// Bitstream definitions
enum BitstreamOp : uint8_t {
OP_NOP = 0,
OP_READ = 1,
OP_WRITE = 2
};
// File and database convenience functions
// Line-by-line reader, skipping over blank lines and comments
struct LineReader {
LineReader(const std::string &filename) {
in.open(filename);
if (!in) {
throw std::runtime_error("failed to open " + filename);
}
}
std::ifstream in;
std::string linebuf;
bool at_sof = true;
struct iterator {
LineReader *parent = nullptr;
bool at_end = false;
inline bool operator!=(const iterator &other) const {
return at_end != other.at_end;
};
inline const std::string& operator*() const {
return parent->linebuf;
}
inline iterator &operator++() {
parent->next();
at_end = parent->linebuf.empty();
return *this;
}
};
void next() {
while (std::getline(in, linebuf)) {
auto cpos = linebuf.find('#');
if (cpos != std::string::npos)
linebuf = linebuf.substr(0, cpos);
if (linebuf.empty())
continue;
linebuf = linebuf.substr(linebuf.find_first_not_of(" \t"));
if (linebuf.empty())
continue;
break;
}
at_sof = false;
}
iterator begin() {
if (at_sof)
next();
return iterator{this, linebuf.empty()};
}
iterator end() {
return iterator{this, true};
}
};
struct TileInstance {
std::string name;
int type;
int x, y;
struct TileBitMapping {
int frame_offset;
int bit_offset;
int size;
};
std::vector<TileBitMapping> bits;
};
struct TileType {
std::string type;
bool loaded_db = false;
std::unordered_map<std::string, std::vector<int>> features;
};
struct ChipData {
std::string root;
void open(const std::string &root);
void load_frames();
void load_tiles();
void load_tiletype_database(int type);
std::unordered_map<std::string, TileInstance> tiles;
inline TileInstance &get_tile_by_name(const std::string &name) {
return tiles.at(name);
}
std::vector<TileType> tiletypes;
std::unordered_map<std::string, int> tiletype_by_name;
TileType &get_tiletype_by_name(const std::string &name) {
return tiletypes.at(tiletype_by_name.at(name));
}
TileType &load_tile_database(const std::string &tile) {
int type = tiles.at(tile).type;
load_tiletype_database(type);
return tiletypes.at(type);
}
std::set<uint32_t> all_frames;
};
inline void split_str(const std::string &s, std::vector<std::string> &dest, const std::string &delim = " ", bool skip_empty = true, int lim = -1) {
dest.clear();
std::string buf;
for (char c : s) {
if (delim.find(c) != std::string::npos && (lim == -1 || int(dest.size()) < lim)) {
if (!buf.empty() || !skip_empty)
dest.push_back(buf);
buf.clear();
} else {
buf += c;
}
}
if (!buf.empty())
dest.push_back(buf);
}
#endif