[Tool] Support superLUT circuit model in core engine

This commit is contained in:
tangxifan 2021-02-09 20:23:05 -07:00
parent 7dcc14d73f
commit 6a0f4f354f
8 changed files with 186 additions and 51 deletions

View File

@ -45,8 +45,13 @@ void build_lut_module(ModuleManager& module_manager,
std::vector<CircuitPortId> lut_global_ports = circuit_lib.model_global_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_INPUT, false, true);
/* Get the input ports from the mux */
std::vector<CircuitPortId> lut_input_ports = circuit_lib.model_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_INPUT, true);
/* Find the inputs that drive the internal LUT MUX */
std::vector<CircuitPortId> lut_mux_input_ports = find_lut_circuit_model_input_port(circuit_lib, lut_model, false);
/* Get the output ports from the mux */
std::vector<CircuitPortId> lut_output_ports = circuit_lib.model_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
/* Find the outputs that are driven the internal LUT MUX */
std::vector<CircuitPortId> lut_mux_output_ports = find_lut_circuit_model_output_port(circuit_lib, lut_model, false);
/* Classify SRAM ports into two categories: regular (not for mode select) and mode-select */
std::vector<CircuitPortId> lut_regular_sram_ports = find_circuit_regular_sram_ports(circuit_lib, lut_model);
@ -60,8 +65,8 @@ void build_lut_module(ModuleManager& module_manager,
/* Single-output LUTs:
* We should have only 1 input port, 1 output port and 1 SRAM port
*/
VTR_ASSERT (1 == lut_input_ports.size());
VTR_ASSERT (1 == lut_output_ports.size());
VTR_ASSERT (1 == lut_mux_input_ports.size());
VTR_ASSERT (1 == lut_mux_output_ports.size());
VTR_ASSERT (1 == lut_regular_sram_ports.size());
VTR_ASSERT (0 == lut_mode_select_sram_ports.size());
} else {
@ -70,8 +75,8 @@ void build_lut_module(ModuleManager& module_manager,
* We should have only 1 input port, a few output ports (fracturable outputs)
* and two SRAM ports
*/
VTR_ASSERT (1 == lut_input_ports.size());
VTR_ASSERT (1 <= lut_output_ports.size());
VTR_ASSERT (1 == lut_mux_input_ports.size());
VTR_ASSERT (1 <= lut_mux_output_ports.size());
VTR_ASSERT (1 == lut_regular_sram_ports.size());
VTR_ASSERT ( (0 == lut_mode_select_sram_ports.size())
|| (1 == lut_mode_select_sram_ports.size()));
@ -155,10 +160,10 @@ void build_lut_module(ModuleManager& module_manager,
* +--------------------------------------+
*/
/* Get the tri-state port map for the input ports*/
std::string tri_state_map = circuit_lib.port_tri_state_map(lut_input_ports[0]);
std::string tri_state_map = circuit_lib.port_tri_state_map(lut_mux_input_ports[0]);
size_t mode_select_port_lsb = 0;
for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) {
ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_input_ports[0]));
for (const auto& pin : circuit_lib.pins(lut_mux_input_ports[0])) {
ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_mux_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(lut_module, lut_module_input_port_id));
/* Create a module net for the connection */
@ -200,7 +205,7 @@ void build_lut_module(ModuleManager& module_manager,
required_gate_type = CIRCUIT_MODEL_GATE_OR;
}
/* Get the circuit model of the gate */
CircuitModelId gate_model = circuit_lib.port_tri_state_model(lut_input_ports[0]);
CircuitModelId gate_model = circuit_lib.port_tri_state_model(lut_mux_input_ports[0]);
/* Check this is the gate we want ! */
VTR_ASSERT (required_gate_type == circuit_lib.gate_type(gate_model));
@ -290,7 +295,7 @@ void build_lut_module(ModuleManager& module_manager,
std::vector<ModuleNetId> lut_mux_sram_inv_nets;
/* Now we need to add inverters by instanciating the modules */
for (size_t pin = 0; pin < circuit_lib.port_size(lut_input_ports[0]); ++pin) {
for (size_t pin = 0; pin < circuit_lib.port_size(lut_mux_input_ports[0]); ++pin) {
ModuleNetId lut_mux_sram_inv_net = add_inverter_buffer_child_module_and_nets(module_manager, lut_module,
circuit_lib, input_inverter_model,
mode_selected_nets[pin]);
@ -308,7 +313,7 @@ void build_lut_module(ModuleManager& module_manager,
std::vector<ModuleNetId> lut_mux_sram_nets;
/* Now we need to add inverters by instanciating the modules and add module nets */
for (size_t pin = 0; pin < circuit_lib.port_size(lut_input_ports[0]); ++pin) {
for (size_t pin = 0; pin < circuit_lib.port_size(lut_mux_input_ports[0]); ++pin) {
ModuleNetId lut_mux_sram_net = add_inverter_buffer_child_module_and_nets(module_manager, lut_module,
circuit_lib, input_buffer_model,
mode_selected_nets[pin]);
@ -362,7 +367,7 @@ void build_lut_module(ModuleManager& module_manager,
*/
ModulePortId lut_sram_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_regular_sram_ports[0]));
BasicPort lut_sram_port = module_manager.module_port(lut_module, lut_sram_port_id);
ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_input_ports[0]));
ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_mux_input_ports[0]));
BasicPort lut_mux_input_port = module_manager.module_port(lut_mux_module, lut_mux_input_port_id);
VTR_ASSERT(lut_mux_input_port.get_width() == lut_sram_port.get_width());
/* Wire the port to lut_mux_sram_net */
@ -372,7 +377,7 @@ void build_lut_module(ModuleManager& module_manager,
module_manager.add_module_net_sink(lut_module, net, lut_mux_module, lut_mux_instance, lut_mux_input_port_id, lut_mux_input_port.pins()[pin_id]);
}
for (const auto& port : lut_output_ports) {
for (const auto& port : lut_mux_output_ports) {
ModulePortId lut_output_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(port));
BasicPort lut_output_port = module_manager.module_port(lut_module, lut_output_port_id);
ModulePortId lut_mux_output_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(port));
@ -407,6 +412,11 @@ void build_lut_modules(ModuleManager& module_manager,
if (CIRCUIT_MODEL_LUT != circuit_lib.model_type(lut_model)) {
continue;
}
/* We skip user-defined models */
if ( (false == circuit_lib.model_verilog_netlist(lut_model).empty())
|| (false == circuit_lib.model_spice_netlist(lut_model).empty()) ) {
continue;
}
build_lut_module(module_manager, circuit_lib, lut_model);
}
}

View File

@ -734,8 +734,18 @@ vtr::vector<MuxInputId, ModuleNetId> build_mux_module_input_buffers(ModuleManage
const MuxGraph& mux_graph) {
vtr::vector<MuxInputId, ModuleNetId> mux_input_nets(mux_graph.num_inputs(), ModuleNetId::INVALID());
/* Get the input ports from the mux */
std::vector<CircuitPortId> mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
/* Get the input ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
*/
std::vector<CircuitPortId> mux_input_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_input_ports = find_lut_circuit_model_input_port(circuit_lib, mux_model, false);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
}
/* We should have only 1 input port! */
VTR_ASSERT(1 == mux_input_ports.size());
@ -849,8 +859,18 @@ vtr::vector<MuxOutputId, ModuleNetId> build_mux_module_output_buffers(ModuleMana
/* Create module nets for output ports */
vtr::vector<MuxOutputId, ModuleNetId> mux_output_nets(mux_graph.num_outputs(), ModuleNetId::INVALID());
/* Get the output ports from the mux */
std::vector<CircuitPortId> mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
/* Get the output ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
* - LUT may have global output ports that are wired directly to top-level module
*/
std::vector<CircuitPortId> mux_output_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_output_ports = find_lut_circuit_model_output_port(circuit_lib, mux_model, false, false);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
}
/* Iterate over all the outputs in the MUX module */
for (const auto& output_port : mux_output_ports) {
@ -1096,10 +1116,32 @@ void build_cmos_mux_module(ModuleManager& module_manager,
const MuxGraph& mux_graph) {
/* Get the global ports required by MUX (and any submodules) */
std::vector<CircuitPortId> mux_global_ports = circuit_lib.model_global_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
/* Get the input ports from the mux */
std::vector<CircuitPortId> mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
/* Get the output ports from the mux */
std::vector<CircuitPortId> mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
/* Get the input ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
*/
std::vector<CircuitPortId> mux_input_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_input_ports = find_lut_circuit_model_input_port(circuit_lib, mux_model, false);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
}
/* Get the output ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
* - LUT may have global output ports that are wired directly to top-level module
*/
std::vector<CircuitPortId> mux_output_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_output_ports = find_lut_circuit_model_output_port(circuit_lib, mux_model, false, false);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
}
/* Get the sram ports from the mux
* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
* Here we just bypass it.

View File

@ -407,7 +407,7 @@ void build_lut_bitstream(BitstreamManager& bitstream_manager,
VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(lut_model));
/* Find the input ports for LUT size, this is used to decode the LUT memory bits! */
std::vector<CircuitPortId> model_input_ports = circuit_lib.model_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> model_input_ports = find_lut_circuit_model_input_port(circuit_lib, lut_model, false);
VTR_ASSERT(1 == model_input_ports.size());
size_t lut_size = circuit_lib.port_size(model_input_ports[0]);

View File

@ -89,7 +89,9 @@ int print_sdc_disable_lut_configure_ports(std::fstream& fp,
}
const std::string& sram_inv_port_name = circuit_lib.port_lib_name(sram_port) + INV_PORT_POSTFIX;
VTR_ASSERT(true == module_manager.valid_module_port_id(programmable_module, module_manager.find_module_port(programmable_module, sram_inv_port_name)));
if (false == module_manager.valid_module_port_id(programmable_module, module_manager.find_module_port(programmable_module, sram_inv_port_name))) {
continue;
}
if (CMD_EXEC_FATAL_ERROR ==
rec_print_sdc_disable_timing_for_module_ports(fp,
flatten_names,

View File

@ -11,6 +11,7 @@
/* Headers from readarchopenfpga library */
#include "circuit_types.h"
#include "circuit_library.h"
#include "circuit_library_utils.h"
#include "mux_utils.h"
#include "pb_type_utils.h"
@ -182,7 +183,7 @@ void build_lut_mux_library(MuxLibrary& mux_lib,
}
/* Find the MUX size required by the LUT */
/* Get input ports which are not global ports! */
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> input_ports = find_lut_circuit_model_input_port(circuit_lib, circuit_model, false);
VTR_ASSERT(1 == input_ports.size());
/* MUX size = 2^lut_size */
size_t lut_mux_size = (size_t)pow(2., (double)(circuit_lib.port_size(input_ports[0])));

View File

@ -50,26 +50,33 @@ static
std::vector<int> generate_lut_rotated_input_pin_map(const std::vector<AtomNetId>& input_nets,
const AtomContext& atom_ctx,
const AtomBlockId& atom_blk,
const VprDeviceAnnotation& device_annotation,
const CircuitLibrary& circuit_lib,
const t_pb_graph_node* pb_graph_node) {
/* Find the pin rotation status and record it ,
* Note that some LUT inputs may not be used, we set them to be open by default
*/
std::vector<int> rotated_pin_map(input_nets.size(), -1);
VTR_ASSERT(1 == pb_graph_node->num_input_ports);
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
/* Skip the input pin that do not drive by LUT MUXes */
CircuitPortId circuit_port = device_annotation.pb_circuit_port(pb_graph_node->input_pins[iport][ipin].port);
if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) {
continue;
}
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[0]; ++ipin) {
/* The lut pb_graph_node may not be the primitive node
* because VPR adds two default modes to its LUT pb_type
* If so, we will use the LUT mode of the pb_graph node
*/
t_port* lut_pb_type_in_port = pb_graph_node->input_pins[0][ipin].port;
t_port* lut_pb_type_in_port = pb_graph_node->input_pins[iport][ipin].port;
if (0 != pb_graph_node->pb_type->num_modes) {
VTR_ASSERT(2 == pb_graph_node->pb_type->num_modes);
VTR_ASSERT(1 == pb_graph_node->pb_type->modes[VPR_PB_TYPE_LUT_MODE].num_pb_type_children);
lut_pb_type_in_port = &(pb_graph_node->pb_type->modes[VPR_PB_TYPE_LUT_MODE].pb_type_children[0].ports[0]);
VTR_ASSERT(std::string(lut_pb_type_in_port->name) == std::string(pb_graph_node->input_pins[0][ipin].port->name));
VTR_ASSERT(lut_pb_type_in_port->num_pins == pb_graph_node->input_pins[0][ipin].port->num_pins);
lut_pb_type_in_port = &(pb_graph_node->pb_type->modes[VPR_PB_TYPE_LUT_MODE].pb_type_children[0].ports[iport]);
VTR_ASSERT(std::string(lut_pb_type_in_port->name) == std::string(pb_graph_node->input_pins[iport][ipin].port->name));
VTR_ASSERT(lut_pb_type_in_port->num_pins == pb_graph_node->input_pins[iport][ipin].port->num_pins);
}
/* Port exists (some LUTs may have no input and hence no port in the atom netlist) */
@ -86,6 +93,7 @@ std::vector<int> generate_lut_rotated_input_pin_map(const std::vector<AtomNetId>
}
}
}
}
return rotated_pin_map;
}
@ -109,15 +117,27 @@ void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb,
/* Find all the nets mapped to each inputs */
std::vector<AtomNetId> input_nets;
VTR_ASSERT(1 == pb_graph_node->num_input_ports);
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[0]; ++ipin) {
input_nets.push_back(physical_pb.pb_graph_pin_atom_net(lut_pb_id, &(pb_graph_node->input_pins[0][ipin])));
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
/* Skip the input pin that do not drive by LUT MUXes */
CircuitPortId circuit_port = device_annotation.pb_circuit_port(pb_graph_node->input_pins[iport][ipin].port);
if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) {
continue;
}
input_nets.push_back(physical_pb.pb_graph_pin_atom_net(lut_pb_id, &(pb_graph_node->input_pins[iport][ipin])));
}
}
/* Find all the nets mapped to each outputs */
for (int iport = 0; iport < pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_output_pins[iport]; ++ipin) {
const t_pb_graph_pin* output_pin = &(pb_graph_node->output_pins[iport][ipin]);
/* Skip the output ports that are not driven by LUT MUXes */
CircuitPortId circuit_port = device_annotation.pb_circuit_port(output_pin->port);
if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) {
continue;
}
AtomNetId output_net = physical_pb.pb_graph_pin_atom_net(lut_pb_id, output_pin);
/* Bypass unmapped pins */
if (AtomNetId::INVALID() == output_net) {
@ -135,7 +155,7 @@ void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb,
VTR_ASSERT(true == atom_ctx.nlist.valid_block_id(atom_blk));
const AtomNetlist::TruthTable& orig_tt = atom_ctx.nlist.block_truth_table(atom_blk);
std::vector<int> rotated_pin_map = generate_lut_rotated_input_pin_map(input_nets, atom_ctx, atom_blk, pb_graph_node);
std::vector<int> rotated_pin_map = generate_lut_rotated_input_pin_map(input_nets, atom_ctx, atom_blk, device_annotation, circuit_lib, pb_graph_node);
adapt_tt = lut_truth_table_adaption(orig_tt, rotated_pin_map);
}

View File

@ -368,4 +368,54 @@ CircuitPortId find_circuit_model_power_gate_enb_port(const CircuitLibrary& circu
return enb_port;
}
/************************************************************************
* Try to find the input ports for a LUT circuit model (EXCLUDE the global ports)
* which can optionally include those ports drives or is driven by hard logic
***********************************************************************/
std::vector<CircuitPortId> find_lut_circuit_model_input_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port) {
VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model));
std::vector<CircuitPortId> input_ports;
/* Find all the non-global input ports */
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, !include_global_port)) {
/* Skip harden ports if specified */
if ( (true == circuit_lib.port_is_harden_lut_port(port))
&& (false == include_harden_port)) {
continue;
}
input_ports.push_back(port);
}
return input_ports;
}
/************************************************************************
* Try to find the output ports for a LUT circuit model (EXCLUDE the global ports)
* which can optionally include those ports drives or is driven by hard logic
***********************************************************************/
std::vector<CircuitPortId> find_lut_circuit_model_output_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port) {
VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model));
std::vector<CircuitPortId> output_ports;
/* Find all the non-global input ports */
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, !include_global_port)) {
/* Skip harden ports if specified */
if ( (true == circuit_lib.port_is_harden_lut_port(port))
&& (false == include_harden_port)) {
continue;
}
output_ports.push_back(port);
}
return output_ports;
}
} /* end namespace openfpga */

View File

@ -51,6 +51,16 @@ CircuitPortId find_circuit_model_power_gate_en_port(const CircuitLibrary& circui
CircuitPortId find_circuit_model_power_gate_enb_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model);
std::vector<CircuitPortId> find_lut_circuit_model_input_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port = true);
std::vector<CircuitPortId> find_lut_circuit_model_output_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port = true);
} /* end namespace openfpga */
#endif