Merge branch 'refactoring' into dev
This commit is contained in:
commit
4c5917ac97
|
@ -253,11 +253,42 @@
|
|||
<port type="output" prefix="sumout" size="1"/>
|
||||
</circuit_model>
|
||||
</circuit_library>
|
||||
<configuration_protocol>
|
||||
<organization type="scan_chain" circuit_model_name="sc_dff_compact"/>
|
||||
</configuration_protocol>
|
||||
<connection_block>
|
||||
<switch name="cb_mux" circuit_model_name="mux_2level_tapbuf"/>
|
||||
</connection_block>
|
||||
<switch_block>
|
||||
<switch name="sb_mux_L4" circuit_model_name="mux_2level_tapbuf"/>
|
||||
</switch_block>
|
||||
<routing_segment>
|
||||
<segment name="L4" circuit_model_name="chan_segment"/>
|
||||
</routing_segment>
|
||||
<!--direct_connection>
|
||||
<direct name="adder" circuit_model_name="direct_interc"/>
|
||||
</direct_connection-->
|
||||
<complex_blocks>
|
||||
<pb_type name="io" idle_mode_name="inpad" physical_mode_name="io_phy"/>
|
||||
<mode name="io[io_phy]" disable_in_packing="true"/>
|
||||
<pb_type name="io[io_phy].iopad" circuit_model_name="iopad" mode_bits="1"/>
|
||||
<pb_type name="io[io_phy].inpad" physical_pb_type_name="iopad" mode_bits="1"/>
|
||||
<pb_type name="io[io_phy].outpad" physical_pb_type_name="iopad" mode_bits="0"/>
|
||||
</complex_blocks>
|
||||
</openfpga_architecture>
|
||||
<openfpga_simulation_setting>
|
||||
<general sim_temp="25" post="false" captab="false" fast="true"/>
|
||||
<monte_carlo mc_sim="false" num_mc_points="2"/>
|
||||
<measure sim_num_clock_cycle="auto" accuracy="1e-13" accuracy_type="abs">
|
||||
<clock_setting>
|
||||
<operating frequency="200e6" num_cycles="auto" slack="0.2"/>
|
||||
<programming frequency="10e6"/>
|
||||
</clock_setting>
|
||||
<simulator_option>
|
||||
<operating_condition temperature="25"/>
|
||||
<output_log verbose="false" captab="false"/>
|
||||
<accuracy type="abs" value="1e-13"/>
|
||||
<runtime fast_simulation="true"/>
|
||||
</simulator_option>
|
||||
<monte_carlo num_simulation_points="2"/>
|
||||
<measurement_setting>
|
||||
<slew>
|
||||
<rise upper_thres_pct="0.95" lower_thres_pct="0.05"/>
|
||||
<fall upper_thres_pct="0.05" lower_thres_pct="0.95"/>
|
||||
|
@ -266,15 +297,15 @@
|
|||
<rise input_thres_pct="0.5" output_thres_pct="0.5"/>
|
||||
<fall input_thres_pct="0.5" output_thres_pct="0.5"/>
|
||||
</delay>
|
||||
</measure>
|
||||
<stimuli>
|
||||
<clock op_freq="200e6" sim_slack="0.2" prog_freq="10e6">
|
||||
<rise slew_time="20e-12" slew_type="abs"/>
|
||||
<fall slew_time="20e-12" slew_type="abs"/>
|
||||
</measurement_setting>
|
||||
<stimulus>
|
||||
<clock>
|
||||
<rise slew_type="abs" slew_time="20e-12" />
|
||||
<fall slew_type="abs" slew_time="20e-12" />
|
||||
</clock>
|
||||
<input>
|
||||
<rise slew_time="25e-12" slew_type="abs"/>
|
||||
<fall slew_time="25e-12" slew_type="abs"/>
|
||||
<rise slew_type="abs" slew_time="25e-12" />
|
||||
<fall slew_type="abs" slew_time="25e-12" />
|
||||
</input>
|
||||
</stimuli>
|
||||
</stimulus>
|
||||
</openfpga_simulation_setting>
|
||||
|
|
|
@ -1357,7 +1357,7 @@ CircuitPortId CircuitLibrary::add_model_port(const CircuitModelId& model_id,
|
|||
port_tri_state_maps_.emplace_back();
|
||||
port_lut_frac_level_.push_back(-1);
|
||||
port_lut_output_masks_.emplace_back();
|
||||
port_sram_orgz_.push_back(NUM_CIRCUIT_MODEL_SRAM_ORGZ_TYPES);
|
||||
port_sram_orgz_.push_back(NUM_CONFIG_PROTOCOL_TYPES);
|
||||
|
||||
/* For timing graphs */
|
||||
port_in_edge_ids_.emplace_back();
|
||||
|
@ -1537,7 +1537,7 @@ void CircuitLibrary::set_port_lut_output_mask(const CircuitPortId& circuit_port_
|
|||
|
||||
/* Set the SRAM organization for a port of a circuit model, only applicable to SRAM ports */
|
||||
void CircuitLibrary::set_port_sram_orgz(const CircuitPortId& circuit_port_id,
|
||||
const enum e_sram_orgz& sram_orgz) {
|
||||
const enum e_config_protocol_type& sram_orgz) {
|
||||
/* validate the circuit_port_id */
|
||||
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||
/* Make sure this is a SRAM port */
|
||||
|
|
|
@ -373,7 +373,7 @@ class CircuitLibrary {
|
|||
void set_port_lut_output_mask(const CircuitPortId& circuit_port_id,
|
||||
const std::vector<size_t>& lut_output_masks);
|
||||
void set_port_sram_orgz(const CircuitPortId& circuit_port_id,
|
||||
const enum e_sram_orgz& sram_orgz);
|
||||
const enum e_config_protocol_type& sram_orgz);
|
||||
/* Delay information */
|
||||
void add_delay_info(const CircuitModelId& model_id,
|
||||
const enum e_circuit_model_delay_type& delay_type);
|
||||
|
@ -542,7 +542,7 @@ class CircuitLibrary {
|
|||
vtr::vector<CircuitPortId, std::string> port_tri_state_maps_;
|
||||
vtr::vector<CircuitPortId, size_t> port_lut_frac_level_;
|
||||
vtr::vector<CircuitPortId, std::vector<size_t>> port_lut_output_masks_;
|
||||
vtr::vector<CircuitPortId, enum e_sram_orgz> port_sram_orgz_;
|
||||
vtr::vector<CircuitPortId, enum e_config_protocol_type> port_sram_orgz_;
|
||||
|
||||
/* Timing graphs */
|
||||
vtr::vector<CircuitEdgeId, CircuitEdgeId> edge_ids_;
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#ifndef CIRCUIT_TYPES_H
|
||||
#define CIRCUIT_TYPES_H
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
/************************************************************************
|
||||
* This file includes basic enumeration types for circuit models
|
||||
***********************************************************************/
|
||||
|
@ -111,15 +114,21 @@ enum e_circuit_model_delay_type {
|
|||
/* Strings correspond to each delay type */
|
||||
constexpr std::array<const char*, NUM_CIRCUIT_MODEL_DELAY_TYPES> CIRCUIT_MODEL_DELAY_TYPE_STRING = {{"rise", "fall"}};
|
||||
|
||||
/* For SRAM */
|
||||
enum e_sram_orgz {
|
||||
CIRCUIT_SRAM_STANDALONE, /* SRAMs are organized and accessed as standalone elements */
|
||||
CIRCUIT_SRAM_SCAN_CHAIN, /* SRAMs are organized and accessed by a scan-chain */
|
||||
CIRCUIT_SRAM_MEMORY_BANK, /* SRAMs are organized and accessed by memory bank */
|
||||
CIRCUIT_SRAM_LOCAL_ENCODER, /* SRAMs are organized and accessed by a local encoder */
|
||||
NUM_CIRCUIT_MODEL_SRAM_ORGZ_TYPES
|
||||
/********************************************************************
|
||||
* Types of configuration protocol
|
||||
* 1. configurable memories are organized and accessed as standalone elements
|
||||
* 2. configurable memories are organized and accessed by a scan-chain
|
||||
* 3. configurable memories are organized and accessed by memory bank
|
||||
* 4. configurable memories are organized and accessed by a local encoder
|
||||
*/
|
||||
enum e_config_protocol_type {
|
||||
CONFIG_MEM_STANDALONE,
|
||||
CONFIG_MEM_SCAN_CHAIN,
|
||||
CONFIG_MEM_MEMORY_BANK,
|
||||
CONFIG_MEM_LOCAL_ENCODER,
|
||||
NUM_CONFIG_PROTOCOL_TYPES
|
||||
};
|
||||
|
||||
constexpr std::array<const char*, NUM_CIRCUIT_MODEL_SRAM_ORGZ_TYPES> CIRCUIT_MODEL_SRAM_ORGZ_TYPE_STRING = {{"standalone", "scan_chain", "memory_bank", "local_encoder"}};
|
||||
constexpr std::array<const char*, NUM_CONFIG_PROTOCOL_TYPES> CONFIG_PROTOCOL_TYPE_STRING = {{"standalone", "scan_chain", "memory_bank", "local_encoder"}};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#include "vtr_assert.h"
|
||||
|
||||
#include "config_protocol.h"
|
||||
|
||||
/************************************************************************
|
||||
* Member functions for class ConfigProtocol
|
||||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Constructors
|
||||
***********************************************************************/
|
||||
ConfigProtocol::ConfigProtocol() {
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Accessors
|
||||
***********************************************************************/
|
||||
e_config_protocol_type ConfigProtocol::type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
std::string ConfigProtocol::memory_model_name() const {
|
||||
return memory_model_name_;
|
||||
}
|
||||
|
||||
CircuitModelId ConfigProtocol::memory_model() const {
|
||||
return memory_model_;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Mutators
|
||||
***********************************************************************/
|
||||
void ConfigProtocol::set_type(const e_config_protocol_type& type) {
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_memory_model_name(const std::string& memory_model_name) {
|
||||
memory_model_name_ = memory_model_name;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_memory_model(const CircuitModelId& memory_model) {
|
||||
memory_model_ = memory_model;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef CONFIG_PROTOCOL_H
|
||||
#define CONFIG_PROTOCOL_H
|
||||
|
||||
#include <string>
|
||||
#include "circuit_types.h"
|
||||
#include "circuit_library_fwd.h"
|
||||
|
||||
/********************************************************************
|
||||
* A data structure to store configuration protocol information
|
||||
*******************************************************************/
|
||||
class ConfigProtocol {
|
||||
public: /* Constructors */
|
||||
ConfigProtocol();
|
||||
public: /* Public Accessors */
|
||||
e_config_protocol_type type() const;
|
||||
std::string memory_model_name() const;
|
||||
CircuitModelId memory_model() const;
|
||||
public: /* Public Mutators */
|
||||
void set_type(const e_config_protocol_type& type);
|
||||
void set_memory_model_name(const std::string& memory_model_name);
|
||||
void set_memory_model(const CircuitModelId& memory_model);
|
||||
private: /* Internal data */
|
||||
/* The type of configuration protocol.
|
||||
* In other words, it is about how to organize and access each configurable memory
|
||||
*/
|
||||
e_config_protocol_type type_;
|
||||
|
||||
/* The circuit model of configuration memory to be used in the protocol */
|
||||
std::string memory_model_name_;
|
||||
CircuitModelId memory_model_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,18 +1,52 @@
|
|||
#ifndef OPENFPGA_ARCH_H
|
||||
#define OPENFPGA_ARCH_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "circuit_library.h"
|
||||
#include "technology_library.h"
|
||||
#include "simulation_setting.h"
|
||||
#include "config_protocol.h"
|
||||
|
||||
/* namespace openfpga begins */
|
||||
namespace openfpga {
|
||||
|
||||
/* A unified data structure to store circuit-level settings,
|
||||
* including circuit library, technology library and simulation parameters
|
||||
*
|
||||
* Note:
|
||||
* Once this struct is built by function read_xml_openfpga_arch()
|
||||
* It should be READ-ONLY! Any modification should not be applied later
|
||||
* This is to keep everything well modularized
|
||||
*/
|
||||
struct Arch {
|
||||
/* Circuit models */
|
||||
CircuitLibrary circuit_lib;
|
||||
|
||||
/* Technology devices */
|
||||
TechnologyLibrary tech_lib;
|
||||
|
||||
/* Simulation settings */
|
||||
SimulationSetting sim_setting;
|
||||
|
||||
/* Configuration protocol settings */
|
||||
ConfigProtocol config_protocol;
|
||||
|
||||
/* Mapping from the names of routing switches
|
||||
* to circuit models in circuit library
|
||||
*/
|
||||
std::map<std::string, CircuitModelId> cb_switch2circuit;
|
||||
std::map<std::string, CircuitModelId> sb_switch2circuit;
|
||||
|
||||
/* Mapping from the names of routing segments
|
||||
* to circuit models in circuit library
|
||||
*/
|
||||
std::map<std::string, CircuitModelId> routing_seg2circuit;
|
||||
|
||||
/* Mapping from the names of direct connection
|
||||
* to circuit models in circuit library
|
||||
*/
|
||||
std::map<std::string, CircuitModelId> direct2circuit;
|
||||
};
|
||||
|
||||
} /* namespace openfpga ends */
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/********************************************************************
|
||||
* This file includes the functions that build links between
|
||||
* data structures inside the openfpga arch data structure
|
||||
*******************************************************************/
|
||||
#include "vtr_log.h"
|
||||
#include "openfpga_arch_linker.h"
|
||||
|
||||
/********************************************************************
|
||||
* Link the circuit model inside configuration protocol
|
||||
* to these circuit models defined in circuit library
|
||||
*******************************************************************/
|
||||
void link_config_protocol_to_circuit_library(openfpga::Arch& openfpga_arch) {
|
||||
CircuitModelId config_memory_model = openfpga_arch.circuit_lib.model(openfpga_arch.config_protocol.memory_model_name());
|
||||
|
||||
/* Error out if the circuit model id is invalid */
|
||||
if (CircuitModelId::INVALID() == config_memory_model) {
|
||||
VTR_LOG("Invalid memory model name (=%s) defined in <configuration_protocol>!",
|
||||
openfpga_arch.config_protocol.memory_model_name().c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
openfpga_arch.config_protocol.set_memory_model(config_memory_model);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef OPENFPGA_ARCH_LINKER_H
|
||||
#define OPENFPGA_ARCH_LINKER_H
|
||||
|
||||
#include "openfpga_arch.h"
|
||||
|
||||
void link_config_protocol_to_circuit_library(openfpga::Arch& openfpga_arch);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,84 @@
|
|||
/********************************************************************
|
||||
* 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"
|
||||
|
||||
#include "read_xml_config_protocol.h"
|
||||
|
||||
/********************************************************************
|
||||
* Convert string to the enumerate of configuration protocol type
|
||||
*******************************************************************/
|
||||
static
|
||||
e_config_protocol_type string_to_config_protocol_type(const std::string& type_string) {
|
||||
if (std::string("standalone") == type_string) {
|
||||
return CONFIG_MEM_STANDALONE;
|
||||
}
|
||||
|
||||
if (std::string("scan_chain") == type_string) {
|
||||
return CONFIG_MEM_SCAN_CHAIN;
|
||||
}
|
||||
|
||||
if (std::string("memory_bank") == type_string) {
|
||||
return CONFIG_MEM_MEMORY_BANK;
|
||||
}
|
||||
|
||||
if (std::string("local_encoder") == type_string) {
|
||||
return CONFIG_MEM_LOCAL_ENCODER;
|
||||
}
|
||||
|
||||
return NUM_CONFIG_PROTOCOL_TYPES;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <organization> to an object of configuration protocol
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_config_organization(pugi::xml_node& xml_config_orgz,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
ConfigProtocol& config_protocol) {
|
||||
/* Find the type of configuration protocol */
|
||||
const char* type_attr = get_attribute(xml_config_orgz, "type", loc_data).value();
|
||||
/* Translate the type of design technology to enumerate */
|
||||
e_config_protocol_type config_orgz_type = string_to_config_protocol_type(std::string(type_attr));
|
||||
|
||||
if (NUM_CONFIG_PROTOCOL_TYPES == config_orgz_type) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_config_orgz),
|
||||
"Invalid 'type' attribute '%s'\n",
|
||||
type_attr);
|
||||
}
|
||||
|
||||
config_protocol.set_type(config_orgz_type);
|
||||
|
||||
config_protocol.set_memory_model_name(get_attribute(xml_config_orgz, "circuit_model_name", loc_data).as_string());
|
||||
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes about <configuration_protocol> to an object of ConfigProtocol
|
||||
*******************************************************************/
|
||||
ConfigProtocol read_xml_config_protocol(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data) {
|
||||
ConfigProtocol config_protocol;
|
||||
|
||||
/* Parse configuration protocol root node */
|
||||
pugi::xml_node xml_config = get_single_child(Node, "configuration_protocol", loc_data);
|
||||
|
||||
pugi::xml_node xml_config_orgz = get_single_child(xml_config, "organization", loc_data);
|
||||
read_xml_config_organization(xml_config_orgz, loc_data, config_protocol);
|
||||
|
||||
return config_protocol;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef READ_XML_CONFIG_PROTOCOL_H
|
||||
#define READ_XML_CONFIG_PROTOCOL_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "pugixml_util.hpp"
|
||||
#include "pugixml.hpp"
|
||||
#include "config_protocol.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
ConfigProtocol read_xml_config_protocol(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data);
|
||||
|
||||
#endif
|
|
@ -15,7 +15,11 @@
|
|||
|
||||
#include "read_xml_technology_library.h"
|
||||
#include "read_xml_circuit_library.h"
|
||||
#include "read_xml_simulation_setting.h"
|
||||
#include "read_xml_config_protocol.h"
|
||||
#include "read_xml_routing_circuit.h"
|
||||
#include "read_xml_openfpga_arch.h"
|
||||
#include "openfpga_arch_linker.h"
|
||||
|
||||
/********************************************************************
|
||||
* Top-level function to parse an XML file and load data to :
|
||||
|
@ -54,10 +58,37 @@ openfpga::Arch read_xml_openfpga_arch(const char* arch_file_name) {
|
|||
/* Build the internal link for technology library */
|
||||
openfpga_arch.tech_lib.link_models_to_variations();
|
||||
|
||||
/* Parse configuration protocol to data structure */
|
||||
openfpga_arch.config_protocol = read_xml_config_protocol(xml_openfpga_arch, loc_data);
|
||||
|
||||
/* Build the internal link between configuration protocol and circuit library */
|
||||
link_config_protocol_to_circuit_library(openfpga_arch);
|
||||
|
||||
/* Parse the connection block circuit definition */
|
||||
openfpga_arch.cb_switch2circuit = read_xml_cb_switch_circuit(xml_openfpga_arch, loc_data,
|
||||
openfpga_arch.circuit_lib);
|
||||
|
||||
/* Parse the connection block circuit definition */
|
||||
openfpga_arch.cb_switch2circuit = read_xml_cb_switch_circuit(xml_openfpga_arch, loc_data,
|
||||
openfpga_arch.circuit_lib);
|
||||
|
||||
/* Parse the switch block circuit definition */
|
||||
openfpga_arch.sb_switch2circuit = read_xml_sb_switch_circuit(xml_openfpga_arch, loc_data,
|
||||
openfpga_arch.circuit_lib);
|
||||
|
||||
/* Parse the routing segment circuit definition */
|
||||
openfpga_arch.routing_seg2circuit = read_xml_routing_segment_circuit(xml_openfpga_arch, loc_data,
|
||||
openfpga_arch.circuit_lib);
|
||||
|
||||
/* Parse the routing segment circuit definition */
|
||||
openfpga_arch.direct2circuit = read_xml_direct_circuit(xml_openfpga_arch, loc_data,
|
||||
openfpga_arch.circuit_lib);
|
||||
|
||||
/* Second node should be <openfpga_simulation_setting> */
|
||||
auto xml_simulation_settings = get_single_child(doc, "openfpga_simulation_setting", loc_data);
|
||||
|
||||
/* Parse simulation settings to data structure */
|
||||
openfpga_arch.sim_setting = read_xml_simulation_setting(xml_simulation_settings, loc_data);
|
||||
|
||||
} catch (pugiutil::XmlError& e) {
|
||||
archfpga_throw(arch_file_name, e.line(),
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
/********************************************************************
|
||||
* 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"
|
||||
|
||||
#include "read_xml_routing_circuit.h"
|
||||
|
||||
/********************************************************************
|
||||
* Find the circuit model id for a routing switch as defined in XML
|
||||
*******************************************************************/
|
||||
static
|
||||
CircuitModelId find_routing_circuit_model(pugi::xml_node& xml_switch,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::string& switch_model_name,
|
||||
const e_circuit_model_type& expected_circuit_model_type) {
|
||||
/* Find the circuit model id in circuit library */
|
||||
CircuitModelId switch_model = circuit_lib.model(switch_model_name);
|
||||
/* Ensure we have a valid circuit model id! */
|
||||
if (CircuitModelId::INVALID() == switch_model) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch),
|
||||
"Invalid circuit model name '%s'! Unable to find it in circuit library\n",
|
||||
switch_model_name.c_str());
|
||||
}
|
||||
/* Check the type of switch model, it must be a specific type!!!
|
||||
* For CB/SB switches, the type must be a multiplexer
|
||||
* For routing segments, the type must be a channel wire
|
||||
* TODO: decide where to put these checking codes
|
||||
* This can be done here or in the function check_arch()
|
||||
*/
|
||||
if (expected_circuit_model_type != circuit_lib.model_type(switch_model)) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch),
|
||||
"Circuit model '%s' must be a type of '%s'\n",
|
||||
switch_model_name.c_str(), CIRCUIT_MODEL_TYPE_STRING[expected_circuit_model_type]);
|
||||
}
|
||||
|
||||
return switch_model;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes about <connection_block> to an object of name-to-circuit mapping
|
||||
* Note: this function should be called AFTER the parsing of circuit library!!!
|
||||
*******************************************************************/
|
||||
std::map<std::string, CircuitModelId> read_xml_cb_switch_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
std::map<std::string, CircuitModelId> cb_switch2circuit;
|
||||
|
||||
/* Parse cb switch list */
|
||||
pugi::xml_node xml_cb_switch = get_single_child(Node, "connection_block", loc_data);
|
||||
|
||||
/* Iterate over the children under this node,
|
||||
* each child should be named after switch
|
||||
*/
|
||||
for (pugi::xml_node xml_switch : xml_cb_switch.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_switch.name() != std::string("switch")) {
|
||||
bad_tag(xml_switch, loc_data, xml_cb_switch, {"switch"});
|
||||
}
|
||||
/* Get the switch name */
|
||||
std::string switch_name = get_attribute(xml_switch, "name", loc_data).as_string();
|
||||
|
||||
/* Get the switch circuit model name */
|
||||
std::string switch_model_name = get_attribute(xml_switch, "circuit_model_name", loc_data).as_string();
|
||||
|
||||
CircuitModelId switch_model = find_routing_circuit_model(xml_switch, loc_data,
|
||||
circuit_lib, switch_model_name,
|
||||
CIRCUIT_MODEL_MUX);
|
||||
|
||||
/* Ensure that there is no duplicated switch names defined here */
|
||||
std::map<std::string, CircuitModelId>::const_iterator it = cb_switch2circuit.find(switch_name);
|
||||
if (it != cb_switch2circuit.end()) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch),
|
||||
"Switch name '%s' has been defined more than once!\n",
|
||||
switch_name.c_str());
|
||||
}
|
||||
|
||||
/* Pass all the check, we can add it to the map */
|
||||
cb_switch2circuit[switch_name] = switch_model;
|
||||
}
|
||||
|
||||
return cb_switch2circuit;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes about <switch_block> to an object of name-to-circuit mapping
|
||||
* Note: this function should be called AFTER the parsing of circuit library!!!
|
||||
*******************************************************************/
|
||||
std::map<std::string, CircuitModelId> read_xml_sb_switch_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
std::map<std::string, CircuitModelId> sb_switch2circuit;
|
||||
|
||||
/* Parse cb switch list */
|
||||
pugi::xml_node xml_sb_switch = get_single_child(Node, "switch_block", loc_data);
|
||||
|
||||
/* Iterate over the children under this node,
|
||||
* each child should be named after switch
|
||||
*/
|
||||
for (pugi::xml_node xml_switch : xml_sb_switch.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_switch.name() != std::string("switch")) {
|
||||
bad_tag(xml_switch, loc_data, xml_sb_switch, {"switch"});
|
||||
}
|
||||
/* Get the switch name */
|
||||
std::string switch_name = get_attribute(xml_switch, "name", loc_data).as_string();
|
||||
|
||||
/* Get the switch circuit model name */
|
||||
std::string switch_model_name = get_attribute(xml_switch, "circuit_model_name", loc_data).as_string();
|
||||
|
||||
CircuitModelId switch_model = find_routing_circuit_model(xml_switch, loc_data,
|
||||
circuit_lib, switch_model_name,
|
||||
CIRCUIT_MODEL_MUX);
|
||||
|
||||
/* Ensure that there is no duplicated switch names defined here */
|
||||
std::map<std::string, CircuitModelId>::const_iterator it = sb_switch2circuit.find(switch_name);
|
||||
if (it != sb_switch2circuit.end()) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch),
|
||||
"Switch name '%s' has been defined more than once!\n",
|
||||
switch_name.c_str());
|
||||
}
|
||||
|
||||
/* Pass all the check, we can add it to the map */
|
||||
sb_switch2circuit[switch_name] = switch_model;
|
||||
}
|
||||
|
||||
return sb_switch2circuit;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes about <routing_segment> to an object of name-to-circuit mapping
|
||||
* Note: this function should be called AFTER the parsing of circuit library!!!
|
||||
*******************************************************************/
|
||||
std::map<std::string, CircuitModelId> read_xml_routing_segment_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
std::map<std::string, CircuitModelId> seg2circuit;
|
||||
|
||||
/* Parse cb switch list */
|
||||
pugi::xml_node xml_segments= get_single_child(Node, "routing_segment", loc_data);
|
||||
|
||||
/* Iterate over the children under this node,
|
||||
* each child should be named after switch
|
||||
*/
|
||||
for (pugi::xml_node xml_seg : xml_segments.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_seg.name() != std::string("segment")) {
|
||||
bad_tag(xml_seg, loc_data, xml_segments, {"segment"});
|
||||
}
|
||||
/* Get the switch name */
|
||||
std::string seg_name = get_attribute(xml_seg, "name", loc_data).as_string();
|
||||
|
||||
/* Get the routing segment circuit model name */
|
||||
std::string seg_model_name = get_attribute(xml_seg, "circuit_model_name", loc_data).as_string();
|
||||
|
||||
CircuitModelId seg_model = find_routing_circuit_model(xml_seg, loc_data,
|
||||
circuit_lib, seg_model_name,
|
||||
CIRCUIT_MODEL_CHAN_WIRE);
|
||||
|
||||
/* Ensure that there is no duplicated seg names defined here */
|
||||
std::map<std::string, CircuitModelId>::const_iterator it = seg2circuit.find(seg_name);
|
||||
if (it != seg2circuit.end()) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_seg),
|
||||
"Segment name '%s' has been defined more than once!\n",
|
||||
seg_name.c_str());
|
||||
}
|
||||
|
||||
/* Pass all the check, we can add it to the map */
|
||||
seg2circuit[seg_name] = seg_model;
|
||||
}
|
||||
|
||||
return seg2circuit;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes about <direct_connection> to an object of name-to-circuit mapping
|
||||
* Note: this function should be called AFTER the parsing of circuit library!!!
|
||||
*******************************************************************/
|
||||
std::map<std::string, CircuitModelId> read_xml_direct_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
std::map<std::string, CircuitModelId> direct2circuit;
|
||||
|
||||
/* Parse direct list, this is optional. May not be used */
|
||||
pugi::xml_node xml_directs= get_single_child(Node, "direct_connection", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
/* Not found, we can return */
|
||||
if (!xml_directs) {
|
||||
return direct2circuit;
|
||||
}
|
||||
|
||||
/* Iterate over the children under this node,
|
||||
* each child should be named after switch
|
||||
*/
|
||||
for (pugi::xml_node xml_direct : xml_directs.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_direct.name() != std::string("direct")) {
|
||||
bad_tag(xml_direct, loc_data, xml_directs, {"direct"});
|
||||
}
|
||||
/* Get the switch name */
|
||||
std::string direct_name = get_attribute(xml_direct, "name", loc_data).as_string();
|
||||
|
||||
/* Get the routing segment circuit model name */
|
||||
std::string direct_model_name = get_attribute(xml_direct, "circuit_model_name", loc_data).as_string();
|
||||
|
||||
CircuitModelId direct_model = find_routing_circuit_model(xml_direct, loc_data,
|
||||
circuit_lib, direct_model_name,
|
||||
CIRCUIT_MODEL_WIRE);
|
||||
|
||||
/* Ensure that there is no duplicated seg names defined here */
|
||||
std::map<std::string, CircuitModelId>::const_iterator it = direct2circuit.find(direct_name);
|
||||
if (it != direct2circuit.end()) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_direct),
|
||||
"Direct name '%s' has been defined more than once!\n",
|
||||
direct_name.c_str());
|
||||
}
|
||||
|
||||
/* Pass all the check, we can add it to the map */
|
||||
direct2circuit[direct_name] = direct_model;
|
||||
}
|
||||
|
||||
return direct2circuit;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef READ_XML_ROUTING_CIRCUIT_H
|
||||
#define READ_XML_ROUTING_CIRCUIT_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "pugixml_util.hpp"
|
||||
#include "pugixml.hpp"
|
||||
#include "circuit_library.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
std::map<std::string, CircuitModelId> read_xml_cb_switch_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
std::map<std::string, CircuitModelId> read_xml_sb_switch_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
std::map<std::string, CircuitModelId> read_xml_routing_segment_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
std::map<std::string, CircuitModelId> read_xml_direct_circuit(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,270 @@
|
|||
/********************************************************************
|
||||
* 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"
|
||||
|
||||
#include "read_xml_simulation_setting.h"
|
||||
|
||||
/********************************************************************
|
||||
* Convert string to the enumerate of simulation accuracy type
|
||||
*******************************************************************/
|
||||
static
|
||||
e_sim_accuracy_type string_to_sim_accuracy_type(const std::string& type_string) {
|
||||
if (std::string("frac") == type_string) {
|
||||
return SIM_ACCURACY_FRAC;
|
||||
}
|
||||
|
||||
if (std::string("abs") == type_string) {
|
||||
return SIM_ACCURACY_ABS;
|
||||
}
|
||||
|
||||
return NUM_SIM_ACCURACY_TYPES;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <clock_setting> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_clock_setting(pugi::xml_node& xml_clock_setting,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
SimulationSetting& sim_setting) {
|
||||
/* Parse operating clock setting */
|
||||
pugi::xml_node xml_operating_clock_setting = get_single_child(xml_clock_setting, "operating", loc_data);
|
||||
|
||||
sim_setting.set_operating_clock_frequency(get_attribute(xml_operating_clock_setting, "frequency", loc_data).as_float(0.));
|
||||
|
||||
/* Parse number of clock cycles to be used in simulation
|
||||
* Valid keywords is "auto" or other integer larger than 0
|
||||
*/
|
||||
std::string num_cycles_str = get_attribute(xml_operating_clock_setting, "num_cycles", loc_data).as_string();
|
||||
if (std::string("auto") == num_cycles_str) {
|
||||
sim_setting.set_num_clock_cycles(0);
|
||||
} else if (0 < get_attribute(xml_operating_clock_setting, "num_cycles", loc_data).as_int(0.)) {
|
||||
sim_setting.set_num_clock_cycles(get_attribute(xml_operating_clock_setting, "num_cycles", loc_data).as_int(0));
|
||||
} else {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_operating_clock_setting),
|
||||
"Invalid <num_cycles> defined under <operating>");
|
||||
}
|
||||
|
||||
sim_setting.set_operating_clock_frequency_slack(get_attribute(xml_operating_clock_setting, "slack", loc_data).as_float(0.));
|
||||
|
||||
/* Parse programming clock setting */
|
||||
pugi::xml_node xml_programming_clock_setting = get_single_child(xml_clock_setting, "programming", loc_data);
|
||||
|
||||
sim_setting.set_programming_clock_frequency(get_attribute(xml_programming_clock_setting, "frequency", loc_data).as_float(0.));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <simulator_option> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_simulator_option(pugi::xml_node& xml_sim_option,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
SimulationSetting& sim_setting) {
|
||||
|
||||
pugi::xml_node xml_operating_condition = get_single_child(xml_sim_option, "operating_condition", loc_data);
|
||||
sim_setting.set_simulation_temperature(get_attribute(xml_operating_condition, "temperature", loc_data).as_float(0.));
|
||||
|
||||
pugi::xml_node xml_output_log = get_single_child(xml_sim_option, "output_log", loc_data);
|
||||
sim_setting.set_verbose_output(get_attribute(xml_output_log, "verbose", loc_data).as_bool(false));
|
||||
sim_setting.set_capacitance_output(get_attribute(xml_output_log, "captab", loc_data).as_bool(false));
|
||||
|
||||
pugi::xml_node xml_accuracy = get_single_child(xml_sim_option, "accuracy", loc_data);
|
||||
|
||||
/* Find the type of accuracy */
|
||||
const char* type_attr = get_attribute(xml_accuracy, "type", loc_data).value();
|
||||
/* Translate the type of design technology to enumerate */
|
||||
e_sim_accuracy_type accuracy_type = string_to_sim_accuracy_type(std::string(type_attr));
|
||||
|
||||
if (NUM_SIM_ACCURACY_TYPES == accuracy_type) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_accuracy),
|
||||
"Invalid 'type' attribute '%s'\n",
|
||||
type_attr);
|
||||
}
|
||||
|
||||
sim_setting.set_simulation_accuracy_type(accuracy_type);
|
||||
|
||||
sim_setting.set_simulation_accuracy(get_attribute(xml_accuracy, "value", loc_data).as_float(0.));
|
||||
|
||||
/* Validate the accuracy value */
|
||||
if (SIM_ACCURACY_FRAC == sim_setting.simulation_accuracy_type()) {
|
||||
if (false == sim_setting.valid_signal_threshold(sim_setting.simulation_accuracy())) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_accuracy),
|
||||
"Invalid 'value' attribute '%f', which should be in the range of (0,1)\n",
|
||||
sim_setting.simulation_accuracy());
|
||||
}
|
||||
}
|
||||
|
||||
pugi::xml_node xml_runtime = get_single_child(xml_sim_option, "runtime", loc_data);
|
||||
sim_setting.set_fast_simulation(get_attribute(xml_runtime, "fast_simulation", loc_data).as_bool(false));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <monte_carlo> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_monte_carlo(pugi::xml_node& xml_mc,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
SimulationSetting& sim_setting) {
|
||||
sim_setting.set_monte_carlo_simulation_points(get_attribute(xml_mc, "num_simulation_points", loc_data).as_int(0));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <measurement_setting> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_measurement_setting(pugi::xml_node& xml_measurement,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
SimulationSetting& sim_setting) {
|
||||
pugi::xml_node xml_slew = get_single_child(xml_measurement, "slew", loc_data);
|
||||
pugi::xml_node xml_slew_rise = get_single_child(xml_slew, "rise", loc_data);
|
||||
sim_setting.set_measure_slew_upper_threshold(SIM_SIGNAL_RISE, get_attribute(xml_slew_rise, "upper_thres_pct", loc_data).as_float(0.));
|
||||
sim_setting.set_measure_slew_lower_threshold(SIM_SIGNAL_RISE, get_attribute(xml_slew_rise, "lower_thres_pct", loc_data).as_float(0.));
|
||||
|
||||
pugi::xml_node xml_slew_fall = get_single_child(xml_slew, "fall", loc_data);
|
||||
sim_setting.set_measure_slew_upper_threshold(SIM_SIGNAL_FALL, get_attribute(xml_slew_fall, "upper_thres_pct", loc_data).as_float(0.));
|
||||
sim_setting.set_measure_slew_lower_threshold(SIM_SIGNAL_FALL, get_attribute(xml_slew_fall, "lower_thres_pct", loc_data).as_float(0.));
|
||||
|
||||
pugi::xml_node xml_delay = get_single_child(xml_measurement, "delay", loc_data);
|
||||
pugi::xml_node xml_delay_rise = get_single_child(xml_delay, "rise", loc_data);
|
||||
sim_setting.set_measure_delay_input_threshold(SIM_SIGNAL_RISE, get_attribute(xml_delay_rise, "input_thres_pct", loc_data).as_float(0.));
|
||||
sim_setting.set_measure_delay_output_threshold(SIM_SIGNAL_RISE, get_attribute(xml_delay_rise, "output_thres_pct", loc_data).as_float(0.));
|
||||
|
||||
pugi::xml_node xml_delay_fall = get_single_child(xml_delay, "fall", loc_data);
|
||||
sim_setting.set_measure_delay_input_threshold(SIM_SIGNAL_FALL, get_attribute(xml_delay_fall, "input_thres_pct", loc_data).as_float(0.));
|
||||
sim_setting.set_measure_delay_output_threshold(SIM_SIGNAL_FALL, get_attribute(xml_delay_fall, "output_thres_pct", loc_data).as_float(0.));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <clock> inside <stimulus> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_stimulus_clock(pugi::xml_node& xml_stimuli_clock,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
SimulationSetting& sim_setting,
|
||||
const e_sim_signal_type& signal_type) {
|
||||
/* Find the type of accuracy */
|
||||
const char* type_attr = get_attribute(xml_stimuli_clock, "slew_type", loc_data).value();
|
||||
/* Translate the type of design technology to enumerate */
|
||||
e_sim_accuracy_type accuracy_type = string_to_sim_accuracy_type(std::string(type_attr));
|
||||
|
||||
if (NUM_SIM_ACCURACY_TYPES == accuracy_type) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_stimuli_clock),
|
||||
"Invalid 'type' attribute '%s'\n",
|
||||
type_attr);
|
||||
}
|
||||
|
||||
sim_setting.set_stimuli_clock_slew_type(signal_type, accuracy_type);
|
||||
|
||||
sim_setting.set_stimuli_clock_slew(signal_type, get_attribute(xml_stimuli_clock, "slew_time", loc_data).as_float(0.));
|
||||
|
||||
/* Validate the accuracy value */
|
||||
if (SIM_ACCURACY_FRAC == sim_setting.stimuli_clock_slew_type(signal_type)) {
|
||||
if (false == sim_setting.valid_signal_threshold(sim_setting.stimuli_clock_slew(signal_type))) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_stimuli_clock),
|
||||
"Invalid 'value' attribute '%f', which should be in the range of (0,1)\n",
|
||||
sim_setting.stimuli_clock_slew(signal_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <input> inside <stimulus> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_stimulus_input(pugi::xml_node& xml_stimuli_input,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
SimulationSetting& sim_setting,
|
||||
const e_sim_signal_type& signal_type) {
|
||||
/* Find the type of accuracy */
|
||||
const char* type_attr = get_attribute(xml_stimuli_input, "slew_type", loc_data).value();
|
||||
/* Translate the type of design technology to enumerate */
|
||||
e_sim_accuracy_type accuracy_type = string_to_sim_accuracy_type(std::string(type_attr));
|
||||
|
||||
if (NUM_SIM_ACCURACY_TYPES == accuracy_type) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_stimuli_input),
|
||||
"Invalid 'type' attribute '%s'\n",
|
||||
type_attr);
|
||||
}
|
||||
|
||||
sim_setting.set_stimuli_input_slew_type(signal_type, accuracy_type);
|
||||
|
||||
sim_setting.set_stimuli_input_slew(signal_type, get_attribute(xml_stimuli_input, "slew_time", loc_data).as_float(0.));
|
||||
|
||||
/* Validate the accuracy value */
|
||||
if (SIM_ACCURACY_FRAC == sim_setting.stimuli_input_slew_type(signal_type)) {
|
||||
if (false == sim_setting.valid_signal_threshold(sim_setting.stimuli_input_slew(signal_type))) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_stimuli_input),
|
||||
"Invalid 'value' attribute '%f', which should be in the range of (0,1)\n",
|
||||
sim_setting.stimuli_input_slew(signal_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <stimulus> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_stimulus(pugi::xml_node& xml_stimulus,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
SimulationSetting& sim_setting) {
|
||||
pugi::xml_node xml_clock = get_single_child(xml_stimulus, "clock", loc_data);
|
||||
pugi::xml_node xml_clock_rise = get_single_child(xml_clock, "rise", loc_data);
|
||||
read_xml_stimulus_clock(xml_clock_rise, loc_data, sim_setting, SIM_SIGNAL_RISE);
|
||||
|
||||
pugi::xml_node xml_clock_fall = get_single_child(xml_clock, "fall", loc_data);
|
||||
read_xml_stimulus_clock(xml_clock_fall, loc_data, sim_setting, SIM_SIGNAL_FALL);
|
||||
|
||||
pugi::xml_node xml_input = get_single_child(xml_stimulus, "input", loc_data);
|
||||
pugi::xml_node xml_input_rise = get_single_child(xml_input, "rise", loc_data);
|
||||
read_xml_stimulus_input(xml_input_rise, loc_data, sim_setting, SIM_SIGNAL_RISE);
|
||||
|
||||
pugi::xml_node xml_input_fall = get_single_child(xml_input, "fall", loc_data);
|
||||
read_xml_stimulus_input(xml_input_fall, loc_data, sim_setting, SIM_SIGNAL_FALL);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes about <openfpga_simulation_setting> to an object of technology library
|
||||
*******************************************************************/
|
||||
SimulationSetting read_xml_simulation_setting(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data) {
|
||||
SimulationSetting sim_setting;
|
||||
|
||||
/* Parse clock settings */
|
||||
pugi::xml_node xml_clock_setting = get_single_child(Node, "clock_setting", loc_data);
|
||||
read_xml_clock_setting(xml_clock_setting, loc_data, sim_setting);
|
||||
|
||||
/* Parse simulator options */
|
||||
pugi::xml_node xml_simulator_option = get_single_child(Node, "simulator_option", loc_data);
|
||||
read_xml_simulator_option(xml_simulator_option, loc_data, sim_setting);
|
||||
|
||||
/* Parse Monte carlo simulation options */
|
||||
pugi::xml_node xml_mc = get_single_child(Node, "monte_carlo", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
if (xml_mc) {
|
||||
read_xml_monte_carlo(xml_mc, loc_data, sim_setting);
|
||||
}
|
||||
|
||||
/* Parse measurement settings */
|
||||
pugi::xml_node xml_measurement = get_single_child(Node, "measurement_setting", loc_data);
|
||||
read_xml_measurement_setting(xml_measurement, loc_data, sim_setting);
|
||||
|
||||
/* Parse stimulus settings */
|
||||
pugi::xml_node xml_stimulus = get_single_child(Node, "stimulus", loc_data);
|
||||
read_xml_stimulus(xml_stimulus, loc_data, sim_setting);
|
||||
|
||||
return sim_setting;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef READ_XML_SIMULATION_SETTING_H
|
||||
#define READ_XML_SIMULATION_SETTING_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "pugixml_util.hpp"
|
||||
#include "pugixml.hpp"
|
||||
#include "simulation_setting.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
SimulationSetting read_xml_simulation_setting(pugi::xml_node& Node,
|
||||
const pugiutil::loc_data& loc_data);
|
||||
|
||||
#endif
|
|
@ -277,4 +277,3 @@ TechnologyLibrary read_xml_technology_library(pugi::xml_node& Node,
|
|||
|
||||
return tech_lib;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
#include "vtr_assert.h"
|
||||
|
||||
#include "simulation_setting.h"
|
||||
|
||||
/************************************************************************
|
||||
* Member functions for class SimulationSetting
|
||||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Constructors
|
||||
***********************************************************************/
|
||||
SimulationSetting::SimulationSetting() {
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Accessors
|
||||
***********************************************************************/
|
||||
float SimulationSetting::operating_clock_frequency() const {
|
||||
return clock_frequencies_.x();
|
||||
}
|
||||
|
||||
float SimulationSetting::programming_clock_frequency() const {
|
||||
return clock_frequencies_.y();
|
||||
}
|
||||
|
||||
bool SimulationSetting::auto_select_num_clock_cycles() const {
|
||||
return 0 == num_clock_cycles_;
|
||||
}
|
||||
|
||||
size_t SimulationSetting::num_clock_cycles() const {
|
||||
return num_clock_cycles_;
|
||||
}
|
||||
|
||||
float SimulationSetting::operating_clock_frequency_slack() const {
|
||||
return operating_clock_frequency_slack_;
|
||||
}
|
||||
|
||||
float SimulationSetting::simulation_temperature() const {
|
||||
return simulation_temperature_;
|
||||
}
|
||||
|
||||
bool SimulationSetting::verbose_output() const {
|
||||
return verbose_output_;
|
||||
}
|
||||
|
||||
bool SimulationSetting::capacitance_output() const {
|
||||
return capacitance_output_;
|
||||
}
|
||||
|
||||
e_sim_accuracy_type SimulationSetting::simulation_accuracy_type() const {
|
||||
return simulation_accuracy_type_;
|
||||
}
|
||||
|
||||
float SimulationSetting::simulation_accuracy() const {
|
||||
return simulation_accuracy_;
|
||||
}
|
||||
|
||||
bool SimulationSetting::fast_simulation() const {
|
||||
return fast_simulation_;
|
||||
}
|
||||
|
||||
bool SimulationSetting::run_monte_carlo_simulation() const {
|
||||
return 0 == monte_carlo_simulation_points_;
|
||||
}
|
||||
|
||||
size_t SimulationSetting::monte_carlo_simulation_points() const {
|
||||
return monte_carlo_simulation_points_;
|
||||
}
|
||||
|
||||
float SimulationSetting::measure_slew_upper_threshold(const e_sim_signal_type& signal_type) const {
|
||||
VTR_ASSERT (true == valid_signal_threshold(slew_upper_thresholds_[signal_type]));
|
||||
return slew_upper_thresholds_[signal_type];
|
||||
}
|
||||
|
||||
float SimulationSetting::measure_slew_lower_threshold(const e_sim_signal_type& signal_type) const {
|
||||
VTR_ASSERT (true == valid_signal_threshold(slew_lower_thresholds_[signal_type]));
|
||||
return slew_lower_thresholds_[signal_type];
|
||||
}
|
||||
|
||||
float SimulationSetting::measure_delay_input_threshold(const e_sim_signal_type& signal_type) const {
|
||||
VTR_ASSERT (true == valid_signal_threshold(delay_input_thresholds_[signal_type]));
|
||||
return delay_input_thresholds_[signal_type];
|
||||
}
|
||||
|
||||
float SimulationSetting::measure_delay_output_threshold(const e_sim_signal_type& signal_type) const {
|
||||
VTR_ASSERT (true == valid_signal_threshold(delay_output_thresholds_[signal_type]));
|
||||
return delay_output_thresholds_[signal_type];
|
||||
}
|
||||
|
||||
e_sim_accuracy_type SimulationSetting::stimuli_clock_slew_type(const e_sim_signal_type& signal_type) const {
|
||||
return clock_slew_types_[signal_type];
|
||||
}
|
||||
|
||||
float SimulationSetting::stimuli_clock_slew(const e_sim_signal_type& signal_type) const {
|
||||
return clock_slews_[signal_type];
|
||||
}
|
||||
|
||||
e_sim_accuracy_type SimulationSetting::stimuli_input_slew_type(const e_sim_signal_type& signal_type) const {
|
||||
return input_slew_types_[signal_type];
|
||||
}
|
||||
|
||||
float SimulationSetting::stimuli_input_slew(const e_sim_signal_type& signal_type) const {
|
||||
return input_slews_[signal_type];
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Mutators
|
||||
***********************************************************************/
|
||||
void SimulationSetting::set_operating_clock_frequency(const float& clock_freq) {
|
||||
clock_frequencies_.set_x(clock_freq);
|
||||
}
|
||||
|
||||
void SimulationSetting::set_programming_clock_frequency(const float& clock_freq) {
|
||||
clock_frequencies_.set_y(clock_freq);
|
||||
}
|
||||
|
||||
void SimulationSetting::set_num_clock_cycles(const size_t& num_clk_cycles) {
|
||||
num_clock_cycles_ = num_clk_cycles;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_operating_clock_frequency_slack(const float& op_clk_freq_slack) {
|
||||
operating_clock_frequency_slack_ = op_clk_freq_slack;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_simulation_temperature(const float& sim_temp) {
|
||||
simulation_temperature_ = sim_temp;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_verbose_output(const bool& verbose_output) {
|
||||
verbose_output_ = verbose_output;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_capacitance_output(const bool& cap_output) {
|
||||
capacitance_output_ = cap_output;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_simulation_accuracy_type(const e_sim_accuracy_type& type) {
|
||||
VTR_ASSERT(NUM_SIM_ACCURACY_TYPES != type);
|
||||
simulation_accuracy_type_ = type;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_simulation_accuracy(const float& accuracy) {
|
||||
simulation_accuracy_ = accuracy;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_fast_simulation(const bool& fast_sim) {
|
||||
fast_simulation_ = fast_sim;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_monte_carlo_simulation_points(const size_t& num_mc_points) {
|
||||
monte_carlo_simulation_points_ = num_mc_points;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_measure_slew_upper_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& upper_thres) {
|
||||
VTR_ASSERT(NUM_SIM_SIGNAL_TYPES != signal_type);
|
||||
VTR_ASSERT (true == valid_signal_threshold(upper_thres));
|
||||
slew_upper_thresholds_[signal_type] = upper_thres;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_measure_slew_lower_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& lower_thres) {
|
||||
VTR_ASSERT(NUM_SIM_SIGNAL_TYPES != signal_type);
|
||||
VTR_ASSERT (true == valid_signal_threshold(lower_thres));
|
||||
slew_lower_thresholds_[signal_type] = lower_thres;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_measure_delay_input_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& input_thres) {
|
||||
VTR_ASSERT(NUM_SIM_SIGNAL_TYPES != signal_type);
|
||||
VTR_ASSERT (true == valid_signal_threshold(input_thres));
|
||||
delay_input_thresholds_[signal_type] = input_thres;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_measure_delay_output_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& output_thres) {
|
||||
VTR_ASSERT(NUM_SIM_SIGNAL_TYPES != signal_type);
|
||||
VTR_ASSERT (true == valid_signal_threshold(output_thres));
|
||||
delay_output_thresholds_[signal_type] = output_thres;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_stimuli_clock_slew_type(const e_sim_signal_type& signal_type,
|
||||
const e_sim_accuracy_type& slew_type) {
|
||||
VTR_ASSERT(NUM_SIM_SIGNAL_TYPES != signal_type);
|
||||
clock_slew_types_[signal_type] = slew_type;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_stimuli_clock_slew(const e_sim_signal_type& signal_type,
|
||||
const float& clock_slew) {
|
||||
clock_slews_[signal_type] = clock_slew;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_stimuli_input_slew_type(const e_sim_signal_type& signal_type,
|
||||
const e_sim_accuracy_type& input_type) {
|
||||
VTR_ASSERT(NUM_SIM_SIGNAL_TYPES != signal_type);
|
||||
input_slew_types_[signal_type] = input_type;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_stimuli_input_slew(const e_sim_signal_type& signal_type,
|
||||
const float& input_slew) {
|
||||
input_slews_[signal_type] = input_slew;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Validators
|
||||
***********************************************************************/
|
||||
bool SimulationSetting::valid_signal_threshold(const float& threshold) const {
|
||||
return (0. < threshold) && (threshold < 1);
|
||||
}
|
|
@ -1,9 +1,214 @@
|
|||
#ifndef SIMULATION_SETTING_H
|
||||
#define SIMULATION_SETTING_H
|
||||
|
||||
/********************************************************************
|
||||
* This file include the declaration of simulation settings
|
||||
* which are used by OpenFPGA
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
/********************************************************************
|
||||
* Types of signal type in measurement and stimuli
|
||||
*******************************************************************/
|
||||
enum e_sim_signal_type {
|
||||
SIM_SIGNAL_RISE,
|
||||
SIM_SIGNAL_FALL,
|
||||
NUM_SIM_SIGNAL_TYPES
|
||||
};
|
||||
/* Strings correspond to each delay type */
|
||||
constexpr std::array<const char*, NUM_SIM_SIGNAL_TYPES> SIM_SIGNAL_TYPE_STRING = {{"rise", "fall"}};
|
||||
|
||||
/********************************************************************
|
||||
* Types of simulation accuracy type
|
||||
* 1. Fraction to the operating clock frequency
|
||||
* 2. Absolute value
|
||||
*******************************************************************/
|
||||
enum e_sim_accuracy_type {
|
||||
SIM_ACCURACY_FRAC,
|
||||
SIM_ACCURACY_ABS
|
||||
SIM_ACCURACY_ABS,
|
||||
NUM_SIM_ACCURACY_TYPES
|
||||
};
|
||||
/* Strings correspond to each accuracy type */
|
||||
constexpr std::array<const char*, NUM_SIM_ACCURACY_TYPES> SIM_ACCURACY_TYPE_STRING = {{"frac", "abs"}};
|
||||
|
||||
/********************************************************************
|
||||
* A data structure to describe simulation settings
|
||||
*
|
||||
* Typical usage:
|
||||
* --------------
|
||||
* // Create an empty technology library
|
||||
* SimulationSetting sim_setting;
|
||||
* // call your builder for sim_setting
|
||||
*
|
||||
*******************************************************************/
|
||||
class SimulationSetting {
|
||||
public: /* Constructors */
|
||||
SimulationSetting();
|
||||
public: /* Public Accessors */
|
||||
float operating_clock_frequency() const;
|
||||
float programming_clock_frequency() const;
|
||||
bool auto_select_num_clock_cycles() const;
|
||||
size_t num_clock_cycles() const;
|
||||
float operating_clock_frequency_slack() const;
|
||||
float simulation_temperature() const;
|
||||
bool verbose_output() const;
|
||||
bool capacitance_output() const;
|
||||
e_sim_accuracy_type simulation_accuracy_type() const;
|
||||
float simulation_accuracy() const;
|
||||
bool fast_simulation() const;
|
||||
bool run_monte_carlo_simulation() const;
|
||||
size_t monte_carlo_simulation_points() const;
|
||||
float measure_slew_upper_threshold(const e_sim_signal_type& signal_type) const;
|
||||
float measure_slew_lower_threshold(const e_sim_signal_type& signal_type) const;
|
||||
float measure_delay_input_threshold(const e_sim_signal_type& signal_type) const;
|
||||
float measure_delay_output_threshold(const e_sim_signal_type& signal_type) const;
|
||||
e_sim_accuracy_type stimuli_clock_slew_type(const e_sim_signal_type& signal_type) const;
|
||||
float stimuli_clock_slew(const e_sim_signal_type& signal_type) const;
|
||||
e_sim_accuracy_type stimuli_input_slew_type(const e_sim_signal_type& signal_type) const;
|
||||
float stimuli_input_slew(const e_sim_signal_type& signal_type) const;
|
||||
public: /* Public Mutators */
|
||||
void set_operating_clock_frequency(const float& clock_freq);
|
||||
void set_programming_clock_frequency(const float& clock_freq);
|
||||
void set_num_clock_cycles(const size_t& num_clk_cycles);
|
||||
void set_operating_clock_frequency_slack(const float& op_clk_freq_slack);
|
||||
void set_simulation_temperature(const float& sim_temp);
|
||||
void set_verbose_output(const bool& verbose_output);
|
||||
void set_capacitance_output(const bool& cap_output);
|
||||
void set_simulation_accuracy_type(const e_sim_accuracy_type& type);
|
||||
void set_simulation_accuracy(const float& accuracy);
|
||||
void set_fast_simulation(const bool& fast_sim);
|
||||
void set_monte_carlo_simulation_points(const size_t& num_mc_points);
|
||||
void set_measure_slew_upper_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& upper_thres);
|
||||
void set_measure_slew_lower_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& lower_thres);
|
||||
void set_measure_delay_input_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& input_thres);
|
||||
void set_measure_delay_output_threshold(const e_sim_signal_type& signal_type,
|
||||
const float& output_thres);
|
||||
void set_stimuli_clock_slew_type(const e_sim_signal_type& signal_type,
|
||||
const e_sim_accuracy_type& slew_type);
|
||||
void set_stimuli_clock_slew(const e_sim_signal_type& signal_type,
|
||||
const float& clock_slew);
|
||||
void set_stimuli_input_slew_type(const e_sim_signal_type& signal_type,
|
||||
const e_sim_accuracy_type& slew_type);
|
||||
void set_stimuli_input_slew(const e_sim_signal_type& signal_type,
|
||||
const float& input_slew);
|
||||
public: /* Public Validators */
|
||||
bool valid_signal_threshold(const float& threshold) const;
|
||||
private: /* Internal data */
|
||||
/* Operating clock frequency: the clock frequency to be applied to users' implemetation on FPGA
|
||||
* This will be stored in the x() part of vtr::Point
|
||||
* Programming clock frequency: the clock frequency to be applied to configuration protocol of FPGA
|
||||
* This will be stored in the y() part of vtr::Point
|
||||
*/
|
||||
vtr::Point<float> clock_frequencies_;
|
||||
|
||||
/* Number of clock cycles to be used in simulation
|
||||
* If the value is 0, the clock cycles can be automatically
|
||||
* inferred from the signal activities of users' implementation
|
||||
*/
|
||||
size_t num_clock_cycles_;
|
||||
|
||||
/* Slack or margin to be added to clock frequency
|
||||
* if the operating clock frequency is automatically
|
||||
* detemined by VPR's routing results
|
||||
*/
|
||||
float operating_clock_frequency_slack_;
|
||||
|
||||
/* Operating temperature to be use in simulation */
|
||||
float simulation_temperature_;
|
||||
|
||||
/* Options support by simulators
|
||||
* verbose_output: This is an option to turn on verbose output in simulators
|
||||
* Simulation runtime can be slow when this option is on
|
||||
* for large FPGA fabrics!
|
||||
* capacitance_output: Show capacitance of each nodes in the log file
|
||||
* This is an option provided by SPICE simulators
|
||||
* Simulation runtime can be slow when this option is on
|
||||
* for large FPGA fabrics!
|
||||
* accuracy_type: type of accuracy to be used in simulation
|
||||
* See the definition in enumeration e_sim_accuracy_type
|
||||
* Simulation runtime can be slow when a high accuracy is enable
|
||||
* for large FPGA fabrics!
|
||||
* accuracy: the absolute value of accuracy to be used in simulation.
|
||||
* If fractional accuarcy is specified, the value will be determined by
|
||||
* the maximum operating frequency after VPR routing finished
|
||||
* If absolute accuracy is specified, the value will be given by users
|
||||
*/
|
||||
bool verbose_output_;
|
||||
bool capacitance_output_;
|
||||
e_sim_accuracy_type simulation_accuracy_type_;
|
||||
float simulation_accuracy_;
|
||||
|
||||
/* Enable fast simulation
|
||||
* Note: this may impact the accuracy of simulation results
|
||||
*/
|
||||
bool fast_simulation_;
|
||||
|
||||
/* Number of simulation points to be used in Monte Carlo simulation
|
||||
* If a zero is given, monte carlo simulation will not be applied
|
||||
* The larger number of simulation points is used, the slower runtime will be
|
||||
*/
|
||||
size_t monte_carlo_simulation_points_;
|
||||
|
||||
/* The thresholds (in percentage) to be used in the measuring signal slews
|
||||
* Thresholds related to rising edge will be stored in the first element
|
||||
* Thresholds related to falling edge will be stored in the second element
|
||||
*/
|
||||
std::array<float, NUM_SIM_SIGNAL_TYPES> slew_upper_thresholds_;
|
||||
std::array<float, NUM_SIM_SIGNAL_TYPES> slew_lower_thresholds_;
|
||||
|
||||
/* The thresholds (in percentage) to be used in the measuring signal delays
|
||||
* Thresholds related to rising edge will be stored in the first element
|
||||
* Thresholds related to falling edge will be stored in the second element
|
||||
*
|
||||
* An example of delay measurement in rising edge
|
||||
* from 50% of input signal to 50% of output signal
|
||||
* (delay_input_threshold=0.5; delay_output_threshold=0.5)
|
||||
*
|
||||
* Input signal
|
||||
*
|
||||
* 50% of full swing of input signal
|
||||
* ^ +--------------------------
|
||||
* |/
|
||||
* +----------------+
|
||||
* / | |
|
||||
* -------+ | |
|
||||
* v |
|
||||
* rise delay |
|
||||
* |
|
||||
* Output signal |
|
||||
* | +--------
|
||||
* |/
|
||||
* +
|
||||
* /|
|
||||
* -------------------------+ |
|
||||
* v
|
||||
* 50% of full swing of output signal
|
||||
*/
|
||||
std::array<float, NUM_SIM_SIGNAL_TYPES> delay_input_thresholds_;
|
||||
std::array<float, NUM_SIM_SIGNAL_TYPES> delay_output_thresholds_;
|
||||
|
||||
/* Stimulus to be given to each type of port.
|
||||
* We support two types of ports:
|
||||
* 1. clock ports
|
||||
* 2. regular input ports
|
||||
*
|
||||
* Slew time related to rising edge will be stored in the first element
|
||||
* Slew time related to falling edge will be stored in the second element
|
||||
*
|
||||
* accuracy_type: type of accuracy to be used in simulation
|
||||
* Fractional accuracy will be determined by the clock frequency
|
||||
* to be defined by user in the clock_setting
|
||||
*/
|
||||
std::array<e_sim_accuracy_type, NUM_SIM_ACCURACY_TYPES> clock_slew_types_;
|
||||
std::array<float, NUM_SIM_ACCURACY_TYPES> clock_slews_;
|
||||
std::array<e_sim_accuracy_type, NUM_SIM_ACCURACY_TYPES> input_slew_types_;
|
||||
std::array<float, NUM_SIM_ACCURACY_TYPES> input_slews_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that outputs a configuration protocol to XML format
|
||||
*******************************************************************/
|
||||
/* Headers from system goes first */
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtr util library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
/* Headers from readarchopenfpga library */
|
||||
#include "write_xml_utils.h"
|
||||
#include "write_xml_config_protocol.h"
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a configuration memory organization to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_config_organization(std::fstream& fp,
|
||||
const char* fname,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t\t" << "<organization";
|
||||
|
||||
write_xml_attribute(fp, "type", CONFIG_PROTOCOL_TYPE_STRING[config_protocol.type()]);
|
||||
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.memory_model()).c_str());
|
||||
|
||||
fp << "/>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a configuration protocol to XML format
|
||||
* Note:
|
||||
* This function should be run AFTER the function
|
||||
* link_config_protocol_to_circuit_library()
|
||||
*******************************************************************/
|
||||
void write_xml_config_protocol(std::fstream& fp,
|
||||
const char* fname,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* Write the root node */
|
||||
fp << "\t" << "<configuration_protocol>" << "\n";
|
||||
|
||||
/* Write configuration memory organization */
|
||||
write_xml_config_organization(fp, fname, config_protocol, circuit_lib);
|
||||
|
||||
/* Finish writing the root node */
|
||||
fp << "\t" << "</configuration_protocol>" << "\n";
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef WRITE_XML_CONFIG_PROTOCOL_H
|
||||
#define WRITE_XML_CONFIG_PROTOCOL_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <fstream>
|
||||
#include "config_protocol.h"
|
||||
#include "circuit_library.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
void write_xml_config_protocol(std::fstream& fp,
|
||||
const char* fname,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
#endif
|
|
@ -10,6 +10,9 @@
|
|||
/* Headers from readarchopenfpga library */
|
||||
#include "write_xml_circuit_library.h"
|
||||
#include "write_xml_technology_library.h"
|
||||
#include "write_xml_simulation_setting.h"
|
||||
#include "write_xml_config_protocol.h"
|
||||
#include "write_xml_routing_circuit.h"
|
||||
#include "write_xml_openfpga_arch.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -34,5 +37,23 @@ void write_xml_openfpga_arch(const char* fname,
|
|||
/* Write the circuit library */
|
||||
write_xml_circuit_library(fp, fname, openfpga_arch.circuit_lib);
|
||||
|
||||
/* Write the configuration protocol */
|
||||
write_xml_config_protocol(fp, fname, openfpga_arch.config_protocol, openfpga_arch.circuit_lib);
|
||||
|
||||
/* Write the connection block circuit definition */
|
||||
write_xml_cb_switch_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.cb_switch2circuit);
|
||||
|
||||
/* Write the switch block circuit definition */
|
||||
write_xml_sb_switch_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.sb_switch2circuit);
|
||||
|
||||
/* Write the routing segment circuit definition */
|
||||
write_xml_routing_segment_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.routing_seg2circuit);
|
||||
|
||||
/* Write the direct connection circuit definition */
|
||||
write_xml_direct_circuit(fp, fname, openfpga_arch.circuit_lib, openfpga_arch.direct2circuit);
|
||||
|
||||
fp << "</openfpga_architecture>" << "\n";
|
||||
|
||||
/* Write the simulation */
|
||||
write_xml_simulation_setting(fp, fname, openfpga_arch.sim_setting);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that outputs routing circuit definition
|
||||
* to XML format
|
||||
*******************************************************************/
|
||||
/* Headers from system goes first */
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtr util library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
/* Headers from readarchopenfpga library */
|
||||
#include "write_xml_utils.h"
|
||||
#include "write_xml_routing_circuit.h"
|
||||
|
||||
/********************************************************************
|
||||
* Write switch circuit model definition in XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_routing_component_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const std::string& routing_component_name,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& switch2circuit) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* Iterate over the mapping */
|
||||
for (std::map<std::string, CircuitModelId>::const_iterator it = switch2circuit.begin();
|
||||
it != switch2circuit.end();
|
||||
++it) {
|
||||
fp << "\t\t" << "<" << routing_component_name;
|
||||
write_xml_attribute(fp, "name", it->first.c_str());
|
||||
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(it->second).c_str());
|
||||
fp << "/>" << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write Connection block circuit models in XML format
|
||||
*******************************************************************/
|
||||
void write_xml_cb_switch_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& switch2circuit) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* Write the root node */
|
||||
fp << "\t" << "<connection_block>" << "\n";
|
||||
|
||||
/* Write each switch circuit definition */
|
||||
write_xml_routing_component_circuit(fp, fname, std::string("switch"), circuit_lib, switch2circuit);
|
||||
|
||||
/* Finish writing the root node */
|
||||
fp << "\t" << "</connection_block>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write Switch block circuit models in XML format
|
||||
*******************************************************************/
|
||||
void write_xml_sb_switch_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& switch2circuit) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* Write the root node */
|
||||
fp << "\t" << "<switch_block>" << "\n";
|
||||
|
||||
/* Write each switch circuit definition */
|
||||
write_xml_routing_component_circuit(fp, fname, std::string("switch"), circuit_lib, switch2circuit);
|
||||
|
||||
/* Finish writing the root node */
|
||||
fp << "\t" << "</switch_block>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write routing segment circuit models in XML format
|
||||
*******************************************************************/
|
||||
void write_xml_routing_segment_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& seg2circuit) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* Write the root node */
|
||||
fp << "\t" << "<routing_segment>" << "\n";
|
||||
|
||||
/* Write each routing segment circuit definition */
|
||||
write_xml_routing_component_circuit(fp, fname, std::string("segment"), circuit_lib, seg2circuit);
|
||||
|
||||
/* Finish writing the root node */
|
||||
fp << "\t" << "</routing_segment>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write direction connection circuit models in XML format
|
||||
*******************************************************************/
|
||||
void write_xml_direct_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& direct2circuit) {
|
||||
/* If the direct2circuit is empty, we do not output XML */
|
||||
if (direct2circuit.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* Write the root node */
|
||||
fp << "\t" << "<direct_connection>" << "\n";
|
||||
|
||||
/* Write each direct connection circuit definition */
|
||||
write_xml_routing_component_circuit(fp, fname, std::string("direct"), circuit_lib, direct2circuit);
|
||||
|
||||
/* Finish writing the root node */
|
||||
fp << "\t" << "</direct_connection>" << "\n";
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef WRITE_XML_ROUTING_CIRCUIT_H
|
||||
#define WRITE_XML_ROUTING_CIRCUIT_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "circuit_library.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
void write_xml_cb_switch_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& switch2circuit);
|
||||
|
||||
void write_xml_sb_switch_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& switch2circuit);
|
||||
|
||||
void write_xml_routing_segment_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& seg2circuit);
|
||||
|
||||
void write_xml_direct_circuit(std::fstream& fp,
|
||||
const char* fname,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const std::map<std::string, CircuitModelId>& direct2circuit);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,244 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that outputs a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
/* Headers from system goes first */
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtr util library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
/* Headers from readarchopenfpga library */
|
||||
#include "write_xml_utils.h"
|
||||
#include "write_xml_simulation_setting.h"
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a clock setting in a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_clock_setting(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t" << "<clock_setting>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<operating";
|
||||
write_xml_attribute(fp, "frequency", sim_setting.operating_clock_frequency());
|
||||
|
||||
if (true == sim_setting.auto_select_num_clock_cycles()) {
|
||||
write_xml_attribute(fp, "num_cycles", "auto");
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == sim_setting.auto_select_num_clock_cycles());
|
||||
write_xml_attribute(fp, "num_cycles", std::to_string(sim_setting.num_clock_cycles()).c_str());
|
||||
}
|
||||
|
||||
write_xml_attribute(fp, "slack", std::to_string(sim_setting.operating_clock_frequency_slack()).c_str());
|
||||
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<operating";
|
||||
write_xml_attribute(fp, "frequency", sim_setting.programming_clock_frequency());
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t" << "</clock_setting>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a simulator option in a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_simulator_option(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t" << "<simulator_option>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<operating_condition";
|
||||
write_xml_attribute(fp, "temperature", sim_setting.simulation_temperature());
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<output_log";
|
||||
write_xml_attribute(fp, "verbose", sim_setting.verbose_output());
|
||||
write_xml_attribute(fp, "captab", sim_setting.capacitance_output());
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<accuracy";
|
||||
write_xml_attribute(fp, "type", SIM_ACCURACY_TYPE_STRING[sim_setting.simulation_accuracy_type()]);
|
||||
write_xml_attribute(fp, "value", sim_setting.simulation_accuracy());
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<runtime";
|
||||
write_xml_attribute(fp, "fast_simulation", sim_setting.fast_simulation());
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t" << "</simulator_option>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a monte carlo simulation setting
|
||||
* in a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_monte_carlo(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* This is an optional setting,
|
||||
* If defined, we will output the monte carlo simulation
|
||||
*/
|
||||
if (false == sim_setting.run_monte_carlo_simulation()) {
|
||||
return;
|
||||
}
|
||||
|
||||
fp << "\t\t" << "<monte_carlo";
|
||||
|
||||
write_xml_attribute(fp, "num_simulation_points", std::to_string(sim_setting.monte_carlo_simulation_points()).c_str());
|
||||
|
||||
fp << "/>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output the slew measurement setting in a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_slew_measurement(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting,
|
||||
const e_sim_signal_type& signal_type) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t\t\t" << "<" << SIM_SIGNAL_TYPE_STRING[signal_type];
|
||||
|
||||
write_xml_attribute(fp, "upper_thres_pct", sim_setting.measure_slew_upper_threshold(signal_type));
|
||||
write_xml_attribute(fp, "lower_thres_pct", sim_setting.measure_slew_lower_threshold(signal_type));
|
||||
|
||||
fp << "/>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output the delay measurement setting in a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_delay_measurement(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting,
|
||||
const e_sim_signal_type& signal_type) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t\t\t" << "<" << SIM_SIGNAL_TYPE_STRING[signal_type];
|
||||
|
||||
write_xml_attribute(fp, "input_thres_pct", sim_setting.measure_delay_input_threshold(signal_type));
|
||||
write_xml_attribute(fp, "output_thres_pct", sim_setting.measure_delay_output_threshold(signal_type));
|
||||
|
||||
fp << "/>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a measurement setting in a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_measurement(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t" << "<measurement_setting>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<slew>" << "\n";
|
||||
write_xml_slew_measurement(fp, fname, sim_setting, SIM_SIGNAL_RISE);
|
||||
write_xml_slew_measurement(fp, fname, sim_setting, SIM_SIGNAL_FALL);
|
||||
fp << "\t\t" << "</slew>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<delay>" << "\n";
|
||||
write_xml_delay_measurement(fp, fname, sim_setting, SIM_SIGNAL_RISE);
|
||||
write_xml_delay_measurement(fp, fname, sim_setting, SIM_SIGNAL_FALL);
|
||||
fp << "\t\t" << "</delay>" << "\n";
|
||||
|
||||
fp << "\t" << "</measurement_setting>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a stimulus setting in a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
static
|
||||
void write_xml_stimulus(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t" << "<stimulus>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<clock>" << "\n";
|
||||
|
||||
fp << "\t\t\t" << "<rise";
|
||||
write_xml_attribute(fp, "slew_type", SIM_ACCURACY_TYPE_STRING[sim_setting.stimuli_clock_slew_type(SIM_SIGNAL_RISE)]);
|
||||
write_xml_attribute(fp, "slew_time", sim_setting.stimuli_clock_slew(SIM_SIGNAL_RISE));
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t\t" << "<fall";
|
||||
write_xml_attribute(fp, "slew_type", SIM_ACCURACY_TYPE_STRING[sim_setting.stimuli_clock_slew_type(SIM_SIGNAL_FALL)]);
|
||||
write_xml_attribute(fp, "slew_time", sim_setting.stimuli_clock_slew(SIM_SIGNAL_FALL));
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t" << "</clock>" << "\n";
|
||||
|
||||
fp << "\t\t" << "<input>" << "\n";
|
||||
|
||||
fp << "\t\t\t" << "<rise";
|
||||
write_xml_attribute(fp, "slew_type", SIM_ACCURACY_TYPE_STRING[sim_setting.stimuli_input_slew_type(SIM_SIGNAL_RISE)]);
|
||||
write_xml_attribute(fp, "slew_time", sim_setting.stimuli_input_slew(SIM_SIGNAL_RISE));
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t\t" << "<fall";
|
||||
write_xml_attribute(fp, "slew_type", SIM_ACCURACY_TYPE_STRING[sim_setting.stimuli_input_slew_type(SIM_SIGNAL_FALL)]);
|
||||
write_xml_attribute(fp, "slew_time", sim_setting.stimuli_input_slew(SIM_SIGNAL_FALL));
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t" << "</input>" << "\n";
|
||||
|
||||
fp << "\t" << "</stimulus>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a simulation setting to XML format
|
||||
*******************************************************************/
|
||||
void write_xml_simulation_setting(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting) {
|
||||
/* Validate the file stream */
|
||||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
/* Write the root node <openfpga_simulation_setting>
|
||||
*/
|
||||
fp << "<openfpga_simulation_setting>" << "\n";
|
||||
|
||||
/* Write clock settings */
|
||||
write_xml_clock_setting(fp, fname, sim_setting);
|
||||
|
||||
/* Write simulator option */
|
||||
write_xml_simulator_option(fp, fname, sim_setting);
|
||||
|
||||
/* Write monte carlo simulation setting */
|
||||
write_xml_monte_carlo(fp, fname, sim_setting);
|
||||
|
||||
/* Write measurement setting */
|
||||
write_xml_measurement(fp, fname, sim_setting);
|
||||
|
||||
/* Write stimuli setting */
|
||||
write_xml_stimulus(fp, fname, sim_setting);
|
||||
|
||||
/* Write the root node <openfpga_simulation_setting> */
|
||||
fp << "</openfpga_simulation_setting>" << "\n";
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef WRITE_XML_SIMULATION_SETTING_H
|
||||
#define WRITE_XML_SIMULATION_SETTING_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <fstream>
|
||||
#include "simulation_setting.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
void write_xml_simulation_setting(std::fstream& fp,
|
||||
const char* fname,
|
||||
const SimulationSetting& sim_setting);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue