OpenFPGA/libs/libarchopenfpga/src/config_protocol.cpp

261 lines
8.9 KiB
C++
Raw Normal View History

2023-04-22 02:09:39 -05:00
#include "openfpga_tokenizer.h"
#include "config_protocol.h"
#include "vtr_assert.h"
#include "vtr_log.h"
/************************************************************************
* Member functions for class ConfigProtocol
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
2023-04-21 04:01:51 -05:00
ConfigProtocol::ConfigProtocol() {
INDICE_STRING_DELIM_ = ',';
}
/************************************************************************
* Public Accessors
***********************************************************************/
e_config_protocol_type ConfigProtocol::type() const { return type_; }
std::string ConfigProtocol::memory_model_name() const {
return memory_model_name_;
}
CircuitModelId ConfigProtocol::memory_model() const { return memory_model_; }
int ConfigProtocol::num_regions() const { return num_regions_; }
2023-04-22 02:09:39 -05:00
std::vector<openfpga::BasicPort> ConfigProtocol::prog_clock_ports() const {
std::vector<openfpga::BasicPort> keys;
2023-04-21 04:01:51 -05:00
for (const auto& [k, v] : prog_clk_ccff_head_indices_) {
keys.push_back(k);
}
return keys;
}
2023-04-22 02:09:39 -05:00
std::string ConfigProtocol::prog_clock_port_ccff_head_indices_str(const openfpga::BasicPort& port) const {
2023-04-21 04:01:51 -05:00
std::string ret("");
2023-04-21 23:44:34 -05:00
std::vector<size_t> raw = prog_clock_port_ccff_head_indices(port);
if (!raw.empty()) {
for (size_t idx : raw) {
2023-04-21 04:01:51 -05:00
/* TODO: We need a join function */
2023-04-22 02:09:39 -05:00
ret += std::to_string(idx) + std::to_string(INDICE_STRING_DELIM_);
2023-04-21 04:01:51 -05:00
}
/* Remove the last comma */
2023-04-22 02:09:39 -05:00
ret.pop_back();
2023-04-21 04:01:51 -05:00
}
return ret;
}
2023-04-22 02:09:39 -05:00
std::vector<size_t> ConfigProtocol::prog_clock_port_ccff_head_indices(const openfpga::BasicPort& port) const {
2023-04-21 23:44:34 -05:00
std::vector<size_t> ret;
2023-04-22 02:09:39 -05:00
auto result = prog_clk_ccff_head_indices_.find(port);
if (result != prog_clk_ccff_head_indices_.end()) {
2023-04-21 23:44:34 -05:00
return result->second;
}
return ret;
}
e_blwl_protocol_type ConfigProtocol::bl_protocol_type() const {
return bl_protocol_type_;
}
std::string ConfigProtocol::bl_memory_model_name() const {
return bl_memory_model_name_;
}
CircuitModelId ConfigProtocol::bl_memory_model() const {
return bl_memory_model_;
}
size_t ConfigProtocol::bl_num_banks() const { return bl_num_banks_; }
e_blwl_protocol_type ConfigProtocol::wl_protocol_type() const {
return wl_protocol_type_;
}
std::string ConfigProtocol::wl_memory_model_name() const {
return wl_memory_model_name_;
}
CircuitModelId ConfigProtocol::wl_memory_model() const {
return wl_memory_model_;
}
size_t ConfigProtocol::wl_num_banks() const { return wl_num_banks_; }
/************************************************************************
* Public Mutators
***********************************************************************/
void ConfigProtocol::set_type(const e_config_protocol_type& type) {
type_ = type;
}
void ConfigProtocol::set_memory_model_name(
const std::string& memory_model_name) {
memory_model_name_ = memory_model_name;
}
void ConfigProtocol::set_memory_model(const CircuitModelId& memory_model) {
memory_model_ = memory_model;
}
void ConfigProtocol::set_num_regions(const int& num_regions) {
num_regions_ = num_regions;
}
2023-04-22 02:09:39 -05:00
void ConfigProtocol::set_prog_clock_port_ccff_head_indices_pair(const openfpga::BasicPort& port, const std::string& indices_str) {
2023-04-21 04:01:51 -05:00
openfpga::StringToken tokenizer(indices_str);
2023-04-22 02:09:39 -05:00
std::vector<size_t> token_int;
2023-04-21 04:01:51 -05:00
token_int.reserve(tokenizer.split(INDICE_STRING_DELIM_).size());
for (std::string token : tokenizer.split(INDICE_STRING_DELIM_)) {
2023-04-22 02:09:39 -05:00
token_int.push_back(std::stoi(token));
2023-04-21 04:01:51 -05:00
}
2023-04-22 02:09:39 -05:00
auto result = prog_clk_ccff_head_indices_.find(port);
if (result != prog_clk_ccff_head_indices_.end()) {
VTR_LOG_WARN("Overwrite the pair between programming clock port '%s[%d:%d]' and ccff head indices (previous: '%s', current: '%s')!\n", port.get_name().c_str(), port.get_lsb(), port.get_msb(), prog_clock_port_ccff_head_indices_str(port).c_str(), indices_str.c_str());
2023-04-21 04:01:51 -05:00
}
prog_clk_ccff_head_indices_[port] = token_int;
}
void ConfigProtocol::set_bl_protocol_type(const e_blwl_protocol_type& type) {
if (CONFIG_MEM_QL_MEMORY_BANK != type_) {
VTR_LOG_ERROR(
"BL protocol type is only applicable for configuration protocol '%d'",
CONFIG_PROTOCOL_TYPE_STRING[type_]);
return;
}
bl_protocol_type_ = type;
}
void ConfigProtocol::set_bl_memory_model_name(
const std::string& memory_model_name) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
VTR_LOG_ERROR(
"BL protocol memory model is only applicable when '%d' is defined",
BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
return;
}
bl_memory_model_name_ = memory_model_name;
}
void ConfigProtocol::set_bl_memory_model(const CircuitModelId& memory_model) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
VTR_LOG_ERROR(
"BL protocol memory model is only applicable when '%d' is defined",
BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
return;
}
bl_memory_model_ = memory_model;
}
void ConfigProtocol::set_bl_num_banks(const size_t& num_banks) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
VTR_LOG_ERROR(
"BL protocol memory model is only applicable when '%d' is defined",
BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
return;
}
bl_num_banks_ = num_banks;
}
void ConfigProtocol::set_wl_protocol_type(const e_blwl_protocol_type& type) {
if (CONFIG_MEM_QL_MEMORY_BANK != type_) {
VTR_LOG_ERROR(
"WL protocol type is only applicable for configuration protocol '%d'",
CONFIG_PROTOCOL_TYPE_STRING[type_]);
return;
}
wl_protocol_type_ = type;
}
void ConfigProtocol::set_wl_memory_model_name(
const std::string& memory_model_name) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
VTR_LOG_ERROR(
"WL protocol memory model is only applicable when '%d' is defined",
BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
return;
}
wl_memory_model_name_ = memory_model_name;
}
void ConfigProtocol::set_wl_memory_model(const CircuitModelId& memory_model) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
VTR_LOG_ERROR(
"WL protocol memory model is only applicable when '%d' is defined",
BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
return;
}
wl_memory_model_ = memory_model;
}
void ConfigProtocol::set_wl_num_banks(const size_t& num_banks) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
VTR_LOG_ERROR(
"WL protocol memory model is only applicable when '%d' is defined",
BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
return;
}
wl_num_banks_ = num_banks;
}
2023-04-21 23:44:34 -05:00
/************************************************************************
* Private Validators
***********************************************************************/
2023-04-22 02:09:39 -05:00
int ConfigProtocol::validate_ccff_prog_clocks() const {
2023-04-21 23:44:34 -05:00
int num_err = 0;
/* Initialize scoreboard */
std::vector<int> ccff_head_scoreboard(num_regions(), 0);
2023-04-22 02:09:39 -05:00
for (openfpga::BasicPort port : prog_clock_ports()) {
2023-04-21 23:44:34 -05:00
/* Must be valid first */
if (port.is_valid()) {
VTR_LOG_ERROR("Programming clock '%s[%d:%d]' is not a valid port!\n", port.get_name().c_str(), port.get_lsb(), port.get_msb());
num_err++;
}
/* Each port should have a width of 1 */
if (port.get_width() != 1) {
VTR_LOG_ERROR("Expect each programming clock has a size of 1 in the definition. '%s[%d:%d]' violates the rule!\n", port.get_name().c_str(), port.get_lsb(), port.get_msb());
num_err++;
}
/* Fill scoreboard */
for (size_t ccff_head_idx : prog_clock_port_ccff_head_indices(port)) {
2023-04-22 02:09:39 -05:00
if (ccff_head_idx >= ccff_head_scoreboard.size()) {
2023-04-21 23:44:34 -05:00
VTR_LOG_ERROR("Programming clock '%s[%d:%d]' controlls an invalid ccff head '%ld' (Expect [0, '%ld'])!\n", port.get_name().c_str(), port.get_lsb(), port.get_msb(), ccff_head_idx, ccff_head_scoreboard.size() - 1);
num_err++;
}
ccff_head_scoreboard[ccff_head_idx]++;
}
}
2023-04-22 02:09:39 -05:00
if (prog_clock_ports().size() != (size_t)num_regions()) {
2023-04-21 23:44:34 -05:00
VTR_LOG_ERROR("Number of programming clocks '%ld' does not match the number of configuration regions '%ld'!\n", prog_clock_ports().size(), num_regions());
num_err++;
}
for (size_t iregion = 0; iregion < ccff_head_scoreboard.size(); iregion++) {
if (ccff_head_scoreboard[iregion] == 0) {
VTR_LOG_ERROR("Configuration chain '%ld' is not driven by any programming clock!\n", iregion);
num_err++;
}
if (ccff_head_scoreboard[iregion] > 1) {
VTR_LOG_ERROR("Configuration chain '%ld' is driven by %ld programming clock!\n", iregion, ccff_head_scoreboard[iregion]);
num_err++;
}
}
return num_err;
}
/************************************************************************
* Public Validators
***********************************************************************/
2023-04-22 02:09:39 -05:00
int ConfigProtocol::validate() const {
2023-04-21 23:44:34 -05:00
int num_err = 0;
if (type() == CONFIG_MEM_SCAN_CHAIN) {
num_err += validate_ccff_prog_clocks();
}
return num_err;
}