2020-01-12 22:33:28 -06:00
|
|
|
/********************************************************************
|
|
|
|
* This file includes the top-level function of this library
|
|
|
|
* which reads an XML modeling OpenFPGA architecture to the associated
|
|
|
|
* data structures
|
|
|
|
*******************************************************************/
|
2020-01-12 23:39:38 -06:00
|
|
|
#include <string>
|
2020-01-12 22:33:28 -06:00
|
|
|
|
|
|
|
/* Headers from pugi XML library */
|
|
|
|
#include "pugixml.hpp"
|
|
|
|
#include "pugixml_util.hpp"
|
|
|
|
|
2020-01-14 17:24:27 -06:00
|
|
|
/* Headers from vtr util library */
|
|
|
|
#include "vtr_assert.h"
|
|
|
|
|
2020-01-12 22:33:28 -06:00
|
|
|
/* Headers from libarchfpga */
|
|
|
|
#include "arch_error.h"
|
|
|
|
#include "read_xml_util.h"
|
|
|
|
|
2020-01-16 14:26:55 -06:00
|
|
|
/* Headers from openfpgautil library */
|
|
|
|
#include "openfpga_tokenizer.h"
|
2020-01-14 09:33:48 -06:00
|
|
|
#include "read_xml_circuit_library.h"
|
2020-01-12 22:33:28 -06:00
|
|
|
|
2020-01-12 23:39:38 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of model type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_type string_to_circuit_model_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_TYPES; ++itype) {
|
|
|
|
if (std::string(CIRCUIT_MODEL_TYPE_STRING[itype]) == type_string) {
|
|
|
|
return static_cast<e_circuit_model_type>(itype);
|
|
|
|
}
|
2020-01-12 23:39:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Reach here, we have an invalid value, error out */
|
|
|
|
return NUM_CIRCUIT_MODEL_TYPES;
|
|
|
|
}
|
|
|
|
|
2020-01-14 15:10:00 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of model type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_design_tech string_to_design_tech_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_DESIGN_TECH_TYPES; ++itype) {
|
2022-10-06 19:08:50 -05:00
|
|
|
if (std::string(CIRCUIT_MODEL_DESIGN_TECH_TYPE_STRING[itype]) ==
|
|
|
|
type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
return static_cast<e_circuit_model_design_tech>(itype);
|
|
|
|
}
|
2020-01-14 15:10:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_CIRCUIT_MODEL_DESIGN_TECH_TYPES;
|
|
|
|
}
|
|
|
|
|
2020-01-14 16:44:24 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of buffer type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_buffer_type string_to_buffer_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_BUF_TYPES; ++itype) {
|
|
|
|
if (std::string(CIRCUIT_MODEL_BUFFER_TYPE_STRING[itype]) == type_string) {
|
|
|
|
return static_cast<e_circuit_model_buffer_type>(itype);
|
|
|
|
}
|
2020-01-14 16:44:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_CIRCUIT_MODEL_BUF_TYPES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of pass-gate-logic type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_pass_gate_logic_type string_to_passgate_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_PASS_GATE_TYPES; ++itype) {
|
|
|
|
if (std::string(CIRCUIT_MODEL_PASSGATE_TYPE_STRING[itype]) == type_string) {
|
|
|
|
return static_cast<e_circuit_model_pass_gate_logic_type>(itype);
|
|
|
|
}
|
2020-01-14 16:44:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_CIRCUIT_MODEL_PASS_GATE_TYPES;
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:24:27 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of multiplexer structure
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_structure string_to_mux_structure_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_STRUCTURE_TYPES; ++itype) {
|
2022-10-06 19:08:50 -05:00
|
|
|
if (std::string(CIRCUIT_MODEL_STRUCTURE_TYPE_STRING[itype]) ==
|
|
|
|
type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
return static_cast<e_circuit_model_structure>(itype);
|
|
|
|
}
|
2020-01-14 17:24:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_CIRCUIT_MODEL_STRUCTURE_TYPES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of logic gate type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_gate_type string_to_gate_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_GATE_TYPES; ++itype) {
|
|
|
|
if (std::string(CIRCUIT_MODEL_GATE_TYPE_STRING[itype]) == type_string) {
|
|
|
|
return static_cast<e_circuit_model_gate_type>(itype);
|
|
|
|
}
|
2020-01-14 17:24:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_CIRCUIT_MODEL_GATE_TYPES;
|
|
|
|
}
|
|
|
|
|
2020-01-15 18:29:49 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of circuit model port type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_port_type string_to_circuit_model_port_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_PORT_TYPES; ++itype) {
|
|
|
|
if (std::string(CIRCUIT_MODEL_PORT_TYPE_STRING[itype]) == type_string) {
|
|
|
|
return static_cast<e_circuit_model_port_type>(itype);
|
|
|
|
}
|
2020-01-15 18:29:49 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_CIRCUIT_MODEL_PORT_TYPES;
|
|
|
|
}
|
|
|
|
|
2020-01-15 20:54:57 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of wire model type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_wire_model_type string_to_wire_model_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_WIRE_MODEL_TYPES; ++itype) {
|
|
|
|
if (std::string(WIRE_MODEL_TYPE_STRING[itype]) == type_string) {
|
|
|
|
return static_cast<e_wire_model_type>(itype);
|
|
|
|
}
|
2020-01-15 20:54:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_WIRE_MODEL_TYPES;
|
|
|
|
}
|
|
|
|
|
2020-01-15 21:21:53 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Convert string to the enumerate of delay model type
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static e_circuit_model_delay_type string_to_circuit_model_delay_type(
|
|
|
|
const std::string& type_string) {
|
2020-09-27 15:33:14 -05:00
|
|
|
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_DELAY_TYPES; ++itype) {
|
|
|
|
if (std::string(CIRCUIT_MODEL_DELAY_TYPE_STRING[itype]) == type_string) {
|
|
|
|
return static_cast<e_circuit_model_delay_type>(itype);
|
|
|
|
}
|
2020-01-15 21:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return NUM_CIRCUIT_MODEL_DELAY_TYPES;
|
|
|
|
}
|
|
|
|
|
2020-01-14 15:10:00 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Parse XML codes of design technology of a circuit model to circuit library
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static void read_xml_model_design_technology(pugi::xml_node& xml_model,
|
|
|
|
const pugiutil::loc_data& loc_data,
|
|
|
|
CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& model) {
|
|
|
|
auto xml_design_tech =
|
|
|
|
get_single_child(xml_model, "design_technology", loc_data);
|
2020-01-14 15:10:00 -06:00
|
|
|
|
|
|
|
/* Identify if the circuit model power-gated */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_model_is_power_gated(
|
|
|
|
model, get_attribute(xml_design_tech, "power_gated", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-14 15:10:00 -06:00
|
|
|
|
|
|
|
/* Identify the type of design technology */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* type_attr =
|
|
|
|
get_attribute(xml_design_tech, "type", loc_data).value();
|
2020-01-14 15:10:00 -06:00
|
|
|
/* Translate the type of design technology to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_design_tech design_tech_type =
|
|
|
|
string_to_design_tech_type(std::string(type_attr));
|
2020-01-14 15:10:00 -06:00
|
|
|
|
|
|
|
if (NUM_CIRCUIT_MODEL_DESIGN_TECH_TYPES == design_tech_type) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'type' attribute '%s'\n", type_attr);
|
2020-01-14 15:10:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
circuit_lib.set_model_design_tech_type(model, design_tech_type);
|
2022-10-06 19:08:50 -05:00
|
|
|
|
2020-01-14 15:10:00 -06:00
|
|
|
/* Parse exclusive attributes for inverters and buffers */
|
2020-01-14 16:44:24 -06:00
|
|
|
if (CIRCUIT_MODEL_INVBUF == circuit_lib.model_type(model)) {
|
|
|
|
/* Identify the topology of the buffer */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* topology_attr =
|
|
|
|
get_attribute(xml_design_tech, "topology", loc_data).value();
|
2020-01-14 16:44:24 -06:00
|
|
|
/* Translate the type of buffer to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_buffer_type buf_type =
|
|
|
|
string_to_buffer_type(std::string(topology_attr));
|
2020-01-14 16:44:24 -06:00
|
|
|
|
|
|
|
if (NUM_CIRCUIT_MODEL_BUF_TYPES == buf_type) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'topology' attribute '%s'\n", topology_attr);
|
|
|
|
}
|
2020-01-14 16:44:24 -06:00
|
|
|
|
|
|
|
circuit_lib.set_buffer_type(model, buf_type);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Parse the others options:
|
|
|
|
* 1. size of buffer in the first stage
|
|
|
|
* 2. number of levels
|
2020-01-14 16:44:24 -06:00
|
|
|
* 3. driving strength per stage
|
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_buffer_size(
|
|
|
|
model, get_attribute(xml_design_tech, "size", loc_data).as_float(0.));
|
|
|
|
circuit_lib.set_buffer_num_levels(
|
|
|
|
model, get_attribute(xml_design_tech, "num_level", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_int(1));
|
|
|
|
circuit_lib.set_buffer_f_per_stage(
|
|
|
|
model, get_attribute(xml_design_tech, "f_per_stage", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_int(4));
|
2020-01-14 16:44:24 -06:00
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
|
2020-01-14 16:44:24 -06:00
|
|
|
/* Parse exclusive attributes for pass-gate logics */
|
|
|
|
if (CIRCUIT_MODEL_PASSGATE == circuit_lib.model_type(model)) {
|
|
|
|
/* Identify the topology of the pass-gate logic */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* topology_attr =
|
|
|
|
get_attribute(xml_design_tech, "topology", loc_data).value();
|
2020-01-14 16:44:24 -06:00
|
|
|
/* Translate the type of pass-gate logic to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_pass_gate_logic_type passgate_type =
|
|
|
|
string_to_passgate_type(std::string(topology_attr));
|
2020-01-14 16:44:24 -06:00
|
|
|
|
|
|
|
if (NUM_CIRCUIT_MODEL_PASS_GATE_TYPES == passgate_type) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'topology' attribute '%s'\n", topology_attr);
|
|
|
|
}
|
2020-01-14 16:44:24 -06:00
|
|
|
|
|
|
|
circuit_lib.set_pass_gate_logic_type(model, passgate_type);
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Parse the others options:
|
|
|
|
* 1. pmos size to be used in the pass gate logic
|
|
|
|
* 2. nmos size to be used in the pass gate logic
|
2020-01-14 16:44:24 -06:00
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_pass_gate_logic_pmos_size(
|
|
|
|
model,
|
|
|
|
get_attribute(xml_design_tech, "pmos_size", loc_data).as_float(0.));
|
|
|
|
circuit_lib.set_pass_gate_logic_nmos_size(
|
|
|
|
model,
|
|
|
|
get_attribute(xml_design_tech, "nmos_size", loc_data).as_float(0.));
|
2020-01-14 16:44:24 -06:00
|
|
|
}
|
|
|
|
|
2020-01-14 17:24:27 -06:00
|
|
|
/* Parse exclusive attributes for Look-Up Tables (LUTs) */
|
|
|
|
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
|
|
|
|
/* Identify if this is a fracturable LUT */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_lut_is_fracturable(
|
|
|
|
model, get_attribute(xml_design_tech, "fracturable_lut", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-14 17:24:27 -06:00
|
|
|
/* Set default MUX-relate attributes as LUT contains a tree-like MUX */
|
|
|
|
circuit_lib.set_mux_structure(model, CIRCUIT_MODEL_STRUCTURE_TREE);
|
|
|
|
circuit_lib.set_mux_use_local_encoder(model, false);
|
|
|
|
circuit_lib.set_mux_use_advanced_rram_design(model, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse exclusive attributes for multiplexers */
|
|
|
|
if (CIRCUIT_MODEL_MUX == circuit_lib.model_type(model)) {
|
|
|
|
/* Set default values for multiplexer structure */
|
|
|
|
if (CIRCUIT_MODEL_DESIGN_CMOS == circuit_lib.design_tech_type(model)) {
|
|
|
|
circuit_lib.set_mux_structure(model, CIRCUIT_MODEL_STRUCTURE_TREE);
|
|
|
|
} else {
|
2022-10-06 19:08:50 -05:00
|
|
|
VTR_ASSERT_SAFE(CIRCUIT_MODEL_DESIGN_RRAM ==
|
|
|
|
circuit_lib.design_tech_type(model));
|
2020-01-14 17:24:27 -06:00
|
|
|
circuit_lib.set_mux_structure(model, CIRCUIT_MODEL_STRUCTURE_ONELEVEL);
|
|
|
|
}
|
|
|
|
/* Identify the topology of the multiplexer structure */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* structure_attr =
|
|
|
|
get_attribute(xml_design_tech, "structure", loc_data).value();
|
2020-01-14 17:24:27 -06:00
|
|
|
/* Translate the type of multiplexer structure to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_structure mux_structure =
|
|
|
|
string_to_mux_structure_type(std::string(structure_attr));
|
|
|
|
|
2020-01-14 17:24:27 -06:00
|
|
|
if (NUM_CIRCUIT_MODEL_STRUCTURE_TYPES == mux_structure) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'structure' attribute '%s'\n", structure_attr);
|
|
|
|
}
|
2020-01-14 17:24:27 -06:00
|
|
|
|
|
|
|
circuit_lib.set_mux_structure(model, mux_structure);
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Parse the others options:
|
2020-01-14 17:24:27 -06:00
|
|
|
* 1. constant input values
|
|
|
|
* 2. number of levels if multi-level multiplexer structure is selected
|
|
|
|
* 3. if advanced ReRAM design is used
|
2022-10-06 19:08:50 -05:00
|
|
|
* 4. if local encoder is to be used
|
2020-01-14 17:24:27 -06:00
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if (true == get_attribute(xml_design_tech, "add_const_input", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false)) {
|
|
|
|
circuit_lib.set_mux_const_input_value(
|
|
|
|
model,
|
|
|
|
get_attribute(xml_design_tech, "const_input_val", loc_data).as_int(0));
|
2020-01-14 17:24:27 -06:00
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
if (CIRCUIT_MODEL_STRUCTURE_MULTILEVEL ==
|
|
|
|
circuit_lib.mux_structure(model)) {
|
|
|
|
circuit_lib.set_mux_num_levels(
|
|
|
|
model, get_attribute(xml_design_tech, "num_level", loc_data).as_int(1));
|
|
|
|
/* Correction on the mux structure:
|
2020-01-16 15:45:41 -06:00
|
|
|
* if the number of level is set to 1 in a multi-level multiplexer,
|
|
|
|
* we change the mux structure to one-level
|
|
|
|
*/
|
|
|
|
if (1 == circuit_lib.mux_num_levels(model)) {
|
|
|
|
circuit_lib.set_mux_structure(model, CIRCUIT_MODEL_STRUCTURE_ONELEVEL);
|
|
|
|
}
|
2020-01-14 17:24:27 -06:00
|
|
|
}
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_mux_use_advanced_rram_design(
|
|
|
|
model, get_attribute(xml_design_tech, "advanced_rram_design", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
|
|
|
circuit_lib.set_mux_use_local_encoder(
|
|
|
|
model, get_attribute(xml_design_tech, "local_encoder", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-14 17:24:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse exclusive attributes for logic gates */
|
|
|
|
if (CIRCUIT_MODEL_GATE == circuit_lib.model_type(model)) {
|
|
|
|
/* Identify the topology of the logic gate */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* topology_attr =
|
|
|
|
get_attribute(xml_design_tech, "topology", loc_data).value();
|
2020-01-14 17:24:27 -06:00
|
|
|
/* Translate the type of logic gate to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_gate_type gate_type =
|
|
|
|
string_to_gate_type(std::string(topology_attr));
|
2020-01-14 17:24:27 -06:00
|
|
|
|
|
|
|
if (NUM_CIRCUIT_MODEL_GATE_TYPES == gate_type) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'topology' attribute '%s'\n", topology_attr);
|
|
|
|
}
|
2020-01-14 17:24:27 -06:00
|
|
|
|
|
|
|
circuit_lib.set_gate_type(model, gate_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse exclusive attributes for RRAM */
|
|
|
|
if (CIRCUIT_MODEL_DESIGN_RRAM == circuit_lib.design_tech_type(model)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_rram_rlrs(
|
|
|
|
model, get_attribute(xml_design_tech, "ron", loc_data).as_float(0.));
|
|
|
|
circuit_lib.set_rram_rhrs(
|
|
|
|
model, get_attribute(xml_design_tech, "roff", loc_data).as_float(0.));
|
|
|
|
circuit_lib.set_rram_wprog_set_pmos(
|
|
|
|
model,
|
|
|
|
get_attribute(xml_design_tech, "wprog_set_pmos", loc_data).as_float(0.));
|
|
|
|
circuit_lib.set_rram_wprog_set_nmos(
|
|
|
|
model,
|
|
|
|
get_attribute(xml_design_tech, "wprog_set_nmos", loc_data).as_float(0.));
|
|
|
|
circuit_lib.set_rram_wprog_reset_pmos(
|
|
|
|
model, get_attribute(xml_design_tech, "wprog_reset_pmos", loc_data)
|
|
|
|
.as_float(0.));
|
|
|
|
circuit_lib.set_rram_wprog_reset_nmos(
|
|
|
|
model, get_attribute(xml_design_tech, "wprog_reset_nmos", loc_data)
|
|
|
|
.as_float(0.));
|
2020-01-14 17:24:27 -06:00
|
|
|
}
|
2020-01-15 16:27:49 -06:00
|
|
|
}
|
|
|
|
|
2020-07-13 21:35:10 -05:00
|
|
|
/********************************************************************
|
|
|
|
* Parse XML codes of device technology of a circuit model to circuit library
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static void read_xml_model_device_technology(pugi::xml_node& xml_model,
|
|
|
|
const pugiutil::loc_data& loc_data,
|
|
|
|
CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& model) {
|
|
|
|
auto xml_device_tech = get_single_child(xml_model, "device_technology",
|
|
|
|
loc_data, pugiutil::ReqOpt::OPTIONAL);
|
2020-07-13 21:35:10 -05:00
|
|
|
|
2020-07-14 13:04:22 -05:00
|
|
|
if (!xml_device_tech) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-13 21:35:10 -05:00
|
|
|
|
|
|
|
/* Parse device model name */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* device_model_name_attr =
|
|
|
|
get_attribute(xml_device_tech, "device_model_name", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.value();
|
2020-07-13 21:35:10 -05:00
|
|
|
if (nullptr != device_model_name_attr) {
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_device_model_name(model,
|
|
|
|
std::string(device_model_name_attr));
|
2020-07-13 21:35:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-15 16:27:49 -06:00
|
|
|
/********************************************************************
|
|
|
|
* This is a generic function to parse XML codes that describe
|
|
|
|
* a buffer of a circuit model to circuit library
|
2022-10-06 19:08:50 -05:00
|
|
|
* This function will return a string with the circuit model name
|
2020-01-15 16:27:49 -06:00
|
|
|
* linked to the buffer
|
|
|
|
* If the return is empty, it means that buffer does NOT exist
|
2022-10-06 19:08:50 -05:00
|
|
|
*******************************************************************/
|
|
|
|
static std::string read_xml_buffer(pugi::xml_node& xml_buffer,
|
|
|
|
const pugiutil::loc_data& loc_data) {
|
|
|
|
bool buffer_existence =
|
|
|
|
get_attribute(xml_buffer, "exist", loc_data).as_bool(false);
|
2020-01-15 16:27:49 -06:00
|
|
|
std::string buffer_circuit_model_name("");
|
2022-10-06 19:08:50 -05:00
|
|
|
|
|
|
|
if (true == buffer_existence) {
|
|
|
|
buffer_circuit_model_name =
|
|
|
|
get_attribute(xml_buffer, "circuit_model_name", loc_data).as_string();
|
2020-01-15 16:27:49 -06:00
|
|
|
}
|
2020-01-14 17:24:27 -06:00
|
|
|
|
2020-01-15 16:27:49 -06:00
|
|
|
return buffer_circuit_model_name;
|
2020-01-14 15:10:00 -06:00
|
|
|
}
|
|
|
|
|
2020-01-15 18:29:49 -06:00
|
|
|
/********************************************************************
|
2022-10-06 19:08:50 -05:00
|
|
|
* Identify the output mask of the port in LUTs,
|
2020-01-15 18:29:49 -06:00
|
|
|
* by default it will be applied to each pin of this port
|
|
|
|
* This is only applicable to output ports of a LUT
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static void read_xml_output_mask(pugi::xml_node& xml_port,
|
|
|
|
const pugiutil::loc_data& loc_data,
|
|
|
|
CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitPortId& port) {
|
|
|
|
std::string output_mask_attr =
|
|
|
|
get_attribute(xml_port, "lut_output_mask", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string();
|
2020-01-15 18:29:49 -06:00
|
|
|
std::vector<size_t> mask_vector;
|
2020-01-16 17:05:11 -06:00
|
|
|
if (!output_mask_attr.empty()) {
|
2020-01-15 18:29:49 -06:00
|
|
|
/* Split the string with token ',' */
|
2022-10-06 19:08:50 -05:00
|
|
|
openfpga::StringToken string_tokenizer(
|
|
|
|
get_attribute(xml_port, "lut_output_mask", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string(nullptr));
|
2020-01-15 18:29:49 -06:00
|
|
|
for (const std::string& mask_token : string_tokenizer.split(',')) {
|
|
|
|
mask_vector.push_back(std::atoi(mask_token.c_str()));
|
|
|
|
}
|
|
|
|
/* Make sure that the size of mask fits the port size */
|
|
|
|
if (circuit_lib.port_size(port) != mask_vector.size()) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_port),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid lut_output_mask attribute '%s'! It must match "
|
|
|
|
"the port size (=%lu)\n",
|
2020-09-14 22:26:53 -05:00
|
|
|
output_mask_attr.c_str(), circuit_lib.port_size(port));
|
2022-10-06 19:08:50 -05:00
|
|
|
}
|
2020-01-15 18:29:49 -06:00
|
|
|
} else {
|
|
|
|
/* By default, we give a mask vector covering each pin of the port */
|
|
|
|
mask_vector.resize(circuit_lib.port_size(port));
|
|
|
|
std::iota(mask_vector.begin(), mask_vector.end(), 0);
|
|
|
|
}
|
|
|
|
circuit_lib.set_port_lut_output_mask(port, mask_vector);
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************
|
|
|
|
* This is a generic function to parse XML codes that describe
|
|
|
|
* a port of a circuit model to circuit library
|
2022-10-06 19:08:50 -05:00
|
|
|
*******************************************************************/
|
|
|
|
static void read_xml_circuit_port(pugi::xml_node& xml_port,
|
|
|
|
const pugiutil::loc_data& loc_data,
|
|
|
|
CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& model) {
|
2020-01-15 18:29:49 -06:00
|
|
|
/* Find the type of the circuit port
|
2022-10-06 19:08:50 -05:00
|
|
|
* so that we can add a new circuit port to circuit library
|
2020-01-15 18:29:49 -06:00
|
|
|
*/
|
|
|
|
const char* type_attr = get_attribute(xml_port, "type", loc_data).value();
|
|
|
|
|
|
|
|
/* Translate the type of circuit model to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_port_type port_type =
|
|
|
|
string_to_circuit_model_port_type(std::string(type_attr));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
if (NUM_CIRCUIT_MODEL_PORT_TYPES == port_type) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_port),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'type' attribute '%s'\n", type_attr);
|
2020-01-15 18:29:49 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
CircuitPortId port = circuit_lib.add_model_port(model, port_type);
|
|
|
|
|
|
|
|
/* Parse the name of the port */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_prefix(
|
|
|
|
port, get_attribute(xml_port, "prefix", loc_data).as_string());
|
|
|
|
|
|
|
|
/* Parse the name of the port in cell library. By default, the lib_name is the
|
|
|
|
* same as port name */
|
|
|
|
const char* lib_name_attr =
|
|
|
|
get_attribute(xml_port, "lib_name", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string(nullptr);
|
2020-01-15 18:29:49 -06:00
|
|
|
if (nullptr != lib_name_attr) {
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_lib_name(
|
|
|
|
port, get_attribute(xml_port, "lib_name", loc_data).as_string());
|
2020-01-15 18:29:49 -06:00
|
|
|
} else {
|
|
|
|
circuit_lib.set_port_lib_name(port, circuit_lib.port_prefix(port));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse the port size, by default it will be 1 */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_size(
|
|
|
|
port, get_attribute(xml_port, "size", loc_data).as_int(1));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
2020-04-05 17:52:21 -05:00
|
|
|
/* Identify if the port is for io, this is only applicable to INPUT ports.
|
|
|
|
* By default, it will NOT be a mode selection port
|
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_io(
|
|
|
|
port, get_attribute(xml_port, "is_io", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-04-05 17:52:21 -05:00
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Identify if the port is a data io, ONLY applicable to I/O port
|
2020-11-04 21:21:49 -06:00
|
|
|
* By default, it will NOT be a data io port
|
|
|
|
*/
|
|
|
|
if (true == circuit_lib.port_is_io(port)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_data_io(
|
|
|
|
port, get_attribute(xml_port, "is_data_io", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-11-04 21:21:49 -06:00
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Identify if the port is for mode selection, this is only applicable to SRAM
|
|
|
|
* ports. By default, it will NOT be a mode selection port
|
2020-01-15 18:29:49 -06:00
|
|
|
*/
|
|
|
|
if (CIRCUIT_MODEL_PORT_SRAM == circuit_lib.port_type(port)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_mode_select(
|
|
|
|
port, get_attribute(xml_port, "mode_select", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
|
|
|
}
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
/* Identify the default value of the port, by default it will be 0 */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_default_value(
|
|
|
|
port,
|
|
|
|
get_attribute(xml_port, "default_val", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_int(0));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Identify the tri-state map of the port, by default it will be nullptr
|
2020-01-15 18:29:49 -06:00
|
|
|
* This is only applicable to input ports of a LUT
|
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_INPUT == circuit_lib.port_type(port))) {
|
|
|
|
const char* tri_state_map_attr =
|
|
|
|
get_attribute(xml_port, "tri_state_map", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.value();
|
2020-01-15 18:29:49 -06:00
|
|
|
if (nullptr != tri_state_map_attr) {
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_tri_state_map(
|
|
|
|
port, get_attribute(xml_port, "tri_state_map", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string());
|
2020-01-15 18:29:49 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Identify the fracturable-level of the port in LUTs, by default it will be
|
|
|
|
* -1 This is only applicable to output ports of a LUT
|
2020-01-15 18:29:49 -06:00
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port))) {
|
|
|
|
circuit_lib.set_port_lut_frac_level(
|
|
|
|
port, get_attribute(xml_port, "lut_frac_level", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_int(-1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Identify if the port carries a harden functionality rather than a
|
|
|
|
* reconfigurable port This is only applicable to LUT circuit models. The
|
|
|
|
* super LUT circuit model (whose netlists are supposed to be provided by
|
|
|
|
* users) contains some hard logic inside, e.g., a carry logic. By default, a
|
|
|
|
* port does NOT carry a hard functionality
|
2021-02-09 22:15:57 -06:00
|
|
|
*/
|
|
|
|
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_harden_lut_port(
|
|
|
|
port, get_attribute(xml_port, "is_harden_lut_port", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2021-02-09 22:15:57 -06:00
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Identify the output mask of the port in LUTs, by default it will be applied
|
|
|
|
* to each pin of this port This is only applicable to output ports of a LUT
|
2020-01-15 18:29:49 -06:00
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) &&
|
|
|
|
(CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port))) {
|
2020-01-15 18:29:49 -06:00
|
|
|
read_xml_output_mask(xml_port, loc_data, circuit_lib, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Identify if the port is a global port, by default it is NOT */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_global(
|
|
|
|
port,
|
|
|
|
get_attribute(xml_port, "is_global", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
/* Identify if the port is a reset port, by default it is NOT */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_reset(
|
|
|
|
port,
|
|
|
|
get_attribute(xml_port, "is_reset", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
/* Identify if the port is a set port, by default it is NOT */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_set(port, get_attribute(xml_port, "is_set", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
/* Identify if the port is in programming purpose, by default it is NOT */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_prog(
|
|
|
|
port,
|
|
|
|
get_attribute(xml_port, "is_prog", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
2021-10-01 13:00:38 -05:00
|
|
|
/* Identify if the port is in shift register purpose, by default it is NOT */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_is_shift_register(
|
|
|
|
port, get_attribute(xml_port, "is_shift_register", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
|
|
|
|
|
|
|
/* Identify if the port is to enable programming for FPGAs, by default it is
|
|
|
|
* NOT */
|
|
|
|
circuit_lib.set_port_is_config_enable(
|
|
|
|
port, get_attribute(xml_port, "is_config_enable", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
/* Find the name of circuit model that this port is linked to */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_port_tri_state_model_name(
|
|
|
|
port, get_attribute(xml_port, "circuit_model_name", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string());
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
/* Find the name of circuit model that port is used for inversion of signals,
|
|
|
|
* This is only applicable to BL/WL/BLB/WLB ports
|
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((CIRCUIT_MODEL_PORT_BL == circuit_lib.port_type(port)) ||
|
|
|
|
(CIRCUIT_MODEL_PORT_WL == circuit_lib.port_type(port)) ||
|
|
|
|
(CIRCUIT_MODEL_PORT_BLB == circuit_lib.port_type(port)) ||
|
|
|
|
(CIRCUIT_MODEL_PORT_WLB == circuit_lib.port_type(port))) {
|
|
|
|
circuit_lib.set_port_inv_model_name(
|
|
|
|
port, get_attribute(xml_port, "inv_circuit_model_name", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string());
|
2020-01-15 18:29:49 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-15 20:54:57 -06:00
|
|
|
/********************************************************************
|
|
|
|
* This is a generic function to parse XML codes that describe
|
|
|
|
* RC parasitics for wire circuit model to circuit library
|
2022-10-06 19:08:50 -05:00
|
|
|
*******************************************************************/
|
|
|
|
static void read_xml_wire_param(pugi::xml_node& xml_wire_param,
|
|
|
|
const pugiutil::loc_data& loc_data,
|
|
|
|
CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& model) {
|
2020-01-15 20:54:57 -06:00
|
|
|
/* Find the type of the wire model */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* type_attr =
|
|
|
|
get_attribute(xml_wire_param, "model_type", loc_data).value();
|
2020-01-15 20:54:57 -06:00
|
|
|
|
|
|
|
/* Translate the type of circuit model to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_wire_model_type wire_model_type =
|
|
|
|
string_to_wire_model_type(std::string(type_attr));
|
2020-01-15 20:54:57 -06:00
|
|
|
|
|
|
|
if (NUM_WIRE_MODEL_TYPES == wire_model_type) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_wire_param),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'type' attribute '%s'\n", type_attr);
|
2020-01-15 20:54:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
circuit_lib.set_wire_type(model, wire_model_type);
|
|
|
|
|
|
|
|
/* Parse the R and C values */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_wire_r(
|
|
|
|
model, get_attribute(xml_wire_param, "R", loc_data).as_float(0.));
|
|
|
|
circuit_lib.set_wire_c(
|
|
|
|
model, get_attribute(xml_wire_param, "C", loc_data).as_float(0.));
|
2020-01-15 20:54:57 -06:00
|
|
|
|
|
|
|
/* Parse the number of levels for the wire model */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_wire_num_level(
|
|
|
|
model, get_attribute(xml_wire_param, "num_level", loc_data).as_int(0));
|
2020-01-15 20:54:57 -06:00
|
|
|
}
|
|
|
|
|
2020-01-15 21:21:53 -06:00
|
|
|
/********************************************************************
|
|
|
|
* This is a generic function to parse XML codes that describe
|
|
|
|
* a delay matrix for a circuit model to circuit library
|
2022-10-06 19:08:50 -05:00
|
|
|
*******************************************************************/
|
|
|
|
static void read_xml_delay_matrix(pugi::xml_node& xml_delay_matrix,
|
|
|
|
const pugiutil::loc_data& loc_data,
|
|
|
|
CircuitLibrary& circuit_lib,
|
|
|
|
const CircuitModelId& model) {
|
2020-01-15 21:21:53 -06:00
|
|
|
/* Find the type of the delay model, so that we can add to circuit library */
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* type_attr =
|
|
|
|
get_attribute(xml_delay_matrix, "type", loc_data).value();
|
2020-01-15 21:21:53 -06:00
|
|
|
|
|
|
|
/* Translate the type of delay matrix for a circuit model to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_delay_type delay_type =
|
|
|
|
string_to_circuit_model_delay_type(std::string(type_attr));
|
2020-01-15 21:21:53 -06:00
|
|
|
|
|
|
|
if (NUM_CIRCUIT_MODEL_DELAY_TYPES == delay_type) {
|
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_delay_matrix),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'type' attribute '%s'\n", type_attr);
|
2020-01-15 21:21:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
circuit_lib.add_delay_info(model, delay_type);
|
|
|
|
|
|
|
|
/* Parse the input ports */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_delay_in_port_names(
|
|
|
|
model, delay_type,
|
|
|
|
get_attribute(xml_delay_matrix, "in_port", loc_data).as_string());
|
2020-01-15 21:21:53 -06:00
|
|
|
|
|
|
|
/* Parse the output ports */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_delay_out_port_names(
|
|
|
|
model, delay_type,
|
|
|
|
get_attribute(xml_delay_matrix, "out_port", loc_data).as_string());
|
2020-01-15 21:21:53 -06:00
|
|
|
|
|
|
|
/* Parse the delay values */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_delay_values(model, delay_type,
|
|
|
|
std::string(xml_delay_matrix.child_value()));
|
2020-01-15 21:21:53 -06:00
|
|
|
}
|
|
|
|
|
2020-01-13 22:05:58 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Parse XML codes of a circuit model to circuit library
|
|
|
|
*******************************************************************/
|
2022-10-06 19:08:50 -05:00
|
|
|
static void read_xml_circuit_model(pugi::xml_node& xml_model,
|
|
|
|
const pugiutil::loc_data& loc_data,
|
|
|
|
CircuitLibrary& circuit_lib) {
|
2020-01-13 22:05:58 -06:00
|
|
|
/* Find the type of the circuit model
|
2022-10-06 19:08:50 -05:00
|
|
|
* so that we can add a new circuit model to circuit library
|
2020-01-13 22:05:58 -06:00
|
|
|
*/
|
2020-01-14 15:10:00 -06:00
|
|
|
const char* type_attr = get_attribute(xml_model, "type", loc_data).value();
|
2020-01-13 22:05:58 -06:00
|
|
|
|
|
|
|
/* Translate the type of circuit model to enumerate */
|
2022-10-06 19:08:50 -05:00
|
|
|
e_circuit_model_type model_type =
|
|
|
|
string_to_circuit_model_type(std::string(type_attr));
|
2020-01-13 22:05:58 -06:00
|
|
|
|
|
|
|
if (NUM_CIRCUIT_MODEL_TYPES == model_type) {
|
2020-01-14 15:10:00 -06:00
|
|
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_model),
|
2022-10-06 19:08:50 -05:00
|
|
|
"Invalid 'type' attribute '%s'\n", type_attr);
|
2020-01-13 22:05:58 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
CircuitModelId model = circuit_lib.add_model(model_type);
|
|
|
|
|
|
|
|
/* Find the name of the circuit model */
|
2020-01-14 15:10:00 -06:00
|
|
|
const char* name_attr = get_attribute(xml_model, "name", loc_data).value();
|
2020-01-13 22:05:58 -06:00
|
|
|
circuit_lib.set_model_name(model, std::string(name_attr));
|
2020-01-14 09:45:27 -06:00
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* TODO: This attribute is going to be DEPRECATED
|
2020-01-14 09:45:27 -06:00
|
|
|
* Find the prefix of the circuit model
|
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
const char* prefix_attr =
|
|
|
|
get_attribute(xml_model, "prefix", loc_data).value();
|
2020-01-14 09:45:27 -06:00
|
|
|
circuit_lib.set_model_prefix(model, std::string(prefix_attr));
|
|
|
|
|
|
|
|
/* Find a SPICE netlist which is an optional attribute*/
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_model_spice_netlist(
|
|
|
|
model, get_attribute(xml_model, "spice_netlist", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string(""));
|
2020-01-14 09:45:27 -06:00
|
|
|
|
|
|
|
/* Find a Verilog netlist which is an optional attribute*/
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_model_verilog_netlist(
|
|
|
|
model, get_attribute(xml_model, "verilog_netlist", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_string(""));
|
2020-01-14 15:10:00 -06:00
|
|
|
|
|
|
|
/* Find if the circuit model is default in its type */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_model_is_default(
|
|
|
|
model,
|
|
|
|
get_attribute(xml_model, "is_default", loc_data, pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
|
|
|
|
2020-01-14 15:10:00 -06:00
|
|
|
/* Find if the circuit model is should be dumped in structural verilog */
|
2022-10-06 19:08:50 -05:00
|
|
|
circuit_lib.set_model_dump_structural_verilog(
|
|
|
|
model, get_attribute(xml_model, "dump_structural_verilog", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL)
|
|
|
|
.as_bool(false));
|
2020-01-14 15:10:00 -06:00
|
|
|
|
|
|
|
/* Parse attributes under the <circuit_model> */
|
|
|
|
/* Design technology -related attributes */
|
|
|
|
read_xml_model_design_technology(xml_model, loc_data, circuit_lib, model);
|
2022-10-06 19:08:50 -05:00
|
|
|
|
2020-01-15 16:27:49 -06:00
|
|
|
/* Parse special buffer attributes required by LUTs only */
|
2022-10-06 19:08:50 -05:00
|
|
|
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
|
2020-01-15 16:27:49 -06:00
|
|
|
/* Input buffer of LUTs */
|
2022-10-06 19:08:50 -05:00
|
|
|
auto xml_input_buffer =
|
|
|
|
get_single_child(xml_model, "lut_input_buffer", loc_data);
|
|
|
|
std::string input_buffer_circuit_model_name =
|
|
|
|
read_xml_buffer(xml_input_buffer, loc_data);
|
|
|
|
circuit_lib.set_model_lut_input_buffer(
|
|
|
|
model, true != input_buffer_circuit_model_name.empty(),
|
|
|
|
input_buffer_circuit_model_name);
|
2020-01-15 16:27:49 -06:00
|
|
|
|
|
|
|
/* Input inverter of LUTs */
|
2022-10-06 19:08:50 -05:00
|
|
|
auto xml_input_inverter =
|
|
|
|
get_single_child(xml_model, "lut_input_inverter", loc_data);
|
|
|
|
std::string input_inverter_circuit_model_name =
|
|
|
|
read_xml_buffer(xml_input_inverter, loc_data);
|
|
|
|
circuit_lib.set_model_lut_input_inverter(
|
|
|
|
model, true != input_inverter_circuit_model_name.empty(),
|
|
|
|
input_inverter_circuit_model_name);
|
2020-01-15 16:27:49 -06:00
|
|
|
|
|
|
|
/* Intermediate buffer of LUTs */
|
2022-10-06 19:08:50 -05:00
|
|
|
auto xml_intermediate_buffer =
|
|
|
|
get_single_child(xml_model, "lut_intermediate_buffer", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL);
|
2020-01-15 16:27:49 -06:00
|
|
|
if (xml_intermediate_buffer) {
|
2022-10-06 19:08:50 -05:00
|
|
|
std::string intermediate_buffer_circuit_model_name =
|
|
|
|
read_xml_buffer(xml_intermediate_buffer, loc_data);
|
|
|
|
circuit_lib.set_model_lut_intermediate_buffer(
|
|
|
|
model, true != intermediate_buffer_circuit_model_name.empty(),
|
|
|
|
intermediate_buffer_circuit_model_name);
|
2020-01-15 16:27:49 -06:00
|
|
|
/* If intermediate buffer is defined, try to find the location map */
|
2022-10-06 19:08:50 -05:00
|
|
|
if (true != intermediate_buffer_circuit_model_name.empty()) {
|
|
|
|
circuit_lib.set_model_lut_intermediate_buffer_location_map(
|
|
|
|
model,
|
|
|
|
get_attribute(xml_intermediate_buffer, "location_map", loc_data)
|
|
|
|
.as_string());
|
2020-01-15 16:27:49 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-13 21:35:10 -05:00
|
|
|
/* Parse device technology attributes
|
|
|
|
* This is applicable to only atom circuit models:
|
|
|
|
* - inverter/buffer
|
|
|
|
* - pass gate
|
|
|
|
* - logic gates
|
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((CIRCUIT_MODEL_INVBUF == circuit_lib.model_type(model)) ||
|
|
|
|
(CIRCUIT_MODEL_PASSGATE == circuit_lib.model_type(model)) ||
|
|
|
|
(CIRCUIT_MODEL_GATE == circuit_lib.model_type(model))) {
|
|
|
|
read_xml_model_device_technology(xml_model, loc_data, circuit_lib, model);
|
2020-07-13 21:35:10 -05:00
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Input buffer attributes, NOT required for circuit models which are
|
|
|
|
* inverters or buffers */
|
2020-01-15 16:27:49 -06:00
|
|
|
if (CIRCUIT_MODEL_INVBUF != circuit_lib.model_type(model)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
auto xml_input_buffer =
|
|
|
|
get_single_child(xml_model, "input_buffer", loc_data);
|
|
|
|
std::string input_buffer_circuit_model_name =
|
|
|
|
read_xml_buffer(xml_input_buffer, loc_data);
|
|
|
|
circuit_lib.set_model_input_buffer(
|
|
|
|
model, true != input_buffer_circuit_model_name.empty(),
|
|
|
|
input_buffer_circuit_model_name);
|
2020-01-15 16:27:49 -06:00
|
|
|
}
|
|
|
|
|
2022-10-06 19:08:50 -05:00
|
|
|
/* Output buffer attributes, NOT required for circuit models which are
|
|
|
|
* inverters or buffers */
|
2020-01-15 16:27:49 -06:00
|
|
|
if (CIRCUIT_MODEL_INVBUF != circuit_lib.model_type(model)) {
|
2022-10-06 19:08:50 -05:00
|
|
|
auto xml_output_buffer =
|
|
|
|
get_single_child(xml_model, "output_buffer", loc_data);
|
|
|
|
std::string output_buffer_circuit_model_name =
|
|
|
|
read_xml_buffer(xml_output_buffer, loc_data);
|
|
|
|
circuit_lib.set_model_output_buffer(
|
|
|
|
model, true != output_buffer_circuit_model_name.empty(),
|
|
|
|
output_buffer_circuit_model_name);
|
2020-01-15 16:27:49 -06:00
|
|
|
}
|
2020-01-15 16:49:02 -06:00
|
|
|
|
|
|
|
/* Pass-gate-logic attributes, required by LUT and MUX */
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) ||
|
|
|
|
(CIRCUIT_MODEL_MUX == circuit_lib.model_type(model))) {
|
|
|
|
auto xml_pass_gate_logic =
|
|
|
|
get_single_child(xml_model, "pass_gate_logic", loc_data);
|
|
|
|
circuit_lib.set_model_pass_gate_logic(
|
|
|
|
model, get_attribute(xml_pass_gate_logic, "circuit_model_name", loc_data)
|
|
|
|
.as_string());
|
|
|
|
}
|
2020-01-15 18:29:49 -06:00
|
|
|
|
|
|
|
/* Parse all the ports belonging to this circuit model
|
2022-10-06 19:08:50 -05:00
|
|
|
* We count the number of ports in total and then add one by one
|
2020-01-15 18:29:49 -06:00
|
|
|
*/
|
2022-10-06 19:08:50 -05:00
|
|
|
size_t num_ports =
|
|
|
|
count_children(xml_model, "port", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
2020-01-16 17:05:11 -06:00
|
|
|
if (0 < num_ports) {
|
|
|
|
pugi::xml_node xml_port = get_first_child(xml_model, "port", loc_data);
|
|
|
|
while (xml_port) {
|
|
|
|
read_xml_circuit_port(xml_port, loc_data, circuit_lib, model);
|
|
|
|
xml_port = xml_port.next_sibling(xml_port.name());
|
2022-10-06 19:08:50 -05:00
|
|
|
}
|
2020-01-15 18:29:49 -06:00
|
|
|
}
|
2020-01-15 20:54:57 -06:00
|
|
|
|
|
|
|
/* Parse the parasitics of wires */
|
2022-10-06 19:08:50 -05:00
|
|
|
if ((CIRCUIT_MODEL_WIRE == circuit_lib.model_type(model)) ||
|
|
|
|
(CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(model))) {
|
|
|
|
auto xml_wire_param = get_single_child(xml_model, "wire_param", loc_data);
|
2020-01-15 20:54:57 -06:00
|
|
|
read_xml_wire_param(xml_wire_param, loc_data, circuit_lib, model);
|
|
|
|
}
|
|
|
|
|
2020-01-15 21:21:53 -06:00
|
|
|
/* Parse all the delay matrix if defined */
|
2022-10-06 19:08:50 -05:00
|
|
|
size_t num_delay_matrix = count_children(xml_model, "delay_matrix", loc_data,
|
|
|
|
pugiutil::ReqOpt::OPTIONAL);
|
2020-01-16 17:05:11 -06:00
|
|
|
if (0 < num_delay_matrix) {
|
2022-10-06 19:08:50 -05:00
|
|
|
pugi::xml_node xml_delay_matrix =
|
|
|
|
get_first_child(xml_model, "delay_matrix", loc_data);
|
2020-01-16 17:05:11 -06:00
|
|
|
while (xml_delay_matrix) {
|
|
|
|
read_xml_delay_matrix(xml_delay_matrix, loc_data, circuit_lib, model);
|
|
|
|
xml_delay_matrix = xml_delay_matrix.next_sibling(xml_delay_matrix.name());
|
|
|
|
}
|
2020-01-15 21:21:53 -06:00
|
|
|
}
|
2020-01-13 22:05:58 -06:00
|
|
|
}
|
|
|
|
|
2020-01-12 22:33:28 -06:00
|
|
|
/********************************************************************
|
|
|
|
* Parse XML codes about circuit models to circuit library
|
|
|
|
*******************************************************************/
|
2020-01-14 09:33:48 -06:00
|
|
|
CircuitLibrary read_xml_circuit_library(pugi::xml_node& Node,
|
|
|
|
const pugiutil::loc_data& loc_data) {
|
2020-01-12 23:39:38 -06:00
|
|
|
CircuitLibrary circuit_lib;
|
2020-01-14 09:33:48 -06:00
|
|
|
|
2020-01-12 22:33:28 -06:00
|
|
|
/* Iterate over the children under this node,
|
|
|
|
* each child should be named after circuit_model
|
|
|
|
*/
|
2020-01-14 15:10:00 -06:00
|
|
|
for (pugi::xml_node xml_model : Node.children()) {
|
2020-01-12 22:33:28 -06:00
|
|
|
/* Error out if the XML child has an invalid name! */
|
2020-01-14 15:10:00 -06:00
|
|
|
if (xml_model.name() != std::string("circuit_model")) {
|
|
|
|
bad_tag(xml_model, loc_data, Node, {"circuit_model"});
|
2020-01-12 22:33:28 -06:00
|
|
|
}
|
2020-01-14 15:10:00 -06:00
|
|
|
read_xml_circuit_model(xml_model, loc_data, circuit_lib);
|
2022-10-06 19:08:50 -05:00
|
|
|
}
|
2020-01-12 23:39:38 -06:00
|
|
|
|
|
|
|
return circuit_lib;
|
2020-01-12 22:33:28 -06:00
|
|
|
}
|