OpenFPGA/libs/libarchopenfpga/src/read_xml_circuit_library.cpp

890 lines
36 KiB
C++
Raw Normal View History

/********************************************************************
* This file includes the top-level function of this library
* which reads an XML modeling OpenFPGA architecture to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
/* Headers from openfpgautil library */
#include "openfpga_tokenizer.h"
2020-01-14 09:33:48 -06:00
#include "read_xml_circuit_library.h"
/********************************************************************
* Convert string to the enumerate of model type
*******************************************************************/
static e_circuit_model_type string_to_circuit_model_type(
const std::string& type_string) {
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);
}
}
/* Reach here, we have an invalid value, error out */
return NUM_CIRCUIT_MODEL_TYPES;
}
/********************************************************************
* Convert string to the enumerate of model type
*******************************************************************/
static e_circuit_model_design_tech string_to_design_tech_type(
const std::string& type_string) {
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_DESIGN_TECH_TYPES; ++itype) {
if (std::string(CIRCUIT_MODEL_DESIGN_TECH_TYPE_STRING[itype]) ==
type_string) {
return static_cast<e_circuit_model_design_tech>(itype);
}
}
return NUM_CIRCUIT_MODEL_DESIGN_TECH_TYPES;
}
/********************************************************************
* Convert string to the enumerate of buffer type
*******************************************************************/
static e_circuit_model_buffer_type string_to_buffer_type(
const std::string& type_string) {
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);
}
}
return NUM_CIRCUIT_MODEL_BUF_TYPES;
}
/********************************************************************
* Convert string to the enumerate of pass-gate-logic type
*******************************************************************/
static e_circuit_model_pass_gate_logic_type string_to_passgate_type(
const std::string& type_string) {
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);
}
}
return NUM_CIRCUIT_MODEL_PASS_GATE_TYPES;
}
/********************************************************************
* Convert string to the enumerate of multiplexer structure
*******************************************************************/
static e_circuit_model_structure string_to_mux_structure_type(
const std::string& type_string) {
for (size_t itype = 0; itype < NUM_CIRCUIT_MODEL_STRUCTURE_TYPES; ++itype) {
if (std::string(CIRCUIT_MODEL_STRUCTURE_TYPE_STRING[itype]) ==
type_string) {
return static_cast<e_circuit_model_structure>(itype);
}
}
return NUM_CIRCUIT_MODEL_STRUCTURE_TYPES;
}
/********************************************************************
* Convert string to the enumerate of logic gate type
*******************************************************************/
static e_circuit_model_gate_type string_to_gate_type(
const std::string& type_string) {
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);
}
}
return NUM_CIRCUIT_MODEL_GATE_TYPES;
}
/********************************************************************
* Convert string to the enumerate of circuit model port type
*******************************************************************/
static e_circuit_model_port_type string_to_circuit_model_port_type(
const std::string& type_string) {
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);
}
}
return NUM_CIRCUIT_MODEL_PORT_TYPES;
}
/********************************************************************
* Convert string to the enumerate of wire model type
*******************************************************************/
static e_wire_model_type string_to_wire_model_type(
const std::string& type_string) {
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);
}
}
return NUM_WIRE_MODEL_TYPES;
}
/********************************************************************
* Convert string to the enumerate of delay model type
*******************************************************************/
static e_circuit_model_delay_type string_to_circuit_model_delay_type(
const std::string& type_string) {
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);
}
}
return NUM_CIRCUIT_MODEL_DELAY_TYPES;
}
/********************************************************************
* Parse XML codes of design technology of a circuit model to circuit library
*******************************************************************/
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);
/* Identify if the circuit model power-gated */
circuit_lib.set_model_is_power_gated(
model, get_attribute(xml_design_tech, "power_gated", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Identify the type of design technology */
const char* type_attr =
get_attribute(xml_design_tech, "type", loc_data).value();
/* Translate the type of design technology to enumerate */
e_circuit_model_design_tech design_tech_type =
string_to_design_tech_type(std::string(type_attr));
if (NUM_CIRCUIT_MODEL_DESIGN_TECH_TYPES == design_tech_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
"Invalid 'type' attribute '%s'\n", type_attr);
}
circuit_lib.set_model_design_tech_type(model, design_tech_type);
/* Parse exclusive attributes for inverters and buffers */
if (CIRCUIT_MODEL_INVBUF == circuit_lib.model_type(model)) {
/* Identify the topology of the buffer */
const char* topology_attr =
get_attribute(xml_design_tech, "topology", loc_data).value();
/* Translate the type of buffer to enumerate */
e_circuit_model_buffer_type buf_type =
string_to_buffer_type(std::string(topology_attr));
if (NUM_CIRCUIT_MODEL_BUF_TYPES == buf_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
"Invalid 'topology' attribute '%s'\n", topology_attr);
}
circuit_lib.set_buffer_type(model, buf_type);
/* Parse the others options:
* 1. size of buffer in the first stage
* 2. number of levels
* 3. driving strength per stage
*/
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));
}
/* Parse exclusive attributes for pass-gate logics */
if (CIRCUIT_MODEL_PASSGATE == circuit_lib.model_type(model)) {
/* Identify the topology of the pass-gate logic */
const char* topology_attr =
get_attribute(xml_design_tech, "topology", loc_data).value();
/* Translate the type of pass-gate logic to enumerate */
e_circuit_model_pass_gate_logic_type passgate_type =
string_to_passgate_type(std::string(topology_attr));
if (NUM_CIRCUIT_MODEL_PASS_GATE_TYPES == passgate_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
"Invalid 'topology' attribute '%s'\n", topology_attr);
}
circuit_lib.set_pass_gate_logic_type(model, passgate_type);
/* 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
*/
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.));
}
/* Parse exclusive attributes for Look-Up Tables (LUTs) */
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
/* Identify if this is a fracturable LUT */
circuit_lib.set_lut_is_fracturable(
model, get_attribute(xml_design_tech, "fracturable_lut", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* 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 {
VTR_ASSERT_SAFE(CIRCUIT_MODEL_DESIGN_RRAM ==
circuit_lib.design_tech_type(model));
circuit_lib.set_mux_structure(model, CIRCUIT_MODEL_STRUCTURE_ONELEVEL);
}
/* Identify the topology of the multiplexer structure */
const char* structure_attr =
get_attribute(xml_design_tech, "structure", loc_data).value();
/* Translate the type of multiplexer structure to enumerate */
e_circuit_model_structure mux_structure =
string_to_mux_structure_type(std::string(structure_attr));
if (NUM_CIRCUIT_MODEL_STRUCTURE_TYPES == mux_structure) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
"Invalid 'structure' attribute '%s'\n", structure_attr);
}
circuit_lib.set_mux_structure(model, mux_structure);
/* Parse the others options:
* 1. constant input values
* 2. number of levels if multi-level multiplexer structure is selected
* 3. if advanced ReRAM design is used
* 4. if local encoder is to be used
*/
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));
}
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:
* 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);
}
}
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));
}
/* Parse exclusive attributes for logic gates */
if (CIRCUIT_MODEL_GATE == circuit_lib.model_type(model)) {
/* Identify the topology of the logic gate */
const char* topology_attr =
get_attribute(xml_design_tech, "topology", loc_data).value();
/* Translate the type of logic gate to enumerate */
e_circuit_model_gate_type gate_type =
string_to_gate_type(std::string(topology_attr));
if (NUM_CIRCUIT_MODEL_GATE_TYPES == gate_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_design_tech),
"Invalid 'topology' attribute '%s'\n", topology_attr);
}
circuit_lib.set_gate_type(model, gate_type);
}
/* Parse exclusive attributes for RRAM */
if (CIRCUIT_MODEL_DESIGN_RRAM == circuit_lib.design_tech_type(model)) {
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-07-13 21:35:10 -05:00
/********************************************************************
* Parse XML codes of device technology of a circuit model to circuit library
*******************************************************************/
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
if (!xml_device_tech) {
return;
}
2020-07-13 21:35:10 -05:00
/* Parse device model name */
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) {
circuit_lib.set_device_model_name(model,
std::string(device_model_name_attr));
2020-07-13 21:35:10 -05:00
}
}
/********************************************************************
* This is a generic function to parse XML codes that describe
* a buffer of a circuit model to circuit library
* This function will return a string with the circuit model name
* linked to the buffer
* If the return is empty, it means that buffer does NOT exist
*******************************************************************/
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);
std::string buffer_circuit_model_name("");
if (true == buffer_existence) {
buffer_circuit_model_name =
get_attribute(xml_buffer, "circuit_model_name", loc_data).as_string();
}
return buffer_circuit_model_name;
}
/********************************************************************
* 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
*******************************************************************/
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();
std::vector<size_t> mask_vector;
2020-01-16 17:05:11 -06:00
if (!output_mask_attr.empty()) {
/* Split the string with token ',' */
openfpga::StringToken string_tokenizer(
get_attribute(xml_port, "lut_output_mask", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_string(nullptr));
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),
"Invalid lut_output_mask attribute '%s'! It must match "
"the port size (=%lu)\n",
output_mask_attr.c_str(), circuit_lib.port_size(port));
}
} 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
*******************************************************************/
static void read_xml_circuit_port(pugi::xml_node& xml_port,
const pugiutil::loc_data& loc_data,
CircuitLibrary& circuit_lib,
const CircuitModelId& model) {
/* Find the type of the circuit port
* so that we can add a new circuit port to circuit library
*/
const char* type_attr = get_attribute(xml_port, "type", loc_data).value();
/* Translate the type of circuit model to enumerate */
e_circuit_model_port_type port_type =
string_to_circuit_model_port_type(std::string(type_attr));
if (NUM_CIRCUIT_MODEL_PORT_TYPES == port_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_port),
"Invalid 'type' attribute '%s'\n", type_attr);
}
CircuitPortId port = circuit_lib.add_model_port(model, port_type);
/* Parse the name of the port */
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);
if (nullptr != lib_name_attr) {
circuit_lib.set_port_lib_name(
port, get_attribute(xml_port, "lib_name", loc_data).as_string());
} else {
circuit_lib.set_port_lib_name(port, circuit_lib.port_prefix(port));
}
/* Parse the port size, by default it will be 1 */
circuit_lib.set_port_size(
port, get_attribute(xml_port, "size", loc_data).as_int(1));
/* Identify if the port is for io, this is only applicable to INPUT ports.
* By default, it will NOT be a mode selection port
*/
circuit_lib.set_port_is_io(
port, get_attribute(xml_port, "is_io", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Identify if the port is a data io, ONLY applicable to I/O port
* By default, it will NOT be a data io port
*/
if (true == circuit_lib.port_is_io(port)) {
circuit_lib.set_port_is_data_io(
port, get_attribute(xml_port, "is_data_io", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
}
/* 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
*/
if (CIRCUIT_MODEL_PORT_SRAM == circuit_lib.port_type(port)) {
circuit_lib.set_port_is_mode_select(
port, get_attribute(xml_port, "mode_select", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
}
/* Identify the default value of the port, by default it will be 0 */
circuit_lib.set_port_default_value(
port,
get_attribute(xml_port, "default_val", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_int(0));
/* Identify the tri-state map of the port, by default it will be nullptr
* This is only applicable to input ports of a LUT
*/
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();
if (nullptr != tri_state_map_attr) {
circuit_lib.set_port_tri_state_map(
port, get_attribute(xml_port, "tri_state_map", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_string());
}
}
/* 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
*/
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
*/
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
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));
}
/* 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
*/
if ((CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) &&
(CIRCUIT_MODEL_PORT_OUTPUT == circuit_lib.port_type(port))) {
read_xml_output_mask(xml_port, loc_data, circuit_lib, port);
}
/* Identify if the port is a global port, by default it is NOT */
circuit_lib.set_port_is_global(
port,
get_attribute(xml_port, "is_global", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Identify if the port is a reset port, by default it is NOT */
circuit_lib.set_port_is_reset(
port,
get_attribute(xml_port, "is_reset", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Identify if the port is a set port, by default it is NOT */
circuit_lib.set_port_is_set(port, get_attribute(xml_port, "is_set", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Identify if the port is in programming purpose, by default it is NOT */
circuit_lib.set_port_is_prog(
port,
get_attribute(xml_port, "is_prog", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Identify if the port is in shift register purpose, by default it is NOT */
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));
/* Find the name of circuit model that this port is linked to */
circuit_lib.set_port_tri_state_model_name(
port, get_attribute(xml_port, "circuit_model_name", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_string());
/* Find the name of circuit model that port is used for inversion of signals,
* This is only applicable to BL/WL/BLB/WLB ports
*/
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());
}
}
/********************************************************************
* This is a generic function to parse XML codes that describe
* RC parasitics for wire circuit model to circuit library
*******************************************************************/
static void read_xml_wire_param(pugi::xml_node& xml_wire_param,
const pugiutil::loc_data& loc_data,
CircuitLibrary& circuit_lib,
const CircuitModelId& model) {
/* Find the type of the wire model */
const char* type_attr =
get_attribute(xml_wire_param, "model_type", loc_data).value();
/* Translate the type of circuit model to enumerate */
e_wire_model_type wire_model_type =
string_to_wire_model_type(std::string(type_attr));
if (NUM_WIRE_MODEL_TYPES == wire_model_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_wire_param),
"Invalid 'type' attribute '%s'\n", type_attr);
}
circuit_lib.set_wire_type(model, wire_model_type);
/* Parse the R and C values */
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.));
/* Parse the number of levels for the wire model */
circuit_lib.set_wire_num_level(
model, get_attribute(xml_wire_param, "num_level", loc_data).as_int(0));
}
/********************************************************************
* This is a generic function to parse XML codes that describe
* a delay matrix for a circuit model to circuit library
*******************************************************************/
static void read_xml_delay_matrix(pugi::xml_node& xml_delay_matrix,
const pugiutil::loc_data& loc_data,
CircuitLibrary& circuit_lib,
const CircuitModelId& model) {
/* Find the type of the delay model, so that we can add to circuit library */
const char* type_attr =
get_attribute(xml_delay_matrix, "type", loc_data).value();
/* Translate the type of delay matrix for a circuit model to enumerate */
e_circuit_model_delay_type delay_type =
string_to_circuit_model_delay_type(std::string(type_attr));
if (NUM_CIRCUIT_MODEL_DELAY_TYPES == delay_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_delay_matrix),
"Invalid 'type' attribute '%s'\n", type_attr);
}
circuit_lib.add_delay_info(model, delay_type);
/* Parse the input ports */
circuit_lib.set_delay_in_port_names(
model, delay_type,
get_attribute(xml_delay_matrix, "in_port", loc_data).as_string());
/* Parse the output ports */
circuit_lib.set_delay_out_port_names(
model, delay_type,
get_attribute(xml_delay_matrix, "out_port", loc_data).as_string());
/* Parse the delay values */
circuit_lib.set_delay_values(model, delay_type,
std::string(xml_delay_matrix.child_value()));
}
/********************************************************************
* Parse XML codes of a circuit model to circuit library
*******************************************************************/
static void read_xml_circuit_model(pugi::xml_node& xml_model,
const pugiutil::loc_data& loc_data,
CircuitLibrary& circuit_lib) {
/* Find the type of the circuit model
* so that we can add a new circuit model to circuit library
*/
const char* type_attr = get_attribute(xml_model, "type", loc_data).value();
/* Translate the type of circuit model to enumerate */
e_circuit_model_type model_type =
string_to_circuit_model_type(std::string(type_attr));
if (NUM_CIRCUIT_MODEL_TYPES == model_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_model),
"Invalid 'type' attribute '%s'\n", type_attr);
}
CircuitModelId model = circuit_lib.add_model(model_type);
/* Find the name of the circuit model */
const char* name_attr = get_attribute(xml_model, "name", loc_data).value();
circuit_lib.set_model_name(model, std::string(name_attr));
/* TODO: This attribute is going to be DEPRECATED
* Find the prefix of the circuit model
*/
const char* prefix_attr =
get_attribute(xml_model, "prefix", loc_data).value();
circuit_lib.set_model_prefix(model, std::string(prefix_attr));
/* Find a SPICE netlist which is an optional attribute*/
circuit_lib.set_model_spice_netlist(
model, get_attribute(xml_model, "spice_netlist", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_string(""));
/* Find a Verilog netlist which is an optional attribute*/
circuit_lib.set_model_verilog_netlist(
model, get_attribute(xml_model, "verilog_netlist", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_string(""));
/* Find if the circuit model is default in its type */
circuit_lib.set_model_is_default(
model,
get_attribute(xml_model, "is_default", loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Find if the circuit model is should be dumped in structural verilog */
circuit_lib.set_model_dump_structural_verilog(
model, get_attribute(xml_model, "dump_structural_verilog", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_bool(false));
/* Parse attributes under the <circuit_model> */
/* Design technology -related attributes */
read_xml_model_design_technology(xml_model, loc_data, circuit_lib, model);
/* Parse special buffer attributes required by LUTs only */
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
/* Input buffer of LUTs */
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);
/* Input inverter of LUTs */
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);
/* Intermediate buffer of LUTs */
auto xml_intermediate_buffer =
get_single_child(xml_model, "lut_intermediate_buffer", loc_data,
pugiutil::ReqOpt::OPTIONAL);
if (xml_intermediate_buffer) {
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);
/* If intermediate buffer is defined, try to find the location map */
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-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
*/
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
}
/* Input buffer attributes, NOT required for circuit models which are
* inverters or buffers */
if (CIRCUIT_MODEL_INVBUF != circuit_lib.model_type(model)) {
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);
}
/* Output buffer attributes, NOT required for circuit models which are
* inverters or buffers */
if (CIRCUIT_MODEL_INVBUF != circuit_lib.model_type(model)) {
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);
}
/* Pass-gate-logic attributes, required by LUT and MUX */
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());
}
/* Parse all the ports belonging to this circuit model
* We count the number of ports in total and then add one by one
*/
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());
}
}
/* Parse the parasitics of wires */
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);
read_xml_wire_param(xml_wire_param, loc_data, circuit_lib, model);
}
/* Parse all the delay matrix if defined */
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) {
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());
}
}
}
/********************************************************************
* 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) {
CircuitLibrary circuit_lib;
2020-01-14 09:33:48 -06:00
/* Iterate over the children under this node,
* each child should be named after circuit_model
*/
for (pugi::xml_node xml_model : Node.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_model.name() != std::string("circuit_model")) {
bad_tag(xml_model, loc_data, Node, {"circuit_model"});
}
read_xml_circuit_model(xml_model, loc_data, circuit_lib);
}
return circuit_lib;
}