rework on the circuit model ports and start prototyping mux Verilog generation
This commit is contained in:
parent
a7ac1e4980
commit
29104b6fa5
|
@ -150,7 +150,7 @@ size_t check_one_circuit_model_port_required(const CircuitLibrary& circuit_lib,
|
|||
size_t num_err = 0;
|
||||
|
||||
for (const auto& port_type: port_types_to_check) {
|
||||
if (0 == circuit_lib.ports_by_type(circuit_model, port_type).size()) {
|
||||
if (0 == circuit_lib.model_ports_by_type(circuit_model, port_type).size()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"%s circuit model(name=%s) does not have %s port\n",
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.model_type(circuit_model))],
|
||||
|
@ -175,11 +175,11 @@ size_t check_one_circuit_model_port_size_required(const CircuitLibrary& circuit_
|
|||
|
||||
size_t num_err = 0;
|
||||
|
||||
if (port_size_to_check != circuit_lib.port_size(circuit_model, circuit_port)) {
|
||||
if (port_size_to_check != circuit_lib.port_size(circuit_port)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Port of circuit model(name=%s) does not have a port(type=%s) of size=%d.\n",
|
||||
circuit_lib.model_name(circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(circuit_model, circuit_port))],
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(circuit_port))],
|
||||
port_size_to_check);
|
||||
/* Incremental the counter for errors */
|
||||
num_err++;
|
||||
|
@ -202,7 +202,7 @@ size_t check_one_circuit_model_port_type_and_size_required(const CircuitLibrary&
|
|||
|
||||
size_t num_err = 0;
|
||||
|
||||
std::vector<CircuitPortId> ports = circuit_lib.ports_by_type(circuit_model, port_type_to_check, include_global_ports);
|
||||
std::vector<CircuitPortId> ports = circuit_lib.model_ports_by_type(circuit_model, port_type_to_check, include_global_ports);
|
||||
if (num_ports_to_check != ports.size()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Expect %d %s ports for a %s circuit model, but only have %d %s ports!\n",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -102,6 +102,7 @@
|
|||
*
|
||||
* ------ Port information ------
|
||||
* 1. port_ids_: unique id of ports belonging to a circuit model
|
||||
* 1. port_model_ids_: unique id of the parent circuit model for the port
|
||||
* 2. port_types_: types of ports belonging to a circuit model
|
||||
* 3. port_sizes_: width of ports belonging to a circuit model
|
||||
* 4. port_prefix_: prefix of a port when instance of a circuit model
|
||||
|
@ -113,8 +114,8 @@
|
|||
* 10. port_is_set: specify if this port is a set signal which needs special pulse widths in testbenches
|
||||
* 11. port_is_config_enable: specify if this port is a config_enable signal which needs special pulse widths in testbenches
|
||||
* 12. port_is_prog: specify if this port is for FPGA programming use which needs special pulse widths in testbenches
|
||||
* 13. port_model_name: the name of circuit model linked to the port
|
||||
* 14. port_model_ids_: the Id of circuit model linked to the port
|
||||
* 13. port_tri_state_model_name: the name of circuit model linked to tri-state the port
|
||||
* 14. port_tri_state_model_ids_: the Id of circuit model linked to tri-state the port
|
||||
* 15. port_inv_model_names_: the name of inverter circuit model linked to the port
|
||||
* 16. port_inv_model_ids_: the Id of inverter circuit model linked to the port
|
||||
* 17. port_tri_state_map_: only applicable to inputs of LUTs, the tri-state map applied to each pin of this port
|
||||
|
@ -187,12 +188,12 @@
|
|||
***********************************************************************/
|
||||
class CircuitLibrary {
|
||||
public: /* Types */
|
||||
typedef vtr::vector<CircuitModelId, CircuitModelId>::const_iterator model_iterator;
|
||||
typedef vtr::vector<CircuitModelId, std::string>::const_iterator model_string_iterator;
|
||||
typedef vtr::vector<CircuitModelId, CircuitModelId>::const_iterator circuit_model_iterator;
|
||||
typedef vtr::vector<CircuitModelId, std::string>::const_iterator circuit_model_string_iterator;
|
||||
typedef vtr::vector<CircuitPortId, CircuitPortId>::const_iterator circuit_port_iterator;
|
||||
typedef vtr::vector<CircuitEdgeId, CircuitEdgeId>::const_iterator circuit_edge_iterator;
|
||||
/* Create range */
|
||||
typedef vtr::Range<model_iterator> model_range;
|
||||
typedef vtr::Range<circuit_model_iterator> circuit_model_range;
|
||||
typedef vtr::Range<circuit_port_iterator> circuit_port_range;
|
||||
typedef vtr::Range<circuit_edge_iterator> circuit_edge_range;
|
||||
/* local enumeration for buffer existence */
|
||||
|
@ -202,14 +203,9 @@ class CircuitLibrary {
|
|||
public: /* Constructors */
|
||||
CircuitLibrary();
|
||||
public: /* Accessors: aggregates */
|
||||
model_range models() const;
|
||||
circuit_port_range ports(const CircuitModelId& model_id) const;
|
||||
circuit_model_range models() const;
|
||||
circuit_port_range ports() const;
|
||||
std::vector<CircuitModelId> models_by_type(const enum e_spice_model_type& type) const;
|
||||
std::vector<CircuitPortId> ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type) const;
|
||||
std::vector<CircuitPortId> ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
std::vector<CircuitPortId> input_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<CircuitPortId> output_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<size_t> pins(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
public: /* Public Accessors: Basic data query on Circuit Models*/
|
||||
size_t num_models() const;
|
||||
enum e_spice_model_type model_type(const CircuitModelId& model_id) const;
|
||||
|
@ -225,41 +221,48 @@ class CircuitLibrary {
|
|||
bool is_input_buffered(const CircuitModelId& model_id) const;
|
||||
bool is_output_buffered(const CircuitModelId& model_id) const;
|
||||
bool is_lut_intermediate_buffered(const CircuitModelId& model_id) const;
|
||||
enum e_spice_model_pass_gate_logic_type pass_gate_logic_type(const CircuitModelId& model_id) const;
|
||||
CircuitModelId pass_gate_logic_model(const CircuitModelId& model_id) const;
|
||||
enum e_spice_model_structure mux_structure(const CircuitModelId& model_id) const;
|
||||
size_t mux_num_levels(const CircuitModelId& model_id) const;
|
||||
bool mux_add_const_input(const CircuitModelId& model_id) const;
|
||||
size_t mux_const_input_value(const CircuitModelId& model_id) const;
|
||||
enum e_spice_model_gate_type gate_type(const CircuitModelId& model_id) const;
|
||||
public: /* Public Accessors: Basic data query on cirucit models' Circuit Ports*/
|
||||
CircuitPortId model_port(const CircuitModelId& model_id, const std::string& name) const;
|
||||
size_t num_model_ports(const CircuitModelId& model_id) const;
|
||||
size_t num_model_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
std::vector<CircuitPortId> model_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<CircuitPortId> model_global_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<CircuitPortId> model_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type) const;
|
||||
std::vector<CircuitPortId> model_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
std::vector<CircuitPortId> model_input_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<CircuitPortId> model_output_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<size_t> pins(const CircuitPortId& circuit_port_id) const;
|
||||
public: /* Public Accessors: Basic data query on Circuit Ports*/
|
||||
bool is_input_port(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool is_output_port(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
CircuitPortId port(const CircuitModelId& model_id, const std::string& name) const;
|
||||
size_t num_ports(const CircuitModelId& model_id) const;
|
||||
size_t num_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
enum e_spice_model_port_type port_type(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_size(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_prefix(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_lib_name(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_inv_prefix(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_default_value(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_mode_select(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_global(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_reset(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_set(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_config_enable(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_prog(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool is_input_port(const CircuitPortId& circuit_port_id) const;
|
||||
bool is_output_port(const CircuitPortId& circuit_port_id) const;
|
||||
enum e_spice_model_port_type port_type(const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_size(const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_prefix(const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_lib_name(const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_inv_prefix(const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_default_value(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_mode_select(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_global(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_reset(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_set(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
||||
public: /* Public Accessors: Methods to find circuit model */
|
||||
CircuitModelId model(const char* name) const;
|
||||
CircuitModelId model(const std::string& name) const;
|
||||
CircuitModelId default_model(const enum e_spice_model_type& type) const;
|
||||
public: /* Public Accessors: Timing graph */
|
||||
CircuitEdgeId edge(const CircuitModelId& model_id,
|
||||
const CircuitPortId& from_port, const size_t from_pin,
|
||||
CircuitEdgeId edge(const CircuitPortId& from_port, const size_t from_pin,
|
||||
const CircuitPortId& to_port, const size_t to_pin);
|
||||
public: /* Public Mutators */
|
||||
CircuitModelId add_model();
|
||||
CircuitModelId add_model(const enum e_spice_model_type& type);
|
||||
/* Fundamental information */
|
||||
void set_model_type(const CircuitModelId& model_id, const enum e_spice_model_type& type);
|
||||
void set_model_name(const CircuitModelId& model_id, const std::string& name);
|
||||
void set_model_prefix(const CircuitModelId& model_id, const std::string& prefix);
|
||||
void set_model_verilog_netlist(const CircuitModelId& model_id, const std::string& verilog_netlist);
|
||||
|
@ -273,80 +276,59 @@ class CircuitLibrary {
|
|||
void set_model_is_power_gated(const CircuitModelId& model_id, const bool& is_power_gated);
|
||||
/* Buffer existence */
|
||||
void set_model_input_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_output_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_input_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_input_inverter(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_intermediate_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_intermediate_buffer_location_map(const CircuitModelId& model_id,
|
||||
const std::string& location_map);
|
||||
const std::string& location_map);
|
||||
/* Pass-gate-related parameters */
|
||||
void set_model_pass_gate_logic(const CircuitModelId& model_id, const std::string& model_name);
|
||||
/* Port information */
|
||||
CircuitPortId add_model_port(const CircuitModelId& model_id);
|
||||
void set_port_type(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const enum e_spice_model_port_type& port_type);
|
||||
void set_port_size(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
CircuitPortId add_model_port(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_port_type& port_type);
|
||||
void set_port_size(const CircuitPortId& circuit_port_id,
|
||||
const size_t& port_size);
|
||||
void set_port_prefix(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_prefix(const CircuitPortId& circuit_port_id,
|
||||
const std::string& port_prefix);
|
||||
void set_port_lib_name(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_lib_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& lib_name);
|
||||
void set_port_inv_prefix(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_inv_prefix(const CircuitPortId& circuit_port_id,
|
||||
const std::string& inv_prefix);
|
||||
void set_port_default_value(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_default_value(const CircuitPortId& circuit_port_id,
|
||||
const size_t& default_val);
|
||||
void set_port_is_mode_select(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_mode_select(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_mode_select);
|
||||
void set_port_is_global(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_global(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_global);
|
||||
void set_port_is_reset(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_reset(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_reset);
|
||||
void set_port_is_set(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_set(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_set);
|
||||
void set_port_is_config_enable(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_config_enable(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_config_enable);
|
||||
void set_port_is_prog(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_prog(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_prog);
|
||||
void set_port_model_name(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const std::string& model_name);
|
||||
void set_port_model_id(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& port_model_id);
|
||||
void set_port_inv_model_name(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const std::string& inv_model_name);
|
||||
void set_port_inv_model_id(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& inv_model_id);
|
||||
void set_port_tri_state_map(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& model_name);
|
||||
void set_port_tri_state_model_id(const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& port_model_id);
|
||||
void set_port_inv_model_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& inv_model_name);
|
||||
void set_port_inv_model_id(const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& inv_model_id);
|
||||
void set_port_tri_state_map(const CircuitPortId& circuit_port_id,
|
||||
const std::string& tri_state_map);
|
||||
void set_port_lut_frac_level(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_lut_frac_level(const CircuitPortId& circuit_port_id,
|
||||
const size_t& lut_frac_level);
|
||||
void set_port_lut_output_mask(const CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
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 CircuitModelId& model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_sram_orgz(const CircuitPortId& circuit_port_id,
|
||||
const enum e_sram_orgz& sram_orgz);
|
||||
/* Delay information */
|
||||
void add_delay_info(const CircuitModelId& model_id,
|
||||
|
@ -415,19 +397,18 @@ class CircuitLibrary {
|
|||
const float& c_val);
|
||||
void set_wire_num_levels(const CircuitModelId& model_id,
|
||||
const size_t& num_level);
|
||||
public: /* Public Mutators: builders */
|
||||
private: /* Private Mutators: builders */
|
||||
void set_model_buffer(const CircuitModelId& model_id, const enum e_buffer_type buffer_type, const bool& existence, const std::string& model_name);
|
||||
void link_port_model(const CircuitModelId& model_id);
|
||||
void link_port_inv_model(const CircuitModelId& model_id);
|
||||
void link_port_models(const CircuitModelId& model_id);
|
||||
void link_port_tri_state_model();
|
||||
void link_port_inv_model();
|
||||
void link_buffer_model(const CircuitModelId& model_id);
|
||||
void link_pass_gate_logic_model(const CircuitModelId& model_id);
|
||||
void build_model_links();
|
||||
void build_model_timing_graph(const CircuitModelId& model_id);
|
||||
public: /* Public Mutators: builders */
|
||||
void build_model_links();
|
||||
void build_timing_graphs();
|
||||
public: /* Internal mutators: build timing graphs */
|
||||
void add_edge(const CircuitModelId& model_id,
|
||||
const CircuitPortId& from_port, const size_t& from_pin,
|
||||
void add_edge(const CircuitPortId& from_port, const size_t& from_pin,
|
||||
const CircuitPortId& to_port, const size_t& to_pin);
|
||||
void set_edge_delay(const CircuitModelId& model_id,
|
||||
const CircuitEdgeId& circuit_edge_id,
|
||||
|
@ -437,19 +418,19 @@ class CircuitLibrary {
|
|||
void set_timing_graph_delays(const CircuitModelId& model_id);
|
||||
public: /* Internal mutators: build fast look-ups */
|
||||
void build_model_lookup();
|
||||
void build_model_port_lookup(const CircuitModelId& model_id);
|
||||
void build_model_port_lookup();
|
||||
private: /* Internal invalidators/validators */
|
||||
/* Validators */
|
||||
bool valid_model_id(const CircuitModelId& model_id) const;
|
||||
bool valid_circuit_port_id(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool valid_circuit_pin_id(const CircuitModelId& model_id, const CircuitPortId& circuit_port_id, const size_t& pin_id) const;
|
||||
bool valid_circuit_port_id(const CircuitPortId& circuit_port_id) const;
|
||||
bool valid_circuit_pin_id(const CircuitPortId& circuit_port_id, const size_t& pin_id) const;
|
||||
bool valid_delay_type(const CircuitModelId& model_id, const enum spice_model_delay_type& delay_type) const;
|
||||
bool valid_circuit_edge_id(const CircuitModelId& model_id, const CircuitEdgeId& circuit_edge_id) const;
|
||||
bool valid_circuit_edge_id(const CircuitEdgeId& circuit_edge_id) const;
|
||||
bool valid_mux_const_input_value(const size_t& const_input_value) const;
|
||||
/* Invalidators */
|
||||
void invalidate_model_lookup() const;
|
||||
void invalidate_model_port_lookup(const CircuitModelId& model_id) const;
|
||||
void invalidate_model_timing_graph(const CircuitModelId& model_id);
|
||||
void invalidate_model_port_lookup() const;
|
||||
void invalidate_model_timing_graph();
|
||||
private: /* Internal data */
|
||||
/* Fundamental information */
|
||||
vtr::vector<CircuitModelId, CircuitModelId> model_ids_;
|
||||
|
@ -466,7 +447,7 @@ class CircuitLibrary {
|
|||
*/
|
||||
typedef std::vector<std::vector<CircuitModelId>> CircuitModelLookup;
|
||||
mutable CircuitModelLookup model_lookup_; /* [model_type][model_ids] */
|
||||
typedef std::vector<std::vector<std::vector<CircuitPortId>>> CircuitModelPortLookup;
|
||||
typedef vtr::vector<CircuitModelId, std::vector<std::vector<CircuitPortId>>> CircuitModelPortLookup;
|
||||
mutable CircuitModelPortLookup model_port_lookup_; /* [model_id][port_type][port_ids] */
|
||||
|
||||
/* Verilog generator options */
|
||||
|
@ -488,37 +469,38 @@ class CircuitLibrary {
|
|||
vtr::vector<CircuitModelId, CircuitModelId> pass_gate_logic_model_ids_;
|
||||
|
||||
/* Port information */
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, CircuitPortId>> port_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, enum e_spice_model_port_type>> port_types_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, size_t>> port_sizes_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_prefix_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_lib_names_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_inv_prefix_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, size_t>> port_default_values_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_mode_select_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_global_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_reset_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_set_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_config_enable_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_prog_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_model_names_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, CircuitModelId>> port_model_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_inv_model_names_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, CircuitModelId>> port_inv_model_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_tri_state_maps_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, size_t>> port_lut_frac_level_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::vector<size_t>>> port_lut_output_masks_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, enum e_sram_orgz>> port_sram_orgz_;
|
||||
vtr::vector<CircuitPortId, CircuitPortId> port_ids_;
|
||||
vtr::vector<CircuitPortId, CircuitModelId> port_model_ids_;
|
||||
vtr::vector<CircuitPortId, enum e_spice_model_port_type> port_types_;
|
||||
vtr::vector<CircuitPortId, size_t> port_sizes_;
|
||||
vtr::vector<CircuitPortId, std::string> port_prefix_;
|
||||
vtr::vector<CircuitPortId, std::string> port_lib_names_;
|
||||
vtr::vector<CircuitPortId, std::string> port_inv_prefix_;
|
||||
vtr::vector<CircuitPortId, size_t> port_default_values_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_mode_select_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_global_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_reset_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_set_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_config_enable_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_prog_;
|
||||
vtr::vector<CircuitPortId, std::string> port_tri_state_model_names_;
|
||||
vtr::vector<CircuitPortId, CircuitModelId> port_tri_state_model_ids_;
|
||||
vtr::vector<CircuitPortId, std::string> port_inv_model_names_;
|
||||
vtr::vector<CircuitPortId, CircuitModelId> port_inv_model_ids_;
|
||||
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_;
|
||||
|
||||
/* Timing graphs */
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, CircuitEdgeId>> edge_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>>> port_in_edge_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>>> port_out_edge_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, CircuitPortId>> edge_src_port_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, size_t>> edge_src_pin_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, CircuitPortId>> edge_sink_port_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, size_t>> edge_sink_pin_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, std::vector<float>>> edge_timing_info_; /* x0 => trise, x1 => tfall */
|
||||
vtr::vector<CircuitEdgeId, CircuitEdgeId> edge_ids_;
|
||||
vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>> port_in_edge_ids_;
|
||||
vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>> port_out_edge_ids_;
|
||||
vtr::vector<CircuitEdgeId, CircuitPortId> edge_src_port_ids_;
|
||||
vtr::vector<CircuitEdgeId, size_t> edge_src_pin_ids_;
|
||||
vtr::vector<CircuitEdgeId, CircuitPortId> edge_sink_port_ids_;
|
||||
vtr::vector<CircuitEdgeId, size_t> edge_sink_pin_ids_;
|
||||
vtr::vector<CircuitEdgeId, std::vector<float>> edge_timing_info_; /* x0 => trise, x1 => tfall */
|
||||
|
||||
/* Delay information */
|
||||
vtr::vector<CircuitModelId, std::vector<enum spice_model_delay_type>> delay_types_;
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
/************************************************************************
|
||||
* Create strong id for Circuit Models/Ports to avoid illegal type casting
|
||||
***********************************************************************/
|
||||
#ifndef CIRCUIT_LIBRARY_FWD_H
|
||||
#define CIRCUIT_LIBRARY_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
struct circuit_model_id_tag;
|
||||
|
@ -19,3 +22,5 @@ typedef vtr::StrongId<circuit_edge_id_tag> CircuitEdgeId;
|
|||
|
||||
/* Short declaration of class */
|
||||
class CircuitLibrary;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -102,6 +102,7 @@ enum e_spice_model_pass_gate_logic_type {
|
|||
SPICE_MODEL_PASS_GATE_TRANSMISSION,
|
||||
SPICE_MODEL_PASS_GATE_TRANSISTOR,
|
||||
SPICE_MODEL_PASS_GATE_RRAM, /* RRAM can be treated as a special type of pass-gate logic */
|
||||
SPICE_MODEL_PASS_GATE_STDCELL, /* Standard cell as a special type of pass-gate logic */
|
||||
NUM_CIRCUIT_MODEL_PASS_GATE_TYPES
|
||||
};
|
||||
|
||||
|
|
|
@ -1573,11 +1573,9 @@ CircuitLibrary build_circuit_library(int num_spice_model, t_spice_model* spice_m
|
|||
/* Go spice_model by spice_model */
|
||||
for (int imodel = 0; imodel < num_spice_model; ++imodel) {
|
||||
/* Add a spice model to the circuit_lib */
|
||||
CircuitModelId model_id = circuit_lib.add_model();
|
||||
CircuitModelId model_id = circuit_lib.add_model(spice_models[imodel].type);
|
||||
/* Fill fundamental attributes */
|
||||
/* Basic information*/
|
||||
circuit_lib.set_model_type(model_id, spice_models[imodel].type);
|
||||
|
||||
std::string name(spice_models[imodel].name);
|
||||
circuit_lib.set_model_name(model_id, name);
|
||||
|
||||
|
@ -1728,59 +1726,57 @@ CircuitLibrary build_circuit_library(int num_spice_model, t_spice_model* spice_m
|
|||
|
||||
/* Ports */
|
||||
for (int iport = 0; iport < spice_models[imodel].num_port; ++iport) {
|
||||
CircuitPortId port_id = circuit_lib.add_model_port(model_id);
|
||||
CircuitPortId port_id = circuit_lib.add_model_port(model_id, spice_models[imodel].ports[iport].type);
|
||||
/* Fill fundamental attributes */
|
||||
circuit_lib.set_port_type(model_id, port_id, spice_models[imodel].ports[iport].type);
|
||||
|
||||
circuit_lib.set_port_size(model_id, port_id, spice_models[imodel].ports[iport].size);
|
||||
circuit_lib.set_port_size(port_id, spice_models[imodel].ports[iport].size);
|
||||
|
||||
std::string port_prefix(spice_models[imodel].ports[iport].prefix);
|
||||
circuit_lib.set_port_prefix(model_id, port_id, port_prefix);
|
||||
circuit_lib.set_port_prefix(port_id, port_prefix);
|
||||
|
||||
std::string port_lib_name(spice_models[imodel].ports[iport].lib_name);
|
||||
circuit_lib.set_port_lib_name(model_id, port_id, port_lib_name);
|
||||
circuit_lib.set_port_lib_name(port_id, port_lib_name);
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].inv_prefix) {
|
||||
std::string port_inv_prefix(spice_models[imodel].ports[iport].inv_prefix);
|
||||
circuit_lib.set_port_inv_prefix(model_id, port_id, port_inv_prefix);
|
||||
circuit_lib.set_port_inv_prefix(port_id, port_inv_prefix);
|
||||
}
|
||||
|
||||
circuit_lib.set_port_default_value(model_id, port_id, spice_models[imodel].ports[iport].default_val);
|
||||
circuit_lib.set_port_default_value(port_id, spice_models[imodel].ports[iport].default_val);
|
||||
|
||||
circuit_lib.set_port_is_mode_select(model_id, port_id, TRUE == spice_models[imodel].ports[iport].mode_select);
|
||||
circuit_lib.set_port_is_global(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_global);
|
||||
circuit_lib.set_port_is_reset(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_reset);
|
||||
circuit_lib.set_port_is_set(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_set);
|
||||
circuit_lib.set_port_is_config_enable(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_config_enable);
|
||||
circuit_lib.set_port_is_prog(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_prog);
|
||||
circuit_lib.set_port_is_mode_select(port_id, TRUE == spice_models[imodel].ports[iport].mode_select);
|
||||
circuit_lib.set_port_is_global(port_id, TRUE == spice_models[imodel].ports[iport].is_global);
|
||||
circuit_lib.set_port_is_reset(port_id, TRUE == spice_models[imodel].ports[iport].is_reset);
|
||||
circuit_lib.set_port_is_set(port_id, TRUE == spice_models[imodel].ports[iport].is_set);
|
||||
circuit_lib.set_port_is_config_enable(port_id, TRUE == spice_models[imodel].ports[iport].is_config_enable);
|
||||
circuit_lib.set_port_is_prog(port_id, TRUE == spice_models[imodel].ports[iport].is_prog);
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].spice_model_name) {
|
||||
std::string port_model_name(spice_models[imodel].ports[iport].spice_model_name);
|
||||
circuit_lib.set_port_model_name(model_id, port_id, port_model_name);
|
||||
circuit_lib.set_port_tri_state_model_name(port_id, port_model_name);
|
||||
}
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].inv_spice_model_name) {
|
||||
std::string port_inv_model_name(spice_models[imodel].ports[iport].inv_spice_model_name);
|
||||
circuit_lib.set_port_inv_model_name(model_id, port_id, port_inv_model_name);
|
||||
circuit_lib.set_port_inv_model_name(port_id, port_inv_model_name);
|
||||
}
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].tri_state_map) {
|
||||
std::string port_tri_state_map(spice_models[imodel].ports[iport].tri_state_map);
|
||||
circuit_lib.set_port_tri_state_map(model_id, port_id, port_tri_state_map);
|
||||
circuit_lib.set_port_tri_state_map(port_id, port_tri_state_map);
|
||||
}
|
||||
|
||||
if (SPICE_MODEL_LUT == spice_models[imodel].type) {
|
||||
circuit_lib.set_port_lut_frac_level(model_id, port_id, spice_models[imodel].ports[iport].lut_frac_level);
|
||||
circuit_lib.set_port_lut_frac_level(port_id, spice_models[imodel].ports[iport].lut_frac_level);
|
||||
|
||||
std::vector<size_t> port_lut_output_mask;
|
||||
for (int ipin = 0; ipin < spice_models[imodel].ports[iport].size; ++ipin) {
|
||||
port_lut_output_mask.push_back(spice_models[imodel].ports[iport].lut_output_mask[ipin]);
|
||||
}
|
||||
circuit_lib.set_port_lut_output_mask(model_id, port_id, port_lut_output_mask);
|
||||
circuit_lib.set_port_lut_output_mask(port_id, port_lut_output_mask);
|
||||
}
|
||||
|
||||
if (SPICE_MODEL_PORT_SRAM == spice_models[imodel].ports[iport].type) {
|
||||
circuit_lib.set_port_sram_orgz(model_id, port_id, spice_models[imodel].ports[iport].organization);
|
||||
circuit_lib.set_port_sram_orgz(port_id, spice_models[imodel].ports[iport].organization);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,19 @@ size_t MuxGraph::num_inputs() const {
|
|||
return num_inputs;
|
||||
}
|
||||
|
||||
/* Find the number of outputs in the MUX graph */
|
||||
size_t MuxGraph::num_outputs() const {
|
||||
/* need to check if the graph is valid or not */
|
||||
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||
/* Sum up the number of INPUT nodes in each level */
|
||||
size_t num_outputs = 0;
|
||||
for (auto node_per_level : node_lookup_) {
|
||||
num_outputs += node_per_level[MUX_OUTPUT_NODE].size();
|
||||
}
|
||||
return num_outputs;
|
||||
}
|
||||
|
||||
|
||||
/* Find the number of levels in the MUX graph */
|
||||
size_t MuxGraph::num_levels() const {
|
||||
/* need to check if the graph is valid or not */
|
||||
|
@ -133,7 +146,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
|||
|
||||
/* Add output nodes to subgraph */
|
||||
MuxNodeId to_node_subgraph = mux_graph.add_node(MUX_OUTPUT_NODE);
|
||||
mux_graph.node_levels_[to_node_subgraph] = 0;
|
||||
mux_graph.node_levels_[to_node_subgraph] = 1;
|
||||
/* Update the node-to-node map */
|
||||
node2node_map[root_node] = to_node_subgraph;
|
||||
|
||||
|
@ -155,7 +168,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
|||
MuxEdgeId edge_subgraph = mux_graph.add_edge(node2node_map[from_node_origin], node2node_map[root_node]);
|
||||
edge2edge_map[edge_origin] = edge_subgraph;
|
||||
/* Configure edges */
|
||||
mux_graph.edge_types_[edge_subgraph] = this->edge_types_[edge_origin];
|
||||
mux_graph.edge_models_[edge_subgraph] = this->edge_models_[edge_origin];
|
||||
mux_graph.edge_inv_mem_[edge_subgraph] = this->edge_inv_mem_[edge_origin];
|
||||
}
|
||||
|
||||
|
@ -179,6 +192,9 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
|||
mem2mem_map[mem_origin] = mem_subgraph;
|
||||
}
|
||||
|
||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||
mux_graph.build_node_lookup();
|
||||
|
||||
return mux_graph;
|
||||
}
|
||||
|
||||
|
@ -300,7 +316,7 @@ MuxEdgeId MuxGraph::add_edge(const MuxNodeId& from_node, const MuxNodeId& to_nod
|
|||
/* Push to the node list */
|
||||
edge_ids_.push_back(edge);
|
||||
/* Resize the other node-related vectors */
|
||||
edge_types_.push_back(NUM_CIRCUIT_MODEL_PASS_GATE_TYPES);
|
||||
edge_models_.push_back(CircuitModelId::INVALID());
|
||||
edge_mem_ids_.push_back(MuxMemId::INVALID());
|
||||
edge_inv_mem_.push_back(false);
|
||||
|
||||
|
@ -386,7 +402,7 @@ void MuxGraph::set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem) {
|
|||
*/
|
||||
void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
||||
const size_t& num_levels, const size_t& num_inputs_per_branch,
|
||||
const enum e_spice_model_pass_gate_logic_type& pgl_type) {
|
||||
const CircuitModelId& pgl_model) {
|
||||
/* Make sure mux_size for each branch is valid */
|
||||
VTR_ASSERT(valid_mux_implementation_num_inputs(num_inputs_per_branch));
|
||||
|
||||
|
@ -439,7 +455,7 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
|||
/* Create an edge and connect the two nodes */
|
||||
MuxEdgeId edge = add_edge(expand_node, seed_node);
|
||||
/* Configure the edge */
|
||||
edge_types_[edge] = pgl_type;
|
||||
edge_models_[edge] = pgl_model;
|
||||
|
||||
/* Memory id depends on the level and offset in the current branch
|
||||
* if number of inputs per branch is 2, it indicates a tree-like multiplexer,
|
||||
|
@ -517,7 +533,7 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
|||
* input_node --->+
|
||||
*/
|
||||
void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
||||
const enum e_spice_model_pass_gate_logic_type& pgl_type) {
|
||||
const CircuitModelId& pgl_model) {
|
||||
/* Make sure mux_size is valid */
|
||||
VTR_ASSERT(valid_mux_implementation_num_inputs(mux_size));
|
||||
|
||||
|
@ -538,7 +554,7 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
|||
*/
|
||||
MuxEdgeId edge = add_edge(input_node, output_node);
|
||||
/* Configure the edge */
|
||||
edge_types_[edge] = pgl_type;
|
||||
edge_models_[edge] = pgl_model;
|
||||
|
||||
/* Create a memory bit*/
|
||||
MuxMemId mem = add_mem();
|
||||
|
@ -574,11 +590,11 @@ void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
|||
size_t num_inputs_per_branch = 2;
|
||||
|
||||
/* Build a multilevel mux graph */
|
||||
build_multilevel_mux_graph(impl_mux_size, num_levels, num_inputs_per_branch, circuit_lib.pass_gate_logic_type(circuit_model));
|
||||
build_multilevel_mux_graph(impl_mux_size, num_levels, num_inputs_per_branch, circuit_lib.pass_gate_logic_model(circuit_model));
|
||||
break;
|
||||
}
|
||||
case SPICE_MODEL_STRUCTURE_ONELEVEL: {
|
||||
build_onelevel_mux_graph(impl_mux_size, circuit_lib.pass_gate_logic_type(circuit_model));
|
||||
build_onelevel_mux_graph(impl_mux_size, circuit_lib.pass_gate_logic_model(circuit_model));
|
||||
break;
|
||||
}
|
||||
case SPICE_MODEL_STRUCTURE_MULTILEVEL: {
|
||||
|
@ -588,7 +604,7 @@ void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
|||
/* Build a multilevel mux graph */
|
||||
build_multilevel_mux_graph(impl_mux_size, circuit_lib.mux_num_levels(circuit_model),
|
||||
num_inputs_per_branch,
|
||||
circuit_lib.pass_gate_logic_type(circuit_model));
|
||||
circuit_lib.pass_gate_logic_model(circuit_model));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -63,6 +63,8 @@ class MuxGraph {
|
|||
public: /* Public accessors: Data query */
|
||||
/* Find the number of inputs in the MUX graph */
|
||||
size_t num_inputs() const;
|
||||
/* Find the number of outputs in the MUX graph */
|
||||
size_t num_outputs() const;
|
||||
/* Find the number of levels in the MUX graph */
|
||||
size_t num_levels() const;
|
||||
/* Find the number of SRAMs in the MUX graph */
|
||||
|
@ -88,10 +90,10 @@ class MuxGraph {
|
|||
private: /* Private mutators : graph builders */
|
||||
void build_multilevel_mux_graph(const size_t& mux_size,
|
||||
const size_t& num_levels, const size_t& num_inputs_per_branch,
|
||||
const enum e_spice_model_pass_gate_logic_type& pgl_type);
|
||||
const CircuitModelId& pgl_model) ;
|
||||
/* Build the graph for a given one-level multiplexer implementation */
|
||||
void build_onelevel_mux_graph(const size_t& mux_size,
|
||||
const enum e_spice_model_pass_gate_logic_type& pgl_type);
|
||||
const CircuitModelId& pgl_model) ;
|
||||
/* Build the graph for a given multiplexer model */
|
||||
void build_mux_graph(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
|
@ -120,7 +122,7 @@ class MuxGraph {
|
|||
vtr::vector<MuxEdgeId, MuxEdgeId> edge_ids_; /* Unique ids for each edge */
|
||||
vtr::vector<MuxEdgeId, std::vector<MuxNodeId>> edge_src_nodes_; /* source nodes drive this edge */
|
||||
vtr::vector<MuxEdgeId, std::vector<MuxNodeId>> edge_sink_nodes_; /* sink nodes this edge drives */
|
||||
vtr::vector<MuxEdgeId, enum e_spice_model_pass_gate_logic_type> edge_types_; /* type of each edge: tgate/pass-gate */
|
||||
vtr::vector<MuxEdgeId, CircuitModelId> edge_models_; /* type of each edge: tgate/pass-gate */
|
||||
vtr::vector<MuxEdgeId, MuxMemId> edge_mem_ids_; /* ids of memory bit that control the edge */
|
||||
vtr::vector<MuxEdgeId, bool> edge_inv_mem_; /* if the edge is controlled by an inverted output of a memory bit */
|
||||
|
||||
|
|
|
@ -196,7 +196,6 @@ void link_sram_inf(t_sram_inf* cur_sram_inf,
|
|||
**************************************************************************/
|
||||
t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& circuit_port) {
|
||||
t_port* ret = NULL;
|
||||
size_t num_found = 0;
|
||||
|
@ -204,10 +203,10 @@ t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
|||
/* Search ports */
|
||||
for (int iport = 0; iport < pb_type->num_ports; iport++) {
|
||||
/* Match the name and port size*/
|
||||
if ( (0 == circuit_lib.port_prefix(circuit_model, circuit_port).compare(pb_type->ports[iport].name))
|
||||
&& (size_t(pb_type->ports[iport].num_pins) == circuit_lib.port_size(circuit_model, circuit_port))) {
|
||||
if ( (0 == circuit_lib.port_prefix(circuit_port).compare(pb_type->ports[iport].name))
|
||||
&& (size_t(pb_type->ports[iport].num_pins) == circuit_lib.port_size(circuit_port))) {
|
||||
/* Match the type*/
|
||||
switch (circuit_lib.port_type(circuit_model, circuit_port)) {
|
||||
switch (circuit_lib.port_type(circuit_port)) {
|
||||
case SPICE_MODEL_PORT_INPUT:
|
||||
if ((IN_PORT == pb_type->ports[iport].type)
|
||||
&&(0 == pb_type->ports[iport].is_clock)) {
|
||||
|
@ -236,7 +235,7 @@ t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
|||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s, [LINE%d])Invalid type for circuit model port(%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.port_prefix(circuit_model, circuit_port));
|
||||
__FILE__, __LINE__, circuit_lib.port_prefix(circuit_port));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +245,7 @@ t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
|||
if (1 < num_found) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])More than 1 pb_type(%s) port match spice_model_port(%s)!\n",
|
||||
__FILE__, __LINE__, pb_type->name, circuit_lib.port_prefix(circuit_model, circuit_port).c_str());
|
||||
__FILE__, __LINE__, pb_type->name, circuit_lib.port_prefix(circuit_port).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -276,8 +275,8 @@ int link_pb_type_port_to_circuit_model_ports(const t_pb_type* cur_pb_type,
|
|||
}
|
||||
|
||||
/* For each port, find a SPICE model port, which has the same name and port size */
|
||||
for (auto& port : circuit_lib.ports(circuit_model)) {
|
||||
t_port* cur_pb_type_port = find_pb_type_port_match_circuit_model_port(cur_pb_type, circuit_lib, circuit_model, port);
|
||||
for (auto& port : circuit_lib.model_ports(circuit_model)) {
|
||||
t_port* cur_pb_type_port = find_pb_type_port_match_circuit_model_port(cur_pb_type, circuit_lib, port);
|
||||
/* Not every spice_model_port can find a mapped pb_type_port.
|
||||
* Since a pb_type only includes necessary ports in technology mapping.
|
||||
* ports for physical designs may be ignored !
|
||||
|
|
|
@ -54,7 +54,6 @@ CircuitModelId link_circuit_model_by_name_and_type(const char* circuit_model_nam
|
|||
|
||||
t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& circuit_port);
|
||||
|
||||
void link_circuit_library_to_arch(t_arch* arch,
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/************************************************
|
||||
* This files includes data structures for
|
||||
* module management.
|
||||
* It keeps a list of modules that have been
|
||||
* generated, the port map of the modules,
|
||||
* parents and children of each modules
|
||||
* This will ease instanciation of modules
|
||||
* with explicit port map and outputting a
|
||||
* hierarchy of modules
|
||||
***********************************************/
|
||||
|
||||
#ifndef MODULE_MANAGER_H
|
||||
#define MODULE_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include "module_manager_fwd.h"
|
||||
#include "device_port.h"
|
||||
|
||||
class ModuleManager {
|
||||
private: /* Internal data */
|
||||
vtr::vector<ModuleId, ModuleId> ids_;
|
||||
vtr::vector<ModuleId, BasicPort> ports_;
|
||||
vtr::vector<ModuleId, std::vector<ModuleId>> parents_;
|
||||
vtr::vector<ModuleId, std::vector<ModuleId>> children_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
/**************************************************
|
||||
* This file includes only declarations for
|
||||
* the data structures for module managers
|
||||
* Please refer to module_manager.h for more details
|
||||
*************************************************/
|
||||
#ifndef MODULE_MANAGER_FWD_H
|
||||
#define MODULE_MANAGER_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
/* Strong Ids for MUXes */
|
||||
struct module_id_tag;
|
||||
|
||||
typedef vtr::StrongId<module_id_tag> ModuleId;
|
||||
|
||||
class ModuleManager;
|
||||
|
||||
#endif
|
|
@ -803,9 +803,9 @@ void dump_compact_verilog_defined_one_switch_box(t_sram_orgz_info* cur_sram_orgz
|
|||
chan_coordinator.get_x(), chan_coordinator.get_y(), itrack,
|
||||
rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)));
|
||||
if (true == is_explicit_mapping) {
|
||||
fprintf(fp, ")",itrack);
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ",\n",itrack);
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
fprintf(fp, "//----- %s side inputs: CLB output pins -----\n", convert_side_index_to_string(side));
|
||||
/* Dump OPINs of adjacent CLBs */
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifndef VERILOG_GLOBAL_H
|
||||
#define VERILOG_GLOBAL_H
|
||||
/* global parameters for dumping synthesizable verilog */
|
||||
|
||||
extern char* verilog_netlist_file_postfix;
|
||||
|
@ -140,8 +142,10 @@ VERILOG_PORT_OUTPUT,
|
|||
VERILOG_PORT_INOUT,
|
||||
VERILOG_PORT_WIRE,
|
||||
VERILOG_PORT_REG,
|
||||
VERILOG_PORT_CONKT
|
||||
VERILOG_PORT_CONKT,
|
||||
NUM_VERILOG_PORT_TYPES
|
||||
};
|
||||
constexpr std::array<const char*, NUM_VERILOG_PORT_TYPES> VERILOG_PORT_TYPE_STRING = {{"input", "output", "inout", "wire", "reg", ""}}; /* string version of enum e_verilog_port_type */
|
||||
|
||||
enum e_verilog_tb_type {
|
||||
VERILOG_TB_TOP,
|
||||
|
@ -149,3 +153,5 @@ VERILOG_TB_BLIF_TOP,
|
|||
VERILOG_TB_AUTOCHECK_TOP,
|
||||
VERILOG_TB_FORMAL_VERIFICATION
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,12 +5,25 @@
|
|||
* such as a branch in a multiplexer
|
||||
* and the full multiplexer
|
||||
**********************************************/
|
||||
#include <string>
|
||||
|
||||
#include "util.h"
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "verilog_submodule_mux.h"
|
||||
/* Device-level header files */
|
||||
#include "mux_graph.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "spice_types.h"
|
||||
#include "fpga_x2p_naming.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_submodule_mux.h"
|
||||
|
||||
/***********************************************
|
||||
* Generate Verilog codes modeling an branch circuit
|
||||
|
@ -20,7 +33,153 @@ static
|
|||
void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const std::string& module_name,
|
||||
const MuxGraph& mux_graph) {
|
||||
/* Get the tgate model */
|
||||
CircuitModelId tgate_model = circuit_lib.pass_gate_logic_model(circuit_model);
|
||||
|
||||
/* Skip output if the tgate model is a MUX2, it is handled by essential-gate generator */
|
||||
if (SPICE_MODEL_GATE == circuit_lib.model_type(tgate_model)) {
|
||||
VTR_ASSERT(SPICE_MODEL_GATE_MUX2 == circuit_lib.gate_type(tgate_model));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get model ports of tgate */
|
||||
std::vector<CircuitPortId> tgate_input_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT);
|
||||
std::vector<CircuitPortId> tgate_output_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_OUTPUT);
|
||||
VTR_ASSERT(3 == tgate_input_ports.size());
|
||||
VTR_ASSERT(1 == tgate_output_ports.size());
|
||||
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Generate the Verilog netlist according to the mux_graph */
|
||||
/* Find out the number of inputs */
|
||||
size_t num_inputs = mux_graph.num_inputs();
|
||||
/* Find out the number of outputs */
|
||||
size_t num_outputs = mux_graph.num_outputs();
|
||||
/* Find out the number of memory bits */
|
||||
size_t num_mems = mux_graph.num_memory_bits();
|
||||
|
||||
/* Check codes to ensure the port of Verilog netlists will match */
|
||||
/* MUX graph must have only 1 output */
|
||||
VTR_ASSERT(1 == num_outputs);
|
||||
/* MUX graph must have only 1 level*/
|
||||
VTR_ASSERT(1 == mux_graph.num_levels());
|
||||
|
||||
/* Comment lines */
|
||||
fp << "//---- Structural Verilog for CMOS MUX basis module:" << module_name << "-----" << std::endl;
|
||||
|
||||
/* Print the port list and definition */
|
||||
fp << "module " << module_name << "(" << std::endl;
|
||||
|
||||
/* Create port information */
|
||||
BasicPort input_port;
|
||||
/* Configure each input port */
|
||||
input_port.set_name(std::string("in"));
|
||||
input_port.set_width(num_inputs);
|
||||
|
||||
BasicPort output_port;
|
||||
/* Configure each input port */
|
||||
output_port.set_name(std::string("out"));
|
||||
output_port.set_width(num_outputs);
|
||||
|
||||
BasicPort mem_port;
|
||||
/* Configure each input port */
|
||||
mem_port.set_name(std::string("mem"));
|
||||
mem_port.set_width(num_mems);
|
||||
|
||||
BasicPort mem_inv_port;
|
||||
/* Configure each input port */
|
||||
mem_inv_port.set_name(std::string("mem_inv"));
|
||||
mem_inv_port.set_width(num_mems);
|
||||
|
||||
/* TODO: Generate global ports */
|
||||
|
||||
|
||||
/* TODO: add a module to the Module Manager */
|
||||
|
||||
/* Port list */
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, input_port) << "," << std::endl;
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_OUTPUT, output_port) << "," << std::endl;
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, mem_port) << "," << std::endl;
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, mem_inv_port) << std::endl;
|
||||
fp << ");" << std::endl;
|
||||
|
||||
/* Verilog Behavior description for a MUX */
|
||||
fp << "//---- Structure-level description -----" << std::endl;
|
||||
/* Special case: only one memory, switch case is simpler
|
||||
* When mem = 1, propagate input 0;
|
||||
* when mem = 0, propagate input 1;
|
||||
*/
|
||||
if (1 == num_mems) {
|
||||
/* Transmission gates are connected to each input and also the output*/
|
||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_0 ";
|
||||
/* Dump explicit port map if required */
|
||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
||||
fp << " (";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[0]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
||||
fp << ");" << std::endl;
|
||||
} else {
|
||||
fp << " (";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
/* Transmission gates are connected to each input and also the output*/
|
||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_1 ";
|
||||
/* Dump explicit port map if required */
|
||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
||||
fp << " (";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[1]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
||||
fp << ");" << std::endl;
|
||||
} else {
|
||||
fp << " (";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
} else {
|
||||
/* Other cases, we need to follow the rules:
|
||||
* When mem[k] is enabled, switch on input[k]
|
||||
* Only one memory bit is enabled!
|
||||
*/
|
||||
for (size_t i = 0; i < num_mems; i++) {
|
||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_" << i << " ";
|
||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
||||
fp << " (";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[" << i << "]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << "mem[" << i << "]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << "mem_inv[" << i << "]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
||||
fp << ");" << std::endl;
|
||||
} else {
|
||||
fp << " (";
|
||||
fp << "in[" << i << "]";
|
||||
fp << ", " << "mem[" << i << "]";
|
||||
fp << ", " << "mem_inv[" << i << "]";
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Put an end to this module */
|
||||
fp << "endmodule" << std::endl;
|
||||
|
||||
/* Comment lines */
|
||||
fp << "//---- END Structural Verilog CMOS MUX basis module: " << module_name << "-----" << std::endl << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -31,12 +190,15 @@ void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
|||
void generate_verilog_mux_branch_module(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const MuxGraph& mux_graph) {
|
||||
std::string module_name = generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, verilog_mux_basis_posfix);
|
||||
|
||||
/* Multiplexers built with different technology is in different organization */
|
||||
switch (circuit_lib.design_tech_type(circuit_model)) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
if (true == circuit_lib.dump_structural_verilog(circuit_model)) {
|
||||
generate_verilog_cmos_mux_branch_module_structural(fp, circuit_lib, circuit_model, mux_graph);
|
||||
generate_verilog_cmos_mux_branch_module_structural(fp, circuit_lib, circuit_model, module_name, mux_graph);
|
||||
} else {
|
||||
/*
|
||||
dump_verilog_cmos_mux_one_basis_module(fp, mux_basis_subckt_name,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
void generate_verilog_mux_branch_module(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const MuxGraph& mux_graph);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2854,7 +2854,8 @@ void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
std::vector<MuxGraph> branch_mux_graphs = mux_graph.build_mux_branch_graphs();
|
||||
/* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */
|
||||
for (auto branch_mux_graph : branch_mux_graphs) {
|
||||
generate_verilog_mux_branch_module(sfp, spice->circuit_lib, mux_circuit_model, branch_mux_graph);
|
||||
generate_verilog_mux_branch_module(sfp, spice->circuit_lib, mux_circuit_model,
|
||||
mux_graph.num_inputs(), branch_mux_graph);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ void dump_include_user_defined_verilog_netlists(FILE* fp,
|
|||
return;
|
||||
}
|
||||
|
||||
void check_file_handler(const std::fstream& fp) {
|
||||
void check_file_handler(std::fstream& fp) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
/* Print out debugging information for if the file is not opened/created properly */
|
||||
if (!fp.is_open() || !fp.good()) {
|
||||
|
@ -855,7 +855,6 @@ int rec_dump_verilog_spice_model_lib_global_ports(FILE* fp,
|
|||
return dumped_port_cnt;
|
||||
}
|
||||
|
||||
|
||||
/* Dump all the global ports that are stored in the linked list
|
||||
* Return the number of ports that have been dumped
|
||||
*/
|
||||
|
|
|
@ -10,7 +10,7 @@ void init_include_user_defined_verilog_netlists(t_spice spice);
|
|||
void dump_include_user_defined_verilog_netlists(FILE* fp,
|
||||
t_spice spice);
|
||||
|
||||
void check_file_handler(const std::fstream& fp);
|
||||
void check_file_handler(std::fstream& fp);
|
||||
|
||||
void dump_verilog_file_header(FILE* fp,
|
||||
char* usage);
|
||||
|
@ -52,6 +52,7 @@ void dump_verilog_subckt_header_file(t_llist* subckt_llist_head,
|
|||
|
||||
char determine_verilog_generic_port_split_sign(enum e_dump_verilog_port_type dump_port_type);
|
||||
|
||||
|
||||
void dump_verilog_generic_port(FILE* fp,
|
||||
enum e_dump_verilog_port_type dump_port_type,
|
||||
char* port_name, int port_lsb, int port_msb);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/************************************************
|
||||
* Include functions for most frequently
|
||||
* used Verilog writers
|
||||
***********************************************/
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Device-level header files */
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "spice_types.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
|
||||
/* Generate a string of a Verilog port */
|
||||
std::string generate_verilog_port(const enum e_dump_verilog_port_type& verilog_port_type,
|
||||
const BasicPort& port_info) {
|
||||
std::string verilog_line;
|
||||
|
||||
/* Ensure the port type is valid */
|
||||
VTR_ASSERT(verilog_port_type < NUM_VERILOG_PORT_TYPES);
|
||||
|
||||
std::string size_str = "[" + std::to_string(port_info.get_lsb()) + ":" + std::to_string(port_info.get_msb()) + "]";
|
||||
|
||||
/* Only connection require a format of <port_name>[<lsb>:<msb>]
|
||||
* others require a format of <port_type> [<lsb>:<msb>] <port_name>
|
||||
*/
|
||||
if (VERILOG_PORT_CONKT == verilog_port_type) {
|
||||
verilog_line = port_info.get_name() + " " + size_str;
|
||||
} else {
|
||||
verilog_line = VERILOG_PORT_TYPE_STRING[verilog_port_type];
|
||||
verilog_line += "" + size_str + " " + port_info.get_name();
|
||||
}
|
||||
|
||||
return verilog_line;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/************************************************
|
||||
* Header file for verilog_writer_utils.cpp
|
||||
* Include function declaration for most frequently
|
||||
* used Verilog writers
|
||||
***********************************************/
|
||||
#ifndef VERILOG_WRITER_UTILS_H
|
||||
#define VERILOG_WRITER_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include "device_port.h"
|
||||
|
||||
std::string generate_verilog_port(const enum e_dump_verilog_port_type& dump_port_type,
|
||||
const BasicPort& port_info);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue