complete refacotriing the inv and buf part in submodules

This commit is contained in:
tangxifan 2019-08-21 14:54:05 -06:00
parent a40e5c91ca
commit 9c43b1b753
10 changed files with 381 additions and 148 deletions

View File

@ -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**

View File

@ -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.

View File

@ -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));

View File

@ -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_;

View File

@ -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
*/

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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