complete refacotriing the inv and buf part in submodules
This commit is contained in:
parent
a40e5c91ca
commit
9c43b1b753
|
@ -17,11 +17,11 @@ Inverters and Buffers
|
|||
|
||||
* design_technology:
|
||||
|
||||
* **topology:** [inverter|buffer]. Specify the type of this component, can be either an inverter or a buffer.
|
||||
* **topology:** [``inverter`` | ``buffer``]. Specify the type of this component, can be either an inverter or a buffer.
|
||||
|
||||
* **size:** Specify the driving strength of inverter/buffer. For a buffer, the size is the driving strength of the inverter at the second level. We consider a two-level structure for a buffer here. The support for multi-level structure of a buffer will be introduced in the tapered options.
|
||||
|
||||
* **tapered:** [on|off]. Define if the buffer is a tapered (multi-level) buffer. *If "on" the following parameter are required.*
|
||||
* **tapered:** [``on`` | ``off``]. Define if the buffer is a tapered (multi-level) buffer. *If ``on`` the following parameter are required.*
|
||||
|
||||
* **tap_drive_level:** Define the number of levels of a tapered buffer. This parameter is valid only when tapered is turned on.
|
||||
|
||||
|
@ -54,6 +54,21 @@ This example shows:
|
|||
* Size of 1 for the output strength
|
||||
* The tapered parameter is not declared and is off by default
|
||||
|
||||
**Power-gated Inverter x1 example**
|
||||
|
||||
The XML code describing an inverter which can be power-gated by the control signals ``EN`` and ``ENB`` :
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<circuit_model type="inv_buf" name="INVTX1" prefix="INVTX1">
|
||||
<design_technology type="cmos" topology="inverter" size="3" tapered="off" power_gated="true"/>
|
||||
<port type="input" prefix="in" size="1" lib_name="I"/>
|
||||
<port type="input" prefix="EN" size="1" lib_name="EN" is_global="true" default_val="0" is_config_enable="true"/>
|
||||
<port type="input" prefix="ENB" size="1" lib_name="ENB" is_global="true" default_val="1" is_config_enable="true"/>
|
||||
<port type="output" prefix="out" size="1" lib_name="Z"/>
|
||||
</circuit_model>
|
||||
|
||||
.. note:: For power-gated inverters: all the control signals must be set as ``config_enable`` so that the testbench generation will generate testing waveforms. If the power-gated inverters are auto-generated , all the ``config_enable`` signals must be ``global`` signals as well. If the pwoer-gated inverters come from user-defined netlists, restrictions on ``global`` signals are free.
|
||||
|
||||
**Buffer x2 example**
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@ Define circuit_models
|
|||
|
||||
* **circuit_model**: the child node defining transistor-level modeling parameters.
|
||||
|
||||
* **type**: can be [ inv_buf | pass_gate | mux | wire | chan_wire | sram | lut | ff | scff | hard_logic | iopad ]. Specify the type of circuit model. The provided types cover all the modules in FPGAs. For the circuit models in the type of mux/wire/chan_wire/lut, FPGA-Verilog/SPICE can auto-generate Verilog/SPICE netlists. For the rest, FPGA-Verilog/SPICE requires a user-defined Verilog/SPICE netlist.
|
||||
* **type**: can be [ ``inv_buf`` | ``pass_gate`` | ``gate`` | ``mux`` | ``wire`` | ``chan_wire`` | ``sram`` | ``lut`` | ``ff`` | ``scff`` | ``hard_logic`` | ``iopad`` ]. Specify the type of circuit model. The provided types cover all the modules in FPGAs. For the circuit models in the type of mux/wire/chan_wire/lut, FPGA-Verilog/SPICE can auto-generate Verilog/SPICE netlists. For the rest, FPGA-Verilog/SPICE requires a user-defined Verilog/SPICE netlist.
|
||||
|
||||
* **name**: define the name of this circuit model. The name should be unique and will be used to create the sub-circuit of the circuit model in Verilog/SPICE netlists. Note that for a customized Verilog/SPICE netlist, the name defined here should be the name of the top-level sub-circuit in the customized Verilog/SPICE netlist. FPGA-Verilog/SPICE will check if the given name is conflicted with any reserved words.
|
||||
|
||||
* **prefix**: specify the name of the circuit_model to shown in the auto-generated Verilog/SPICE netlists. The prefix can be the same as the name defined above. And again, the prefix should be unique.
|
||||
|
||||
* **is_default**: can be [1|0], corresponding to [true|false] respectively. Specify this circuit model is the default one for some modules, such as multiplexers. If a module is not linked to any spice model by users, FPGA-Verilog/SPICE will find the default spice model defined in the same type and link. For a spice model type, only one spice model can be set as default.
|
||||
* **is_default**: can be [``1`` | ``0``], corresponding to [true|false] respectively. Specify this circuit model is the default one for some modules, such as multiplexers. If a module is not linked to any spice model by users, FPGA-Verilog/SPICE will find the default spice model defined in the same type and link. For a spice model type, only one spice model can be set as default.
|
||||
|
||||
* **spice_netlist**: specify the path and file name of a customized Verilog/SPICE netlist. For some modules such as SRAMs, FFs, inpads, and outpads, FPGA-Verilog/SPICE does not support auto-generation of the transistor-level sub-circuits because their circuit design is highly dependent on the technology nodes. These circuit designs should be specified by users. For the other modules that can be auto-generated by FPGA-Verilog/SPICE, the user can also define a custom netlist. Multiplexers cannot be user-defined.
|
||||
|
||||
|
@ -87,14 +87,14 @@ Transistor level
|
|||
|
||||
* **circuit_model_name:** only valid when the type of port is sram. Specify the name of the circuit model which is connected to this port.
|
||||
|
||||
* **mode_select:** can be either true or false. Specify if this port controls the mode switching in a configurable logic block. Only valid when the type of this port is sram. (A configurable logic block can operate in different modes, which is controlled by SRAM bits.)
|
||||
* **mode_select:** can be either ``true`` or ``false``. Specify if this port controls the mode switching in a configurable logic block. Only valid when the type of this port is sram. (A configurable logic block can operate in different modes, which is controlled by SRAM bits.)
|
||||
|
||||
* **is_global:** can be either true or false. Specify if this port is a global port, which will be routed globally. Note that when multiple global ports are defined with the same name, these global ports will be short-wired together.
|
||||
* **is_global:** can be either ``true`` or ``false``. Specify if this port is a global port, which will be routed globally. Note that when multiple global ports are defined with the same name, these global ports will be short-wired together.
|
||||
|
||||
* **is_set:** can be either true or false. Specify if this port controls a set signal. Only valid when is_global is true. All the set ports are connected to global set voltage stimuli in testbenches.
|
||||
* **is_set:** can be either ``true`` or ``false``. Specify if this port controls a set signal. Only valid when is_global is true. All the set ports are connected to global set voltage stimuli in testbenches.
|
||||
|
||||
* **is_reset:** can be either true or false. Specify if this port controls a reset signal. Only valid when is_global is true. All the reset ports are connected to a global reset voltage stimuli in testbenches.
|
||||
* **is_reset:** can be either ``true`` or ``false``. Specify if this port controls a reset signal. Only valid when is_global is true. All the reset ports are connected to a global reset voltage stimuli in testbenches.
|
||||
|
||||
* **is_config_enable:** can be either true or false. Only valid when is_global is true. Specify if this port controls a configuration-enable signal. This port is only enabled during FPGA configuration, and always disabled during FPGA operation. All the config_enable ports are connected to global configuration-enable voltage stimuli in testbenches.
|
||||
* **is_config_enable:** can be either ``true`` or ``false``. Only valid when is_global is true. Specify if this port controls a configuration-enable signal. This port is only enabled during FPGA configuration, and always disabled during FPGA operation. All the config_enable ports are connected to global configuration-enable voltage stimuli in testbenches.
|
||||
|
||||
.. note:: Different types of ``circuit_model`` have different XML syntax, with which users can highly customize their circuit topologies. See refer to examples of ``circuit_model`` for more details.
|
||||
|
|
|
@ -269,6 +269,24 @@ enum e_spice_model_buffer_type CircuitLibrary::buffer_type(const CircuitModelId&
|
|||
return buffer_types_[model_id];
|
||||
}
|
||||
|
||||
/* Return the number of levels of buffer for a circuit model
|
||||
* Only applicable for BUF/INV circuit model
|
||||
*/
|
||||
size_t CircuitLibrary::buffer_num_levels(const CircuitModelId& model_id) const {
|
||||
/* validate the model_id */
|
||||
VTR_ASSERT(valid_model_id(model_id));
|
||||
/* validate the circuit model type is BUF */
|
||||
VTR_ASSERT(SPICE_MODEL_INVBUF == model_type(model_id));
|
||||
return buffer_num_levels_[model_id];
|
||||
}
|
||||
|
||||
/* Return the number of levels of delay types for a circuit model */
|
||||
size_t CircuitLibrary::num_delay_info(const CircuitModelId& model_id) const {
|
||||
/* validate the model_id */
|
||||
VTR_ASSERT(valid_model_id(model_id));
|
||||
return delay_types_[model_id].size();
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Accessors : Basic data query on Circuit models' Circuit Port
|
||||
***********************************************************************/
|
||||
|
@ -571,6 +589,57 @@ bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const {
|
|||
return port_is_prog_[circuit_port_id];
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Accessors : Methods to visit timing graphs
|
||||
***********************************************************************/
|
||||
/* Find all the edges belonging to a circuit model */
|
||||
std::vector<CircuitEdgeId> CircuitLibrary::timing_edges_by_model(const CircuitModelId& model_id) const {
|
||||
/* Validate the model id */
|
||||
VTR_ASSERT_SAFE(valid_model_id(model_id));
|
||||
|
||||
std::vector<CircuitEdgeId> model_edges;
|
||||
for (const auto& edge : edge_ids_) {
|
||||
/* Bypass edges whose parent is not the model_id */
|
||||
if (model_id != edge_parent_model_ids_[edge]) {
|
||||
continue;
|
||||
}
|
||||
/* Update the edge list */
|
||||
model_edges.push_back(edge);
|
||||
}
|
||||
return model_edges;
|
||||
}
|
||||
|
||||
/* Get source/sink nodes and delay of edges */
|
||||
CircuitPortId CircuitLibrary::timing_edge_src_port(const CircuitEdgeId& edge) const {
|
||||
/* Validate the edge id */
|
||||
VTR_ASSERT_SAFE(valid_edge_id(edge));
|
||||
return edge_src_port_ids_[edge];
|
||||
}
|
||||
|
||||
size_t CircuitLibrary::timing_edge_src_pin(const CircuitEdgeId& edge) const {
|
||||
/* Validate the edge id */
|
||||
VTR_ASSERT_SAFE(valid_edge_id(edge));
|
||||
return edge_src_pin_ids_[edge];
|
||||
}
|
||||
|
||||
CircuitPortId CircuitLibrary::timing_edge_sink_port(const CircuitEdgeId& edge) const {
|
||||
/* Validate the edge id */
|
||||
VTR_ASSERT_SAFE(valid_edge_id(edge));
|
||||
return edge_sink_port_ids_[edge];
|
||||
}
|
||||
|
||||
size_t CircuitLibrary::timing_edge_sink_pin(const CircuitEdgeId& edge) const {
|
||||
/* Validate the edge id */
|
||||
VTR_ASSERT_SAFE(valid_edge_id(edge));
|
||||
return edge_sink_pin_ids_[edge];
|
||||
}
|
||||
|
||||
float CircuitLibrary::timing_edge_delay(const CircuitEdgeId& edge, const enum spice_model_delay_type& delay_type) const {
|
||||
/* Validate the edge id */
|
||||
VTR_ASSERT_SAFE(valid_edge_id(edge));
|
||||
return edge_timing_info_[edge][delay_type];
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Accessors : Methods to find circuit model
|
||||
***********************************************************************/
|
||||
|
@ -1498,7 +1567,7 @@ void CircuitLibrary::build_model_timing_graph(const CircuitModelId& model_id) {
|
|||
continue;
|
||||
}
|
||||
/* Add an edge to bridge the from_pin_id and to_pin_id */
|
||||
add_edge(from_port_id, from_pin_id, to_port_id, to_pin_id);
|
||||
add_edge(model_id, from_port_id, from_pin_id, to_port_id, to_pin_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1540,14 +1609,19 @@ void CircuitLibrary::build_timing_graphs() {
|
|||
* Internal mutators: build timing graphs
|
||||
***********************************************************************/
|
||||
/* Add an edge between two pins of two ports, and assign an default timing value */
|
||||
void CircuitLibrary::add_edge(const CircuitPortId& from_port, const size_t& from_pin,
|
||||
void CircuitLibrary::add_edge(const CircuitModelId& model_id,
|
||||
const CircuitPortId& from_port, const size_t& from_pin,
|
||||
const CircuitPortId& to_port, const size_t& to_pin) {
|
||||
/* validate the model_id */
|
||||
VTR_ASSERT(valid_model_id(model_id));
|
||||
|
||||
/* Create an edge in the edge id list */
|
||||
CircuitEdgeId edge_id = CircuitEdgeId(edge_ids_.size());
|
||||
/* Expand the edge list */
|
||||
edge_ids_.push_back(edge_id);
|
||||
|
||||
/* Initialize other attributes */
|
||||
edge_parent_model_ids_.push_back(model_id);
|
||||
|
||||
/* Update the list of incoming edges for to_port */
|
||||
/* Resize upon need */
|
||||
|
@ -1757,6 +1831,11 @@ bool CircuitLibrary::valid_circuit_pin_id(const CircuitPortId& circuit_port_id,
|
|||
return ( size_t(pin_id) < port_size(circuit_port_id) );
|
||||
}
|
||||
|
||||
bool CircuitLibrary::valid_edge_id(const CircuitEdgeId& edge_id) const {
|
||||
/* validate the model_id */
|
||||
return ( size_t(edge_id) < edge_ids_.size() ) && ( edge_id == edge_ids_[edge_id] );
|
||||
}
|
||||
|
||||
bool CircuitLibrary::valid_delay_type(const CircuitModelId& model_id, const enum spice_model_delay_type& delay_type) const {
|
||||
/* validate the model_id */
|
||||
VTR_ASSERT(valid_model_id(model_id));
|
||||
|
|
|
@ -218,16 +218,25 @@ class CircuitLibrary {
|
|||
bool dump_explicit_port_map(const CircuitModelId& model_id) const;
|
||||
enum e_spice_model_design_tech design_tech_type(const CircuitModelId& model_id) const;
|
||||
bool is_power_gated(const CircuitModelId& model_id) const;
|
||||
/* General buffer information */
|
||||
bool is_input_buffered(const CircuitModelId& model_id) const;
|
||||
bool is_output_buffered(const CircuitModelId& model_id) const;
|
||||
/* LUT-related information */
|
||||
bool is_lut_intermediate_buffered(const CircuitModelId& model_id) const;
|
||||
/* Pass-gate-logic information */
|
||||
CircuitModelId pass_gate_logic_model(const CircuitModelId& model_id) const;
|
||||
/* Multiplexer information */
|
||||
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;
|
||||
/* Gate information */
|
||||
enum e_spice_model_gate_type gate_type(const CircuitModelId& model_id) const;
|
||||
/* Buffer information */
|
||||
enum e_spice_model_buffer_type buffer_type(const CircuitModelId& model_id) const;
|
||||
size_t buffer_num_levels(const CircuitModelId& model_id) const;
|
||||
/* Delay information */
|
||||
size_t num_delay_info(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;
|
||||
|
@ -256,6 +265,14 @@ class CircuitLibrary {
|
|||
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: Timing graph */
|
||||
/* Get source/sink nodes and delay of edges */
|
||||
std::vector<CircuitEdgeId> timing_edges_by_model(const CircuitModelId& model_id) const;
|
||||
CircuitPortId timing_edge_src_port(const CircuitEdgeId& edge) const;
|
||||
size_t timing_edge_src_pin(const CircuitEdgeId& edge) const;
|
||||
CircuitPortId timing_edge_sink_port(const CircuitEdgeId& edge) const;
|
||||
size_t timing_edge_sink_pin(const CircuitEdgeId& edge) const;
|
||||
float timing_edge_delay(const CircuitEdgeId& edge, const enum spice_model_delay_type& delay_type) const;
|
||||
public: /* Public Accessors: Methods to find circuit model */
|
||||
CircuitModelId model(const char* name) const;
|
||||
CircuitModelId model(const std::string& name) const;
|
||||
|
@ -411,7 +428,8 @@ class CircuitLibrary {
|
|||
void build_model_links();
|
||||
void build_timing_graphs();
|
||||
public: /* Internal mutators: build timing graphs */
|
||||
void add_edge(const CircuitPortId& from_port, const size_t& from_pin,
|
||||
void add_edge(const CircuitModelId& model_id,
|
||||
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,
|
||||
|
@ -427,6 +445,7 @@ class CircuitLibrary {
|
|||
bool valid_model_id(const CircuitModelId& model_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_edge_id(const CircuitEdgeId& edge_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 CircuitEdgeId& circuit_edge_id) const;
|
||||
bool valid_mux_const_input_value(const size_t& const_input_value) const;
|
||||
|
@ -497,6 +516,7 @@ class CircuitLibrary {
|
|||
|
||||
/* Timing graphs */
|
||||
vtr::vector<CircuitEdgeId, CircuitEdgeId> edge_ids_;
|
||||
vtr::vector<CircuitEdgeId, CircuitModelId> edge_parent_model_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_;
|
||||
|
|
|
@ -13,6 +13,27 @@ BasicPort::BasicPort() {
|
|||
msb_ = 0;
|
||||
}
|
||||
|
||||
/* Quick constructor */
|
||||
BasicPort::BasicPort(const char* name, const size_t& lsb, const size_t& msb) {
|
||||
set_name(std::string(name));
|
||||
set_width(lsb, msb);
|
||||
}
|
||||
|
||||
BasicPort::BasicPort(const std::string& name, const size_t& lsb, const size_t& msb) {
|
||||
set_name(name);
|
||||
set_width(lsb, msb);
|
||||
}
|
||||
|
||||
BasicPort::BasicPort(const char* name, const size_t& width) {
|
||||
set_name(std::string(name));
|
||||
set_width(width);
|
||||
}
|
||||
|
||||
BasicPort::BasicPort(const std::string& name, const size_t& width) {
|
||||
set_name(name);
|
||||
set_width(width);
|
||||
}
|
||||
|
||||
/* Copy constructor */
|
||||
BasicPort::BasicPort(const BasicPort& basic_port) {
|
||||
set(basic_port);
|
||||
|
@ -59,7 +80,7 @@ void BasicPort::set_name(const std::string& name) {
|
|||
}
|
||||
|
||||
/* set the port LSB and MSB */
|
||||
void BasicPort::set_width(size_t width) {
|
||||
void BasicPort::set_width(const size_t& width) {
|
||||
if (0 == width) {
|
||||
make_invalid();
|
||||
return;
|
||||
|
@ -70,7 +91,7 @@ void BasicPort::set_width(size_t width) {
|
|||
}
|
||||
|
||||
/* set the port LSB and MSB */
|
||||
void BasicPort::set_width(size_t lsb, size_t msb) {
|
||||
void BasicPort::set_width(const size_t& lsb, const size_t& msb) {
|
||||
/* If lsb and msb is invalid, we make a default port */
|
||||
if (lsb > msb) {
|
||||
make_invalid();
|
||||
|
@ -81,18 +102,18 @@ void BasicPort::set_width(size_t lsb, size_t msb) {
|
|||
return;
|
||||
}
|
||||
|
||||
void BasicPort::set_lsb(size_t lsb) {
|
||||
void BasicPort::set_lsb(const size_t& lsb) {
|
||||
lsb_ = lsb;
|
||||
return;
|
||||
}
|
||||
|
||||
void BasicPort::set_msb(size_t msb) {
|
||||
void BasicPort::set_msb(const size_t& msb) {
|
||||
msb_ = msb;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Increase the port width */
|
||||
void BasicPort::expand(size_t width) {
|
||||
void BasicPort::expand(const size_t& width) {
|
||||
if (0 == width) {
|
||||
return; /* ignore zero-width port */
|
||||
}
|
||||
|
@ -114,7 +135,7 @@ void BasicPort::revert() {
|
|||
}
|
||||
|
||||
/* rotate: increase both lsb and msb by an offset */
|
||||
bool BasicPort::rotate(size_t offset) {
|
||||
bool BasicPort::rotate(const size_t& offset) {
|
||||
/* If current port is invalid or offset is 0,
|
||||
* we do nothing
|
||||
*/
|
||||
|
@ -134,7 +155,7 @@ bool BasicPort::rotate(size_t offset) {
|
|||
}
|
||||
|
||||
/* rotate: decrease both lsb and msb by an offset */
|
||||
bool BasicPort::counter_rotate(size_t offset) {
|
||||
bool BasicPort::counter_rotate(const size_t& offset) {
|
||||
/* If current port is invalid or offset is 0,
|
||||
* we do nothing
|
||||
*/
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
class BasicPort {
|
||||
public: /* Constructors */
|
||||
BasicPort();
|
||||
BasicPort(const char* name, const size_t& lsb, const size_t& msb);
|
||||
BasicPort(const char* name, const size_t& width);
|
||||
BasicPort(const std::string& name, const size_t& lsb, const size_t& msb);
|
||||
BasicPort(const std::string& name, const size_t& width);
|
||||
BasicPort(const BasicPort& basic_port); /* Copy constructor */
|
||||
public: /* Accessors */
|
||||
size_t get_width() const; /* get the port width */
|
||||
|
@ -21,14 +25,14 @@ class BasicPort {
|
|||
public: /* Mutators */
|
||||
void set(const BasicPort& basic_port); /* copy */
|
||||
void set_name(const std::string& name); /* set the port LSB and MSB */
|
||||
void set_width(size_t width); /* set the port LSB and MSB */
|
||||
void set_width(size_t lsb, size_t msb); /* set the port LSB and MSB */
|
||||
void set_lsb(size_t lsb);
|
||||
void set_msb(size_t msb);
|
||||
void expand(size_t width); /* Increase the port width */
|
||||
void set_width(const size_t& width); /* set the port LSB and MSB */
|
||||
void set_width(const size_t& lsb, const size_t& msb); /* set the port LSB and MSB */
|
||||
void set_lsb(const size_t& lsb);
|
||||
void set_msb(const size_t& msb);
|
||||
void expand(const size_t& width); /* Increase the port width */
|
||||
void revert(); /* Swap lsb and msb */
|
||||
bool rotate(size_t offset); /* rotate */
|
||||
bool counter_rotate(size_t offset); /* counter rotate */
|
||||
bool rotate(const size_t& offset); /* rotate */
|
||||
bool counter_rotate(const size_t& offset); /* counter rotate */
|
||||
void reset(); /* Reset to initial port */
|
||||
void combine(const BasicPort& port); /* Combine two ports */
|
||||
private: /* internal functions */
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/************************************************
|
||||
* Header file for verilog_submodule_essential.cpp
|
||||
* Include function declaration on
|
||||
* This file includes functions on
|
||||
* outputting Verilog netlists for essential gates
|
||||
* which are inverters, buffers, transmission-gates
|
||||
* logic gates etc.
|
||||
|
@ -17,17 +16,20 @@
|
|||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_submodule_utils.h"
|
||||
#include "verilog_essential_gates.h"
|
||||
|
||||
/************************************************
|
||||
* Print Verilog codes of a power-gated inverter
|
||||
* Print Verilog body codes of a power-gated inverter
|
||||
* This function does NOT generate any port map !
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_power_gated_inv_module(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitPortId& input_port,
|
||||
const CircuitPortId& output_port,
|
||||
const std::vector<CircuitPortId>& power_gate_ports) {
|
||||
void print_verilog_power_gated_invbuf_body(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& input_port,
|
||||
const CircuitPortId& output_port,
|
||||
const std::vector<CircuitPortId>& power_gate_ports) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
|
@ -72,7 +74,21 @@ void print_verilog_power_gated_inv_module(std::fstream& fp,
|
|||
}
|
||||
|
||||
fp << ") begin" << std::endl;
|
||||
fp << "\t\t\tassign " << circuit_lib.port_lib_name(output_port) << "_reg = ~" << circuit_lib.port_lib_name(input_port) << ";" << std::endl;
|
||||
fp << "\t\t\tassign " << circuit_lib.port_lib_name(output_port) << "_reg = ";
|
||||
|
||||
/* Branch on the type of inverter/buffer:
|
||||
* 1. If this is an inverter or an tapered(multi-stage) buffer with odd number of stages,
|
||||
* we invert the input to output
|
||||
* 2. If this is a buffer or an tapere(multi-stage) buffer with even number of stages,
|
||||
* we wire the input to output
|
||||
*/
|
||||
if ( (SPICE_MODEL_BUF_INV == circuit_lib.buffer_type(circuit_model))
|
||||
|| ( (SPICE_MODEL_BUF_INV == circuit_lib.buffer_type(circuit_model))
|
||||
&& (1 == circuit_lib.buffer_num_levels(circuit_model) % 2 ) ) ) {
|
||||
fp << "~";
|
||||
}
|
||||
|
||||
fp << circuit_lib.port_lib_name(input_port) << ";" << std::endl;
|
||||
fp << "\t\tend else begin" << std::endl;
|
||||
fp << "\t\t\tassign " << circuit_lib.port_lib_name(output_port) << "_reg = 1'bz;" << std::endl;
|
||||
fp << "\t\tend" << std::endl;
|
||||
|
@ -80,6 +96,38 @@ void print_verilog_power_gated_inv_module(std::fstream& fp,
|
|||
fp << "\tassign " << circuit_lib.port_lib_name(output_port) << " = " << circuit_lib.port_lib_name(output_port) << "_reg;" << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print Verilog body codes of a regular inverter
|
||||
* This function does NOT generate any port map !
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_invbuf_body(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& input_port,
|
||||
const CircuitPortId& output_port) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << "//----- Verilog codes of a regular inverter -----" << std::endl;
|
||||
|
||||
fp << "\tassign " << circuit_lib.port_lib_name(output_port) << " = (" << circuit_lib.port_lib_name(input_port) << " == 1'bz)? $random : ";
|
||||
|
||||
/* Branch on the type of inverter/buffer:
|
||||
* 1. If this is an inverter or an tapered(multi-stage) buffer with odd number of stages,
|
||||
* we invert the input to output
|
||||
* 2. If this is a buffer or an tapere(multi-stage) buffer with even number of stages,
|
||||
* we wire the input to output
|
||||
*/
|
||||
if ( (SPICE_MODEL_BUF_INV == circuit_lib.buffer_type(circuit_model))
|
||||
|| ( (SPICE_MODEL_BUF_INV == circuit_lib.buffer_type(circuit_model))
|
||||
&& (1 == circuit_lib.buffer_num_levels(circuit_model) % 2 ) ) ) {
|
||||
fp << "~";
|
||||
}
|
||||
|
||||
fp << circuit_lib.port_lib_name(input_port) << ";" << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module of inverter or buffer
|
||||
* or tapered buffer to a file
|
||||
|
@ -158,107 +206,32 @@ void print_verilog_invbuf_module(std::fstream& fp,
|
|||
/* Finish dumping ports */
|
||||
|
||||
/* Assign logics : depending on topology */
|
||||
switch (circuit_lib.buffer_type(circuit_model)) {
|
||||
case SPICE_MODEL_BUF_INV:
|
||||
if (TRUE == circuit_lib.is_power_gated(circuit_model)) {
|
||||
print_verilog_power_gated_inv_module(fp, circuit_lib, input_ports[0], output_ports[0], global_ports);
|
||||
}
|
||||
// } else {
|
||||
// fprintf(fp, "assign %s = (%s === 1'bz)? $random : ~%s;\n",
|
||||
// output_port[0]->lib_name,
|
||||
// input_port[0]->lib_name,
|
||||
// input_port[0]->lib_name);
|
||||
// }
|
||||
break;
|
||||
case SPICE_MODEL_BUF_BUF:
|
||||
// if (TRUE == invbuf_spice_model->design_tech_info.power_gated) {
|
||||
// /* Create a sensitive list */
|
||||
// fprintf(fp, "reg %s_reg;\n", output_port[0]->lib_name);
|
||||
// fprintf(fp, "always @(");
|
||||
// /* Power-gate port first*/
|
||||
// for (iport = 0; iport < num_powergate_port; iport++) {
|
||||
// fprintf(fp, "%s,", powergate_port[iport]->lib_name);
|
||||
// }
|
||||
// fprintf(fp, "%s) begin\n",
|
||||
// input_port[0]->lib_name);
|
||||
// /* Dump the case of power-gated */
|
||||
// fprintf(fp, " if (");
|
||||
// port_cnt = 0; /* Initialize the counter: decide if we need to put down '&&' */
|
||||
// for (iport = 0; iport < num_powergate_port; iport++) {
|
||||
// if (0 == powergate_port[iport]->default_val) {
|
||||
// for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) {
|
||||
// if ( 0 < port_cnt ) {
|
||||
// fprintf(fp, "\n\t&&");
|
||||
// }
|
||||
// /* Power-gated signal are disable during operating, enabled during configuration,
|
||||
// * Therefore, we need to reverse them here
|
||||
// */
|
||||
// fprintf(fp, "(~%s[%d])",
|
||||
// powergate_port[iport]->lib_name,
|
||||
// ipin);
|
||||
// port_cnt++; /* Update port counter*/
|
||||
// }
|
||||
// } else {
|
||||
// assert (1 == powergate_port[iport]->default_val);
|
||||
// for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) {
|
||||
// if ( 0 < port_cnt ) {
|
||||
// fprintf(fp, "\n\t&&");
|
||||
// }
|
||||
// /* Power-gated signal are disable during operating, enabled during configuration,
|
||||
// * Therefore, we need to reverse them here
|
||||
// */
|
||||
// fprintf(fp, "(%s[%d])",
|
||||
// powergate_port[iport]->lib_name,
|
||||
// ipin);
|
||||
// port_cnt++; /* Update port counter*/
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// fprintf(fp, ") begin\n");
|
||||
// fprintf(fp, "\t\tassign %s_reg = %s;\n",
|
||||
// output_port[0]->lib_name,
|
||||
// input_port[0]->lib_name);
|
||||
// fprintf(fp, "\tend else begin\n");
|
||||
// fprintf(fp, "\t\tassign %s_reg = 1'bz;\n",
|
||||
// output_port[0]->lib_name);
|
||||
// fprintf(fp, "\tend\n");
|
||||
// fprintf(fp, "end\n");
|
||||
// fprintf(fp, "assign %s = %s_reg;\n",
|
||||
// output_port[0]->lib_name,
|
||||
// output_port[0]->lib_name);
|
||||
//
|
||||
// } else if (FALSE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf) {
|
||||
// fprintf(fp, "assign %s = (%s === 1'bz)? $random : %s;\n",
|
||||
// output_port[0]->lib_name,
|
||||
// input_port[0]->lib_name,
|
||||
// input_port[0]->lib_name);
|
||||
// } else {
|
||||
// assert (TRUE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf);
|
||||
// fprintf(fp, "assign %s = (%s === 1'bz)? $random : ",
|
||||
// output_port[0]->lib_name,
|
||||
// input_port[0]->lib_name);
|
||||
// /* depend on the stage, we may invert the output */
|
||||
// if (1 == invbuf_spice_model->design_tech_info.buffer_info->tap_buf_level % 2) {
|
||||
// fprintf(fp, "~");
|
||||
// }
|
||||
// fprintf(fp, "%s;\n",
|
||||
// input_port[0]->lib_name);
|
||||
// }
|
||||
break;
|
||||
default:
|
||||
/* Error out for unsupported technology */
|
||||
if ( ( SPICE_MODEL_BUF_INV != circuit_lib.buffer_type(circuit_model))
|
||||
&& ( SPICE_MODEL_BUF_BUF != circuit_lib.buffer_type(circuit_model)) ) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid topology for circuit model (name=%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model));
|
||||
exit(1);
|
||||
}
|
||||
//
|
||||
// /* Print timing info */
|
||||
// dump_verilog_submodule_timing(fp, invbuf_spice_model);
|
||||
//
|
||||
// dump_verilog_submodule_signal_init(fp, invbuf_spice_model);
|
||||
|
||||
if (TRUE == circuit_lib.is_power_gated(circuit_model)) {
|
||||
/* Output Verilog codes for a power-gated inverter */
|
||||
print_verilog_power_gated_invbuf_body(fp, circuit_lib, circuit_model, input_ports[0], output_ports[0], global_ports);
|
||||
} else {
|
||||
/* Output Verilog codes for a regular inverter */
|
||||
print_verilog_invbuf_body(fp, circuit_lib, circuit_model, input_ports[0], output_ports[0]);
|
||||
}
|
||||
|
||||
/* Print timing info */
|
||||
print_verilog_submodule_timing(fp, circuit_lib, circuit_model);
|
||||
|
||||
print_verilog_submodule_signal_init(fp, circuit_lib, circuit_model);
|
||||
|
||||
fp << "endmodule" << std::endl << std::endl;
|
||||
|
||||
fp << "//----- END Verilog module for " << circuit_lib.model_name(circuit_model) << " -----" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,32 +75,20 @@ void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
|||
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 input_port("in", num_inputs);
|
||||
|
||||
BasicPort output_port;
|
||||
/* Configure each input port */
|
||||
output_port.set_name(std::string("out"));
|
||||
output_port.set_width(num_outputs);
|
||||
/* Configure each output port */
|
||||
BasicPort output_port("out", 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);
|
||||
/* Configure each memory port */
|
||||
BasicPort mem_port("mem", num_mems);
|
||||
BasicPort mem_inv_port("mem_inv", num_mems);
|
||||
|
||||
/* TODO: Generate global ports */
|
||||
for (const auto& port : tgate_global_ports) {
|
||||
BasicPort basic_port;
|
||||
/* Configure each input port */
|
||||
basic_port.set_name(circuit_lib.port_prefix(port));
|
||||
basic_port.set_width(circuit_lib.port_size(port));
|
||||
/* Configure each global port */
|
||||
BasicPort basic_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||
/* Print port */
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, basic_port) << "," << std::endl;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/************************************************
|
||||
* This file includes most utilized functions for
|
||||
* generating Verilog sub-modules
|
||||
* such as timing matrix and signal initialization
|
||||
***********************************************/
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Device-level header files */
|
||||
#include "spice_types.h"
|
||||
#include "device_port.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_submodule_utils.h"
|
||||
|
||||
/* All values are printed with this precision value. The higher the
|
||||
* value, the more accurate timing assignment is. Using numeric_limits
|
||||
* max_digits10 guarentees that no values change during a sequence of
|
||||
* float -> string -> float conversions */
|
||||
constexpr int FLOAT_PRECISION = std::numeric_limits<float>::max_digits10;
|
||||
|
||||
/************************************************
|
||||
* Print a timing matrix defined in theecircuit model
|
||||
* into a Verilog format.
|
||||
* This function print all the timing edges available
|
||||
* in the circuit model (any pin-to-pin delay)
|
||||
***********************************************/
|
||||
void print_verilog_submodule_timing(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* return if there is no delay info */
|
||||
if ( 0 == circuit_lib.num_delay_info(circuit_model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Return if there is no ports */
|
||||
if (0 == circuit_lib.num_model_ports(circuit_model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << std::endl;
|
||||
fp << "`ifdef " << verilog_timing_preproc_flag << std::endl;
|
||||
fp << "//------ BEGIN Pin-to-pin Timing constraints -----" << std::endl;
|
||||
fp << "\tspecify" << std::endl;
|
||||
|
||||
/* Read out pin-to-pin delays by finding out all the edges belonging to a circuit model */
|
||||
for (const auto& timing_edge : circuit_lib.timing_edges_by_model(circuit_model)) {
|
||||
CircuitPortId src_port = circuit_lib.timing_edge_src_port(timing_edge);
|
||||
size_t src_pin = circuit_lib.timing_edge_src_pin(timing_edge);
|
||||
BasicPort src_port_info(circuit_lib.port_lib_name(src_port), src_pin, src_pin);
|
||||
|
||||
CircuitPortId sink_port = circuit_lib.timing_edge_sink_port(timing_edge);
|
||||
size_t sink_pin = circuit_lib.timing_edge_sink_pin(timing_edge);
|
||||
BasicPort sink_port_info(circuit_lib.port_lib_name(sink_port), sink_pin, sink_pin);
|
||||
|
||||
fp << "\t\t";
|
||||
fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, src_port_info);
|
||||
fp << " => ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, sink_port_info) << ")";
|
||||
fp << " = ";
|
||||
fp << "(" << std::setprecision(FLOAT_PRECISION) << circuit_lib.timing_edge_delay(timing_edge, SPICE_MODEL_DELAY_RISE);
|
||||
fp << " => ";
|
||||
fp << std::setprecision(FLOAT_PRECISION) << circuit_lib.timing_edge_delay(timing_edge, SPICE_MODEL_DELAY_RISE) << ")";
|
||||
fp << ";" << std::endl;
|
||||
}
|
||||
|
||||
fp << "\tendspecify" << std::endl;
|
||||
fp << "//------ END Pin-to-pin Timing constraints -----" << std::endl;
|
||||
fp << "`endif" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
void print_verilog_submodule_signal_init(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << std::endl;
|
||||
fp << "`ifdef " << verilog_signal_init_preproc_flag << std::endl;
|
||||
fp << "//------ BEGIN driver initialization -----" << std::endl;
|
||||
fp << "\tinitial begin" << std::endl;
|
||||
fp << "\t`ifdef " << verilog_formal_verification_preproc_flag << std::endl;
|
||||
|
||||
/* Only for formal verification: deposite a zero signal values */
|
||||
/* Initialize each input port */
|
||||
for (const auto& input_port : circuit_lib.model_input_ports(circuit_model)) {
|
||||
fp << "\t\t$deposit(" << circuit_lib.port_lib_name(input_port) << ", 1'b0);" << std::endl;
|
||||
}
|
||||
fp << "\t`else" << std::endl;
|
||||
|
||||
/* Regular case: deposite initial signal values: a random value */
|
||||
for (const auto& input_port : circuit_lib.model_input_ports(circuit_model)) {
|
||||
fp << "\t\t$deposit(" << circuit_lib.port_lib_name(input_port) << ", $random);" << std::endl;
|
||||
}
|
||||
|
||||
fp << "\t`endif\n" << std::endl;
|
||||
fp << "\tend" << std::endl;
|
||||
fp << "//------ END driver initialization -----" << std::endl;
|
||||
fp << "`endif" << std::endl;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/************************************************
|
||||
* Header file for verilog_submodule_utils.cpp
|
||||
* Include function declaration on
|
||||
* most utilized functions for Verilog modules
|
||||
* such as timing matrix and signal initialization
|
||||
***********************************************/
|
||||
|
||||
#ifndef VERILOG_SUBMODULE_UTILS_H
|
||||
#define VERILOG_SUBMODULE_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
void print_verilog_submodule_timing(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
void print_verilog_submodule_signal_init(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue