2020-01-12 19:11:00 -06:00
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Function to perform fundamental checking for the circuit library
|
|
|
|
* such as
|
|
|
|
* 1. if default circuit models are defined
|
|
|
|
* 2. if any circuit models shared the same name or prefix
|
|
|
|
* 3. if nay circuit model miss mandatory ports
|
2020-01-12 19:11:00 -06:00
|
|
|
***********************************************************************/
|
|
|
|
|
2020-01-23 21:12:30 -06:00
|
|
|
/* Headers from vtrutil library */
|
2022-10-06 19:08:50 -05:00
|
|
|
#include "check_circuit_library.h"
|
|
|
|
|
2020-01-12 19:11:00 -06:00
|
|
|
#include "vtr_assert.h"
|
|
|
|
#include "vtr_log.h"
|
2020-01-23 21:12:30 -06:00
|
|
|
#include "vtr_time.h"
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Circuit models have unique names, return the number of errors
|
2020-01-12 19:11:00 -06:00
|
|
|
* If not found, we give an error
|
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_circuit_library_unique_names(
|
|
|
|
const CircuitLibrary& circuit_lib) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < circuit_lib.num_models(); ++i) {
|
|
|
|
/* Skip for the last element, because the inner loop will access it */
|
|
|
|
if (i == circuit_lib.num_models() - 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Get the name of reference */
|
|
|
|
const std::string& i_name = circuit_lib.model_name(CircuitModelId(i));
|
|
|
|
for (size_t j = i + 1; j < circuit_lib.num_models(); ++j) {
|
|
|
|
/* Compare the name of candidate */
|
|
|
|
const std::string& j_name = circuit_lib.model_name(CircuitModelId(j));
|
|
|
|
/* Compare the name and skip for different names */
|
|
|
|
if (0 != i_name.compare(j_name)) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Circuit model(index=%d) and (index=%d) share the same name, which is "
|
|
|
|
"invalid!\n",
|
|
|
|
i, j, i_name.c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Incremental the counter for errors */
|
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Circuit models have unique names, return the number of errors
|
2020-01-12 19:11:00 -06:00
|
|
|
* If not found, we give an error
|
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_circuit_library_unique_prefix(
|
|
|
|
const CircuitLibrary& circuit_lib) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < circuit_lib.num_models(); ++i) {
|
|
|
|
/* Skip for the last element, because the inner loop will access it */
|
|
|
|
if (i == circuit_lib.num_models() - 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Get the name of reference */
|
|
|
|
const std::string& i_prefix = circuit_lib.model_prefix(CircuitModelId(i));
|
|
|
|
for (size_t j = i + 1; j < circuit_lib.num_models(); ++j) {
|
|
|
|
/* Compare the name of candidate */
|
|
|
|
const std::string& j_prefix = circuit_lib.model_prefix(CircuitModelId(j));
|
|
|
|
/* Compare the name and skip for different prefix */
|
|
|
|
if (0 != i_prefix.compare(j_prefix)) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Circuit model(name=%s) and (name=%s) share the same prefix, which is "
|
|
|
|
"invalid!\n",
|
|
|
|
circuit_lib.model_name(CircuitModelId(i)).c_str(),
|
|
|
|
circuit_lib.model_name(CircuitModelId(j)).c_str(), i_prefix.c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Incremental the counter for errors */
|
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* A generic function to check the port list of a circuit model in a given type
|
|
|
|
* If not found, we give an error
|
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_circuit_model_required(
|
|
|
|
const CircuitLibrary& circuit_lib,
|
|
|
|
const enum e_circuit_model_type& circuit_model_type_to_check) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
/* We must have an IOPAD*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if (0 == circuit_lib.models_by_type(circuit_model_type_to_check).size()) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"At least one %s circuit model is required!\n",
|
|
|
|
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_model_type_to_check)]);
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Incremental the counter for errors */
|
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* A generic function to check the port list of a circuit model in a given type
|
2020-01-12 19:11:00 -06:00
|
|
|
* If not found, we give an error
|
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
size_t check_one_circuit_model_port_required(
|
|
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model,
|
|
|
|
const std::vector<enum e_circuit_model_port_type>& port_types_to_check) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
for (const auto& port_type : port_types_to_check) {
|
2020-01-12 19:11:00 -06:00
|
|
|
if (0 == circuit_lib.model_ports_by_type(circuit_model, port_type).size()) {
|
|
|
|
VTR_LOG_ERROR("%s circuit model(name=%s) does not have %s port\n",
|
2022-10-06 19:08:50 -05:00
|
|
|
CIRCUIT_MODEL_TYPE_STRING[size_t(
|
|
|
|
circuit_lib.model_type(circuit_model))],
|
|
|
|
circuit_lib.model_name(circuit_model).c_str(),
|
2020-01-12 19:11:00 -06:00
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(port_type)]);
|
|
|
|
/* Incremental the counter for errors */
|
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* A generic function to check the port size of a given circuit model
|
2022-10-06 19:08:50 -05:00
|
|
|
* if the port size does not match, we give an error
|
2020-01-12 19:11:00 -06:00
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
size_t check_one_circuit_model_port_size_required(
|
|
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model,
|
|
|
|
const CircuitPortId& circuit_port, const size_t& port_size_to_check) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
if (port_size_to_check != circuit_lib.port_size(circuit_port)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Expect circuit model %s to have %d %s ports but only see %d!\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str(), port_size_to_check,
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(
|
|
|
|
circuit_lib.port_type(circuit_port))],
|
|
|
|
circuit_lib.port_size(circuit_port));
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Incremental the counter for errors */
|
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* A generic function to check the port size of a given circuit model
|
2022-10-06 19:08:50 -05:00
|
|
|
* if the number of ports in the given type does not match, we give an error
|
|
|
|
* for each port, if the port size does not match, we give an error
|
2020-01-12 19:11:00 -06:00
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
size_t check_one_circuit_model_port_type_and_size_required(
|
|
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model,
|
|
|
|
const enum e_circuit_model_port_type& port_type_to_check,
|
|
|
|
const size_t& num_ports_to_check, const size_t& port_size_to_check,
|
|
|
|
const bool& include_global_ports) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
std::vector<CircuitPortId> ports = circuit_lib.model_ports_by_type(
|
|
|
|
circuit_model, port_type_to_check, false == include_global_ports);
|
2020-01-12 19:11:00 -06:00
|
|
|
if (num_ports_to_check != ports.size()) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Expect %d %s ports for a %s circuit model, but only have %d %s ports!\n",
|
|
|
|
num_ports_to_check,
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(port_type_to_check)],
|
|
|
|
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.model_type(circuit_model))],
|
|
|
|
ports.size(), CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(port_type_to_check)]);
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
2022-10-06 19:08:50 -05:00
|
|
|
}
|
|
|
|
for (const auto& port : ports) {
|
|
|
|
num_err += check_one_circuit_model_port_size_required(
|
|
|
|
circuit_lib, circuit_model, port, port_size_to_check);
|
2020-01-12 19:11:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* A generic function to check the port list of circuit models in a given type
|
2020-01-12 19:11:00 -06:00
|
|
|
* If not found, we give an error
|
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_circuit_model_port_required(
|
|
|
|
const CircuitLibrary& circuit_lib,
|
|
|
|
const enum e_circuit_model_type& circuit_model_type_to_check,
|
|
|
|
const std::vector<enum e_circuit_model_port_type>& port_types_to_check) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
for (const auto& id :
|
|
|
|
circuit_lib.models_by_type(circuit_model_type_to_check)) {
|
|
|
|
num_err += check_one_circuit_model_port_required(circuit_lib, id,
|
|
|
|
port_types_to_check);
|
2020-01-12 19:11:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2020-08-23 14:48:22 -05:00
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* A generic function to search each default circuit model by types
|
2020-08-23 14:48:22 -05:00
|
|
|
* that have been defined by users.
|
2022-10-06 19:08:50 -05:00
|
|
|
* If a type of circuit model is defined, we expect there is a default model
|
2020-08-23 14:48:22 -05:00
|
|
|
* to be specified
|
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_default_circuit_model_by_types(
|
|
|
|
const CircuitLibrary& circuit_lib) {
|
2020-08-23 14:48:22 -05:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_TYPES; ++itype) {
|
2022-10-06 19:08:50 -05:00
|
|
|
std::vector<CircuitModelId> curr_models =
|
|
|
|
circuit_lib.models_by_type(e_circuit_model_type(itype));
|
2020-08-23 14:48:22 -05:00
|
|
|
if (0 == curr_models.size()) {
|
2022-10-06 19:08:50 -05:00
|
|
|
continue;
|
2020-08-23 14:48:22 -05:00
|
|
|
}
|
|
|
|
/* Go through the models and try to find a default one */
|
|
|
|
size_t found_default_counter = 0;
|
|
|
|
for (const auto& curr_model : curr_models) {
|
|
|
|
if (true == circuit_lib.model_is_default(curr_model)) {
|
|
|
|
found_default_counter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (0 == found_default_counter) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Miss a default circuit model for the type %s! Try to define it in "
|
|
|
|
"your architecture file!\n",
|
|
|
|
CIRCUIT_MODEL_TYPE_STRING[itype]);
|
2020-08-23 14:48:22 -05:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
if (1 < found_default_counter) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Found >1 default circuit models for the type %s! Expect only one!\n",
|
|
|
|
CIRCUIT_MODEL_TYPE_STRING[itype]);
|
2020-08-23 14:48:22 -05:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2020-01-12 19:11:00 -06:00
|
|
|
/************************************************************************
|
|
|
|
* A generic function to find the default circuit model with a given type
|
|
|
|
* If not found, we give an error
|
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_required_default_circuit_model(
|
|
|
|
const CircuitLibrary& circuit_lib,
|
|
|
|
const enum e_circuit_model_type& circuit_model_type) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
if (CircuitModelId::INVALID() ==
|
|
|
|
circuit_lib.default_model(circuit_model_type)) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Miss a default circuit model for the type %s! Try to define it in your "
|
|
|
|
"architecture file!\n",
|
|
|
|
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_model_type)]);
|
2020-08-23 14:48:22 -05:00
|
|
|
num_err++;
|
2020-01-12 19:11:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* A function to check the port map of FF circuit model
|
|
|
|
***********************************************************************/
|
|
|
|
size_t check_ff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& circuit_model) {
|
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
/* Check the type of circuit model */
|
|
|
|
VTR_ASSERT(CIRCUIT_MODEL_FF == circuit_lib.model_type(circuit_model));
|
|
|
|
/* Check if we have D, Set and Reset */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_INPUT, 3, 1, false);
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Check if we have a clock */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_CLOCK, 1, 1, false);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
/* Check if we have output */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, 1, 1, false);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* A function to check the port map of CCFF circuit model
|
|
|
|
***********************************************************************/
|
|
|
|
size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& circuit_model) {
|
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
/* Check the type of circuit model */
|
|
|
|
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
|
|
|
|
|
|
|
/* Check if we have D, Set and Reset */
|
2022-10-06 19:08:50 -05:00
|
|
|
/* We can have either 1 input which is D or 2 inputs which are D and scan
|
|
|
|
* input */
|
|
|
|
size_t num_input_ports =
|
|
|
|
circuit_lib
|
|
|
|
.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true)
|
|
|
|
.size();
|
2021-01-04 16:13:54 -06:00
|
|
|
if ((1 != num_input_ports) && (2 != num_input_ports)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Configuration flip-flop '%s' must have either 1 or 2 %s ports!\n\tAmong "
|
|
|
|
"which:\n\t\tthe first input is a regular input (e.g., D)\n\t\tand the "
|
|
|
|
"other could be scan-chain input (e.g., SI)\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str(),
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
|
2021-01-04 16:13:54 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_INPUT, num_input_ports, 1,
|
|
|
|
false);
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Check if we have a clock */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_CLOCK, 1, 1, true);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
2021-01-04 18:14:26 -06:00
|
|
|
/* Check if we have 1 or 2 or 3 outputs */
|
2022-10-06 19:08:50 -05:00
|
|
|
size_t num_output_ports =
|
|
|
|
circuit_lib
|
|
|
|
.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true)
|
|
|
|
.size();
|
|
|
|
if ((1 != num_output_ports) && (2 != num_output_ports) &&
|
|
|
|
(3 != num_output_ports)) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Configuration flip-flop '%s' must have either 1 or 2 or 3 %s "
|
|
|
|
"ports!\n\tAmong which:\n\t\tthe first port is the manadatory regular "
|
|
|
|
"data output (e.g., Q) and \n\t\tthe second port could be the inverted "
|
|
|
|
"data output which can optionally be enabled by configure-enable signal "
|
|
|
|
"(e.g., QN or cgf_en_QN) and \n\t\tthe third port could be the data "
|
|
|
|
"output which can optionally be enabled by configure-enable signal "
|
|
|
|
"(e.g., cgf_en_Q)\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str(),
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_OUTPUT)]);
|
2021-01-04 16:13:54 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, num_output_ports, 1,
|
|
|
|
false);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2021-09-28 17:56:07 -05:00
|
|
|
/************************************************************************
|
|
|
|
* A function to check the port map of CCFF circuit model used to control BLs
|
|
|
|
* - Require 1 clock port
|
2022-10-06 19:08:50 -05:00
|
|
|
* - Require 1 input port as data input (to be driven by other CCFF in a chain)
|
|
|
|
* - Require 1 output port as data output (to drive other CCFF in a chain)
|
2021-09-28 17:56:07 -05:00
|
|
|
* - Require 1 BL port as data output / inout (to drive/driven by BLs)
|
|
|
|
***********************************************************************/
|
|
|
|
size_t check_bl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& circuit_model) {
|
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
/* Check the type of circuit model */
|
|
|
|
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
|
|
|
|
|
|
|
/* Check if we have D, Set and Reset */
|
2022-10-06 19:08:50 -05:00
|
|
|
/* We can have either 1 input which is D or 2 inputs which are D and scan
|
|
|
|
* input */
|
|
|
|
size_t num_input_ports =
|
|
|
|
circuit_lib
|
|
|
|
.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true)
|
|
|
|
.size();
|
2021-09-28 17:56:07 -05:00
|
|
|
if (1 != num_input_ports) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Configuration flip-flop for BL shift register '%s' must have 1 %s "
|
|
|
|
"port!\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str(),
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
|
2021-09-28 17:56:07 -05:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_INPUT, num_input_ports, 1,
|
|
|
|
false);
|
2021-09-28 17:56:07 -05:00
|
|
|
/* Check if we have a clock */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_CLOCK, 1, 1, true);
|
2021-09-28 17:56:07 -05:00
|
|
|
|
|
|
|
/* Check if we have 1 output*/
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, 1, 1, false);
|
2021-09-28 17:56:07 -05:00
|
|
|
|
|
|
|
/* Check if we have 1 bl port */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_BL, 1, 1, false);
|
2021-09-28 17:56:07 -05:00
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* A function to check the port map of CCFF circuit model used to control WLs
|
|
|
|
* - Require 1 clock port
|
2022-10-06 19:08:50 -05:00
|
|
|
* - Require 1 input port as data input (to be driven by other CCFF in a chain)
|
|
|
|
* - Require 1 output port as data output (to drive other CCFF in a chain)
|
2021-09-28 17:56:07 -05:00
|
|
|
* - Require 1 WL port as data output (to drive WLs)
|
|
|
|
* - Optionally require 1 WLR port as data output (to drive WLRs)
|
|
|
|
***********************************************************************/
|
|
|
|
size_t check_wl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& circuit_model) {
|
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
/* Check the type of circuit model */
|
|
|
|
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
|
|
|
|
|
|
|
/* Check if we have D, Set and Reset */
|
2022-10-06 19:08:50 -05:00
|
|
|
/* We can have either 1 input which is D or 2 inputs which are D and scan
|
|
|
|
* input */
|
|
|
|
size_t num_input_ports =
|
|
|
|
circuit_lib
|
|
|
|
.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true)
|
|
|
|
.size();
|
2021-09-28 17:56:07 -05:00
|
|
|
if (1 != num_input_ports) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Configuration flip-flop for WL shift register '%s' must have 1 %s "
|
|
|
|
"port!\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str(),
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
|
2021-09-28 17:56:07 -05:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_INPUT, num_input_ports, 1,
|
|
|
|
false);
|
2021-10-01 19:23:10 -05:00
|
|
|
/* Check if we have two clock: 1 for write-enable, 1 for shift register */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_CLOCK, 2, 1, true);
|
2021-09-28 17:56:07 -05:00
|
|
|
|
|
|
|
/* Check if we have 1 output*/
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, 1, 1, false);
|
2021-09-28 17:56:07 -05:00
|
|
|
|
|
|
|
/* Check if we have 1 wl port */
|
2022-10-06 19:08:50 -05:00
|
|
|
if (0 < circuit_lib
|
|
|
|
.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_WLR, true)
|
|
|
|
.size()) {
|
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_WLR, 1, 1, false);
|
2021-09-28 17:56:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2020-01-12 19:11:00 -06:00
|
|
|
/************************************************************************
|
|
|
|
* A function to check the port map of SRAM circuit model
|
|
|
|
***********************************************************************/
|
|
|
|
size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& circuit_model,
|
|
|
|
const bool& check_blwl) {
|
|
|
|
size_t num_err = 0;
|
|
|
|
|
|
|
|
/* Check the type of circuit model */
|
|
|
|
VTR_ASSERT(CIRCUIT_MODEL_SRAM == circuit_lib.model_type(circuit_model));
|
|
|
|
|
|
|
|
/* Check if we has 1 output with size 2 */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, 2, 1, false);
|
2020-01-12 19:11:00 -06:00
|
|
|
/* basic check finished here */
|
|
|
|
if (false == check_blwl) {
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If bl and wl are required, check their existence */
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_BL, 1, 1, false);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_one_circuit_model_port_type_and_size_required(
|
|
|
|
circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_WL, 1, 1, false);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2020-07-22 19:47:12 -05:00
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Check all the ports make sure, they satisfy the restriction
|
2020-07-22 19:47:12 -05:00
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
2022-10-06 19:08:50 -05:00
|
|
|
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Check global ports: make sure all the global ports are input ports */
|
|
|
|
for (const auto& port : circuit_lib.ports()) {
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((circuit_lib.port_is_global(port)) &&
|
|
|
|
(!circuit_lib.is_input_port(port)) &&
|
|
|
|
(!circuit_lib.is_output_port(port))) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Circuit port (type=%s) of model (name=%s) is defined as global but "
|
|
|
|
"not an input/output port!\n",
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))],
|
|
|
|
circuit_lib.model_name(port).c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-08 17:54:08 -05:00
|
|
|
/* Check global output ports: make sure they are all I/Os */
|
|
|
|
for (const auto& port : circuit_lib.ports()) {
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((circuit_lib.port_is_global(port)) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port)) &&
|
|
|
|
(false == circuit_lib.port_is_io(port))) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Circuit port (type=%s) of model (name=%s) is defined as global output "
|
|
|
|
"port but not an I/O!\n",
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))],
|
|
|
|
circuit_lib.model_name(port).c_str());
|
2020-04-08 17:54:08 -05:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-12 19:11:00 -06:00
|
|
|
/* Check set/reset/config_enable ports: make sure they are all global ports */
|
|
|
|
for (const auto& port : circuit_lib.ports()) {
|
2022-10-06 19:08:50 -05:00
|
|
|
if (((circuit_lib.port_is_set(port)) || (circuit_lib.port_is_reset(port)) ||
|
|
|
|
(circuit_lib.port_is_config_enable(port))) &&
|
|
|
|
(!circuit_lib.port_is_global(port))) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Circuit port (type=%s) of model (name=%s) is defined as a "
|
|
|
|
"set/reset/config_enable port but it is not global!\n",
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))],
|
|
|
|
circuit_lib.model_name(port).c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the tri-state map of ports, the length should match the port size! */
|
|
|
|
for (const auto& port : circuit_lib.ports()) {
|
|
|
|
if (circuit_lib.port_tri_state_map(port).empty()) {
|
|
|
|
continue; /* No tri-state map is found, go to the next */
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
if (circuit_lib.port_tri_state_map(port).length() ==
|
|
|
|
circuit_lib.port_size(port)) {
|
2020-01-12 19:11:00 -06:00
|
|
|
continue; /* Sizes match, go to the next */
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
/* We have a problem here, sizes do not match, leave a message and raise the
|
|
|
|
* error flag */
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Tri-state map (=%s) of circuit port (type=%s) of model (name=%s) does "
|
|
|
|
"not match the port size (=%lu)!\n",
|
|
|
|
circuit_lib.port_tri_state_map(port).c_str(),
|
|
|
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))],
|
|
|
|
circuit_lib.model_name(port).c_str(), circuit_lib.port_size(port));
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Check all the global ports which sare the same name also share the same
|
|
|
|
* attributes: default_value, is_config, is_reset, is_set etc.
|
2020-01-12 19:11:00 -06:00
|
|
|
*/
|
|
|
|
std::vector<CircuitPortId> global_ports;
|
|
|
|
|
|
|
|
/* Collect all the global ports */
|
|
|
|
for (auto port : circuit_lib.ports()) {
|
|
|
|
/* By pass non-global ports*/
|
|
|
|
if (false == circuit_lib.port_is_global(port)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
global_ports.push_back(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t iport = 0; iport < global_ports.size() - 1; ++iport) {
|
|
|
|
for (size_t jport = iport + 1; jport < global_ports.size(); ++jport) {
|
|
|
|
/* Bypass those do not share the same name */
|
2022-10-06 19:08:50 -05:00
|
|
|
if (0 != circuit_lib.port_prefix(global_ports[iport])
|
|
|
|
.compare(circuit_lib.port_prefix(global_ports[jport]))) {
|
2020-01-12 19:11:00 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if a same port share the same attributes */
|
2022-10-06 19:08:50 -05:00
|
|
|
CircuitModelId iport_parent_model =
|
|
|
|
circuit_lib.port_parent_model(global_ports[iport]);
|
|
|
|
CircuitModelId jport_parent_model =
|
|
|
|
circuit_lib.port_parent_model(global_ports[jport]);
|
|
|
|
|
|
|
|
if (circuit_lib.port_default_value(global_ports[iport]) !=
|
|
|
|
circuit_lib.port_default_value(global_ports[jport])) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Global ports %s from circuit model %s and %s share the same name "
|
|
|
|
"but have different dfefault values(%lu and %lu)!\n",
|
|
|
|
circuit_lib.port_prefix(global_ports[iport]).c_str(),
|
|
|
|
circuit_lib.model_name(iport_parent_model).c_str(),
|
|
|
|
circuit_lib.model_name(jport_parent_model).c_str(),
|
|
|
|
circuit_lib.port_default_value(global_ports[iport]),
|
|
|
|
circuit_lib.port_default_value(global_ports[jport]));
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
if (circuit_lib.port_is_reset(global_ports[iport]) !=
|
|
|
|
circuit_lib.port_is_reset(global_ports[jport])) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Global ports %s from circuit model %s and %s share the same name "
|
|
|
|
"but have different is_reset attributes!\n",
|
|
|
|
circuit_lib.port_prefix(global_ports[iport]).c_str(),
|
|
|
|
circuit_lib.model_name(iport_parent_model).c_str(),
|
|
|
|
circuit_lib.model_name(jport_parent_model).c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
if (circuit_lib.port_is_set(global_ports[iport]) !=
|
|
|
|
circuit_lib.port_is_set(global_ports[jport])) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Global ports %s from circuit model %s and %s share the same name "
|
|
|
|
"but have different is_set attributes!\n",
|
|
|
|
circuit_lib.port_prefix(global_ports[iport]).c_str(),
|
|
|
|
circuit_lib.model_name(iport_parent_model).c_str(),
|
|
|
|
circuit_lib.model_name(jport_parent_model).c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
if (circuit_lib.port_is_config_enable(global_ports[iport]) !=
|
|
|
|
circuit_lib.port_is_config_enable(global_ports[jport])) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Global ports %s from circuit model %s and %s share the same name "
|
|
|
|
"but have different is_config_enable attributes!\n",
|
|
|
|
circuit_lib.port_prefix(global_ports[iport]).c_str(),
|
|
|
|
circuit_lib.model_name(iport_parent_model).c_str(),
|
|
|
|
circuit_lib.model_name(jport_parent_model).c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
if (circuit_lib.port_is_prog(global_ports[iport]) !=
|
|
|
|
circuit_lib.port_is_prog(global_ports[jport])) {
|
|
|
|
VTR_LOG_ERROR(
|
|
|
|
"Global ports %s from circuit model %s and %s share the same name "
|
|
|
|
"but have different is_prog attributes!\n",
|
|
|
|
circuit_lib.port_prefix(global_ports[iport]).c_str(),
|
|
|
|
circuit_lib.model_name(iport_parent_model).c_str(),
|
|
|
|
circuit_lib.model_name(jport_parent_model).c_str());
|
2020-01-12 19:11:00 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2020-07-22 19:47:12 -05:00
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Check the port requirements for a power-gated circuit model
|
2020-07-22 19:47:12 -05:00
|
|
|
* - It must have at least 2 global ports and which are config enable signals
|
2022-10-06 19:08:50 -05:00
|
|
|
* - It must have an Enable port which control power gating
|
|
|
|
* - It must have an EnableB port which control power gating
|
2020-07-22 19:47:12 -05:00
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static int check_power_gated_circuit_model(
|
|
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model) {
|
2020-07-22 19:47:12 -05:00
|
|
|
int num_err = 0;
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
std::vector<CircuitPortId> global_ports =
|
|
|
|
circuit_lib.model_global_ports_by_type(
|
|
|
|
circuit_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
|
2020-07-22 19:47:12 -05:00
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* If the circuit model is power-gated, we need to find at least one global
|
|
|
|
* config_enable signals */
|
2020-07-22 19:47:12 -05:00
|
|
|
VTR_ASSERT(true == circuit_lib.is_power_gated(circuit_model));
|
|
|
|
/* Check all the ports we have are good for a power-gated circuit model */
|
|
|
|
/* We need at least one global port */
|
2022-10-06 19:08:50 -05:00
|
|
|
if (2 > global_ports.size()) {
|
2020-07-22 19:47:12 -05:00
|
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
2022-10-06 19:08:50 -05:00
|
|
|
"Expect at least two global ports (a pair of EN/Enb) for "
|
|
|
|
"circuit model '%s' which is power-gated!\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str());
|
2020-07-22 19:47:12 -05:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
/* All the global ports should be config_enable */
|
|
|
|
int num_config_enable_ports = 0;
|
|
|
|
for (const auto& port : global_ports) {
|
|
|
|
if (true == circuit_lib.port_is_config_enable(port)) {
|
|
|
|
num_config_enable_ports++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (2 != num_config_enable_ports) {
|
|
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
2022-10-06 19:08:50 -05:00
|
|
|
"Circuit model '%s' is power-gated. Two config-enable "
|
|
|
|
"global ports are required!\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str());
|
2020-07-22 19:47:12 -05:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
/* Report errors if there are any */
|
|
|
|
if (0 < num_err) {
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find a pair of Enable and ENb ports from the global ports */
|
|
|
|
CircuitPortId en_port = CircuitPortId::INVALID();
|
|
|
|
CircuitPortId enb_port = CircuitPortId::INVALID();
|
|
|
|
for (const auto& port : global_ports) {
|
|
|
|
/* Focus on config_enable ports which are power-gate control signals */
|
|
|
|
if (false == circuit_lib.port_is_config_enable(port)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (0 == circuit_lib.port_default_value(port)) {
|
|
|
|
en_port = port;
|
|
|
|
} else {
|
|
|
|
VTR_ASSERT(1 == circuit_lib.port_default_value(port));
|
|
|
|
enb_port = port;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* We must have valid EN/ENb ports */
|
|
|
|
if (false == circuit_lib.valid_circuit_port_id(en_port)) {
|
|
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
2022-10-06 19:08:50 -05:00
|
|
|
"Fail to find an enable port for the circuit model '%s' is "
|
|
|
|
"power-gated!\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str());
|
2020-07-22 19:47:12 -05:00
|
|
|
}
|
|
|
|
if (false == circuit_lib.valid_circuit_port_id(enb_port)) {
|
|
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
2022-10-06 19:08:50 -05:00
|
|
|
"Fail to find an inverted enable port for the circuit model "
|
|
|
|
"'%s' is power-gated!\n",
|
|
|
|
circuit_lib.model_name(circuit_model).c_str());
|
2020-07-22 19:47:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Check the port requirements for each power-gated circuit model
|
2020-07-22 19:47:12 -05:00
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static int check_power_gated_circuit_models(const CircuitLibrary& circuit_lib) {
|
2020-07-22 19:47:12 -05:00
|
|
|
int num_err = 0;
|
|
|
|
|
|
|
|
for (const CircuitModelId& circuit_model : circuit_lib.models()) {
|
|
|
|
if (true == circuit_lib.is_power_gated(circuit_model)) {
|
|
|
|
num_err += check_power_gated_circuit_model(circuit_lib, circuit_model);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2020-11-02 14:54:31 -06:00
|
|
|
/************************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Check io has been defined and has input and output ports
|
2020-11-02 14:54:31 -06:00
|
|
|
* - We must have global I/O port, either its type is inout, input or output
|
2022-10-06 19:08:50 -05:00
|
|
|
* - For each IOPAD, we must have at least an input an output
|
2020-11-02 14:54:31 -06:00
|
|
|
***********************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static size_t check_io_circuit_model(const CircuitLibrary& circuit_lib) {
|
2020-11-02 14:54:31 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Each I/O cell must have
|
2020-11-02 14:54:31 -06:00
|
|
|
* - One of the following ports
|
2022-10-06 19:08:50 -05:00
|
|
|
* - At least 1 ASIC-to-FPGA (A2F) port that is defined as global data I/O
|
2020-11-04 21:21:49 -06:00
|
|
|
* - At least 1 FPGA-to-ASIC (F2A) port that is defined as global data I/O!
|
2022-10-06 19:08:50 -05:00
|
|
|
* - At least 1 regular port that is non-global which is connected to global
|
|
|
|
* routing architecture
|
2020-11-02 14:54:31 -06:00
|
|
|
*/
|
|
|
|
for (const auto& io_model : circuit_lib.models_by_type(CIRCUIT_MODEL_IOPAD)) {
|
2020-11-04 21:21:49 -06:00
|
|
|
bool has_data_io = false;
|
|
|
|
bool has_data_input_only_io = false;
|
|
|
|
bool has_data_output_only_io = false;
|
2020-11-02 14:54:31 -06:00
|
|
|
bool has_internal_connection = false;
|
|
|
|
|
|
|
|
for (const auto& port : circuit_lib.model_ports(io_model)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((true == circuit_lib.port_is_io(port)) &&
|
|
|
|
(true == circuit_lib.port_is_data_io(port)) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_INOUT == circuit_lib.port_type(port)) &&
|
|
|
|
(true == circuit_lib.port_is_global(port))) {
|
2020-11-04 21:21:49 -06:00
|
|
|
has_data_io = true;
|
|
|
|
continue; /* Go to next */
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((true == circuit_lib.port_is_io(port)) &&
|
|
|
|
(true == circuit_lib.port_is_data_io(port)) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port)) &&
|
|
|
|
(true == circuit_lib.port_is_global(port))) {
|
2020-11-04 21:21:49 -06:00
|
|
|
has_data_input_only_io = true;
|
2020-11-02 14:54:31 -06:00
|
|
|
continue; /* Go to next */
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((true == circuit_lib.port_is_io(port)) &&
|
|
|
|
(true == circuit_lib.port_is_data_io(port)) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port)) &&
|
|
|
|
(true == circuit_lib.port_is_global(port))) {
|
2020-11-04 21:21:49 -06:00
|
|
|
has_data_output_only_io = true;
|
|
|
|
continue; /* Go to next */
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((false == circuit_lib.port_is_io(port) &&
|
|
|
|
(false == circuit_lib.port_is_global(port))) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_SRAM != circuit_lib.port_type(port))) {
|
2020-11-02 14:54:31 -06:00
|
|
|
has_internal_connection = true;
|
|
|
|
continue; /* Go to next */
|
|
|
|
}
|
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
|
2020-11-04 21:21:49 -06:00
|
|
|
/* Error out when
|
|
|
|
* - there is no data io, data input-only io and data output-only io
|
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((false == has_data_io) && (false == has_data_input_only_io) &&
|
|
|
|
(false == has_data_output_only_io)) {
|
|
|
|
VTR_LOGF_ERROR(
|
|
|
|
__FILE__, __LINE__,
|
|
|
|
"I/O circuit model '%s' does not have any data I/O port defined!\n",
|
|
|
|
circuit_lib.model_name(io_model).c_str());
|
2020-11-02 14:54:31 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (false == has_internal_connection) {
|
|
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
2022-10-06 19:08:50 -05:00
|
|
|
"I/O circuit model '%s' does not have any port connected "
|
|
|
|
"to FPGA core!\n",
|
|
|
|
circuit_lib.model_name(io_model).c_str());
|
2020-11-02 14:54:31 -06:00
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_err;
|
|
|
|
}
|
|
|
|
|
2020-01-12 19:11:00 -06:00
|
|
|
/************************************************************************
|
|
|
|
* Check points to make sure we have a valid circuit library
|
2022-10-06 19:08:50 -05:00
|
|
|
* Detailed checkpoints:
|
|
|
|
* 1. Circuit models have unique names
|
2020-01-12 19:11:00 -06:00
|
|
|
* 2. Circuit models have unique prefix
|
|
|
|
* 3. Check IOPADs have input and output ports
|
|
|
|
* 4. Check MUXes has been defined and has input and output ports
|
2022-10-06 19:08:50 -05:00
|
|
|
* 5. We must have at least one SRAM or CCFF
|
2020-01-12 19:11:00 -06:00
|
|
|
* 6. SRAM must have at least an input and an output ports
|
|
|
|
* 7. CCFF must have at least a clock, an input and an output ports
|
|
|
|
* 8. FF must have at least a clock, an input and an output ports
|
|
|
|
* 9. LUT must have at least an input, an output and a SRAM ports
|
2022-10-06 19:08:50 -05:00
|
|
|
* 10. We must have default circuit models for these types: MUX, channel wires
|
|
|
|
*and wires
|
2020-11-02 14:54:31 -06:00
|
|
|
*
|
|
|
|
* Note:
|
|
|
|
* - NO modification on the circuit library is allowed!
|
|
|
|
* The circuit library should be read-only!!!
|
2020-01-12 19:11:00 -06:00
|
|
|
***********************************************************************/
|
2020-05-14 21:02:42 -05:00
|
|
|
bool check_circuit_library(const CircuitLibrary& circuit_lib) {
|
2020-01-12 19:11:00 -06:00
|
|
|
size_t num_err = 0;
|
|
|
|
|
2020-01-23 21:12:30 -06:00
|
|
|
vtr::ScopedStartFinishTimer timer("Check circuit library");
|
2020-01-12 19:11:00 -06:00
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* 1. Circuit models have unique names
|
|
|
|
* For each circuit model, we always make sure it does not share any name with
|
|
|
|
* any circuit model locating after it
|
2020-01-12 19:11:00 -06:00
|
|
|
*/
|
|
|
|
num_err += check_circuit_library_unique_names(circuit_lib);
|
|
|
|
|
|
|
|
/* 2. Circuit models have unique prefix
|
2022-10-06 19:08:50 -05:00
|
|
|
* For each circuit model, we always make sure it does not share any prefix
|
|
|
|
* with any circuit model locating after it
|
2020-01-12 19:11:00 -06:00
|
|
|
*/
|
|
|
|
num_err += check_circuit_library_unique_prefix(circuit_lib);
|
|
|
|
|
|
|
|
/* Check global ports */
|
|
|
|
num_err += check_circuit_library_ports(circuit_lib);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* 3. Check io has been defined and has input and output ports
|
2020-11-02 14:54:31 -06:00
|
|
|
* [a] We must have global I/O port, either its type is inout, input or output
|
2022-10-06 19:08:50 -05:00
|
|
|
* [b] For each IOPAD, we must have at least an input an output
|
2020-01-12 19:11:00 -06:00
|
|
|
*/
|
|
|
|
num_err += check_circuit_model_required(circuit_lib, CIRCUIT_MODEL_IOPAD);
|
2020-11-02 14:54:31 -06:00
|
|
|
num_err += check_io_circuit_model(circuit_lib);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
/* 4. Check mux has been defined and has input and output ports
|
2022-10-06 19:08:50 -05:00
|
|
|
* [a] We must have a MUX!
|
|
|
|
* [b] For each MUX, we must have at least an input, an output, and an SRAM
|
|
|
|
* port
|
2020-01-12 19:11:00 -06:00
|
|
|
*/
|
|
|
|
num_err += check_circuit_model_required(circuit_lib, CIRCUIT_MODEL_MUX);
|
|
|
|
|
|
|
|
std::vector<enum e_circuit_model_port_type> mux_port_types_required;
|
|
|
|
mux_port_types_required.push_back(CIRCUIT_MODEL_PORT_INPUT);
|
|
|
|
mux_port_types_required.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
|
|
|
|
mux_port_types_required.push_back(CIRCUIT_MODEL_PORT_SRAM);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_MUX,
|
|
|
|
mux_port_types_required);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
/* 5. We must have at least one SRAM or CCFF */
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((0 == circuit_lib.models_by_type(CIRCUIT_MODEL_SRAM).size()) &&
|
|
|
|
(0 == circuit_lib.models_by_type(CIRCUIT_MODEL_CCFF).size())) {
|
2020-01-12 19:11:00 -06:00
|
|
|
VTR_LOG_ERROR("At least one %s or %s circuit model is required!\n",
|
2022-10-06 19:08:50 -05:00
|
|
|
CIRCUIT_MODEL_TYPE_STRING[size_t(CIRCUIT_MODEL_SRAM)],
|
2020-01-12 19:11:00 -06:00
|
|
|
CIRCUIT_MODEL_TYPE_STRING[size_t(CIRCUIT_MODEL_CCFF)]);
|
|
|
|
/* Incremental the counter for errors */
|
|
|
|
num_err++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 6. SRAM must have at least an input and an output ports*/
|
|
|
|
std::vector<enum e_circuit_model_port_type> sram_port_types_required;
|
|
|
|
sram_port_types_required.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_SRAM,
|
|
|
|
sram_port_types_required);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
/* 7. CCFF must have at least a clock, an input and an output ports*/
|
|
|
|
std::vector<enum e_circuit_model_port_type> ccff_port_types_required;
|
|
|
|
ccff_port_types_required.push_back(CIRCUIT_MODEL_PORT_CLOCK);
|
|
|
|
ccff_port_types_required.push_back(CIRCUIT_MODEL_PORT_INPUT);
|
|
|
|
ccff_port_types_required.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_CCFF,
|
|
|
|
ccff_port_types_required);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
/* 8. FF must have at least a clock, an input and an output ports*/
|
|
|
|
std::vector<enum e_circuit_model_port_type> ff_port_types_required;
|
|
|
|
ff_port_types_required.push_back(CIRCUIT_MODEL_PORT_CLOCK);
|
|
|
|
ff_port_types_required.push_back(CIRCUIT_MODEL_PORT_INPUT);
|
|
|
|
ff_port_types_required.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_FF,
|
|
|
|
ff_port_types_required);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
|
|
|
/* 9. LUT must have at least an input, an output and a SRAM ports*/
|
|
|
|
std::vector<enum e_circuit_model_port_type> lut_port_types_required;
|
|
|
|
lut_port_types_required.push_back(CIRCUIT_MODEL_PORT_SRAM);
|
|
|
|
lut_port_types_required.push_back(CIRCUIT_MODEL_PORT_INPUT);
|
|
|
|
lut_port_types_required.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_LUT,
|
|
|
|
lut_port_types_required);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* 10. For each type of circuit models that are define, we must have 1 default
|
|
|
|
* model We must have default circuit models for these types: MUX, channel
|
|
|
|
* wires and wires
|
2020-08-23 14:48:22 -05:00
|
|
|
*/
|
|
|
|
num_err += check_default_circuit_model_by_types(circuit_lib);
|
2022-10-06 19:08:50 -05:00
|
|
|
num_err +=
|
|
|
|
check_required_default_circuit_model(circuit_lib, CIRCUIT_MODEL_MUX);
|
|
|
|
num_err +=
|
|
|
|
check_required_default_circuit_model(circuit_lib, CIRCUIT_MODEL_CHAN_WIRE);
|
|
|
|
num_err +=
|
|
|
|
check_required_default_circuit_model(circuit_lib, CIRCUIT_MODEL_WIRE);
|
2020-01-12 19:11:00 -06:00
|
|
|
|
2020-07-22 19:47:12 -05:00
|
|
|
/* 11. Check power-gated inverter/buffer models */
|
|
|
|
num_err += check_power_gated_circuit_models(circuit_lib);
|
|
|
|
|
2020-01-12 19:11:00 -06:00
|
|
|
/* If we have any errors, exit */
|
|
|
|
|
|
|
|
if (0 < num_err) {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_LOG("Finished checking circuit library with %d errors!\n", num_err);
|
2020-05-14 21:02:42 -05:00
|
|
|
return false;
|
2020-01-12 19:11:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
VTR_LOG("Checking circuit library passed.\n");
|
|
|
|
|
2020-05-14 21:02:42 -05:00
|
|
|
return true;
|
2020-01-12 19:11:00 -06:00
|
|
|
}
|