From 81093f0db6722c2a9a4f5215f2034e53d11d42e6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 21 Oct 2019 17:54:15 -0600 Subject: [PATCH] add lut module generation and simplify Verilog generation codes --- .../module_builder/build_lut_modules.cpp | 402 ++++++++++++++++++ .../module_builder/build_lut_modules.h | 13 + .../module_builder/build_module_graph.cpp | 4 +- .../build_module_graph_utils.cpp | 82 ++++ .../module_builder/build_module_graph_utils.h | 22 + .../vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp | 327 +------------- 6 files changed, 530 insertions(+), 320 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.h create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.h diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp new file mode 100644 index 000000000..c7057712b --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.cpp @@ -0,0 +1,402 @@ +/******************************************************************** + * This file include functions that create modules for + * the Look-Up Tables (LUTs) + ********************************************************************/ +#include +#include + +#include "vtr_assert.h" +#include "util.h" +#include "spice_types.h" + +#include "fpga_x2p_naming.h" +#include "circuit_library_utils.h" +#include "module_manager.h" +#include "module_manager_utils.h" + +#include "build_module_graph_utils.h" +#include "build_lut_modules.h" + +/******************************************************************** + * Build a module for a LUT circuit model + * This function supports both single-output and fracturable LUTs + * The module will be organized in a connected graph of the following instances: + * 1. Multiplexer used inside LUT + * 2. Input buffers + * 3. Input inverters + * 4. Output buffers. + * 6. AND/OR gates to tri-state LUT inputs + ********************************************************************/ +static +void build_lut_module(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const CircuitModelId& lut_model) { + /* Get the global ports required by LUT + * Note that this function will only add global ports from LUT circuit model definition itself + * We should NOT go recursively here. + * The global ports of sub module will be handled by another function !!! + * add_module_global_ports_from_child_modules(module_manager, lut_module); + */ + std::vector lut_global_ports = circuit_lib.model_global_ports_by_type(lut_model, SPICE_MODEL_PORT_INPUT, false, true); + /* Get the input ports from the mux */ + std::vector lut_input_ports = circuit_lib.model_ports_by_type(lut_model, SPICE_MODEL_PORT_INPUT, true); + /* Get the output ports from the mux */ + std::vector lut_output_ports = circuit_lib.model_ports_by_type(lut_model, SPICE_MODEL_PORT_OUTPUT, true); + + /* Classify SRAM ports into two categories: regular (not for mode select) and mode-select */ + std::vector lut_regular_sram_ports = find_circuit_regular_sram_ports(circuit_lib, lut_model); + std::vector lut_mode_select_sram_ports = find_circuit_mode_select_sram_ports(circuit_lib, lut_model); + + /*********************************************** + * Model Port Sanity Check + ***********************************************/ + /* Make sure that the number of ports and sizes of ports are what we want */ + if (false == circuit_lib.is_lut_fracturable(lut_model)) { + /* 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_regular_sram_ports.size()); + VTR_ASSERT (0 == lut_mode_select_sram_ports.size()); + } else { + VTR_ASSERT (true == circuit_lib.is_lut_fracturable(lut_model)); + /* Fracturable LUT: + * 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_regular_sram_ports.size()); + VTR_ASSERT (1 == lut_mode_select_sram_ports.size()); + } + + /*********************************************** + * Module Port addition + ***********************************************/ + /* Create a Verilog Module based on the circuit model, and add to module manager */ + ModuleId lut_module = module_manager.add_module(circuit_lib.model_name(lut_model)); + VTR_ASSERT(true == module_manager.valid_module_id(lut_module)); + /* Add module ports */ + /* Add each global port */ + for (const auto& port : lut_global_ports) { + /* Configure each global port */ + BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + module_manager.add_port(lut_module, global_port, ModuleManager::MODULE_GLOBAL_PORT); + } + /* Add each input port */ + for (const auto& port : lut_input_ports) { + BasicPort input_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + module_manager.add_port(lut_module, input_port, ModuleManager::MODULE_INPUT_PORT); + /* Set the port to be wire-connection */ + module_manager.set_port_is_wire(lut_module, input_port.get_name(), true); + } + /* Add each output port */ + for (const auto& port : lut_output_ports) { + BasicPort output_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + module_manager.add_port(lut_module, output_port, ModuleManager::MODULE_OUTPUT_PORT); + /* Set the port to be wire-connection */ + module_manager.set_port_is_wire(lut_module, output_port.get_name(), true); + } + /* Add each regular (not mode select) SRAM port */ + for (const auto& port : lut_regular_sram_ports) { + BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + module_manager.add_port(lut_module, mem_port, ModuleManager::MODULE_INPUT_PORT); + BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port)); + module_manager.add_port(lut_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT); + } + + /* Add each mode-select SRAM port */ + for (const auto& port : lut_mode_select_sram_ports) { + BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); + module_manager.add_port(lut_module, mem_port, ModuleManager::MODULE_INPUT_PORT); + BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port)); + module_manager.add_port(lut_module, mem_inv_port, ModuleManager::MODULE_INPUT_PORT); + } + + /*********************************************** + * Child module addition: Model-select gates + ***********************************************/ + /* Module nets after the mode-selection circuit, this could include LUT inputs */ + std::vector mode_selected_nets; + /* Instanciate mode selecting circuit: AND/OR gate + * By following the tri-state map of LUT input port + * The wiring of input ports will be organized as follows + * + * LUT input + * | + * v + * +----------+ + * | mode | + * | selector | + * +----------+ + * | mode_selected_nets + * v + * +-----------------+------------+ + * | | + * v v + * +----------+ +---------+ + * | Inverter | | Buffer | + * +----------+ +---------+ + * | inverter_output_net | buffered_output_net + * v v + * +--------------------------------------+ + * | LUT Multiplexing Structure | + * +--------------------------------------+ + */ + /* 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]); + 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_lib_name(lut_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 */ + ModuleNetId net = module_manager.create_module_net(lut_module); + /* Set the source of the net to an lut input port */ + module_manager.add_module_net_source(lut_module, net, lut_module, 0, lut_module_input_port_id, pin); + + /* For an empty tri-state map or a '-' sign in tri-state map, we can short-wire mode select_output_ports */ + if (tri_state_map.empty() || ('-' == tri_state_map[pin]) ) { + /* Update the output nets of the mode-select layer */ + mode_selected_nets.push_back(net); + continue; /* Finish here */ + } + + e_spice_model_gate_type required_gate_type = NUM_SPICE_MODEL_GATE_TYPES; + /* Reach here, it means that we need a circuit for mode selection */ + if ('0' == tri_state_map[pin]) { + /* We need a 2-input AND gate, in order to tri-state the input + * Detailed circuit is as follow: + * +---------+ + * SRAM --->| 2-input |----> mode_select_output_port + * LUT input--->| AND | + * +---------+ + * When SRAM is set to logic 0, the LUT input is tri-stated + * When SRAM is set to logic 1, the LUT input is effective to the downstream circuits + */ + required_gate_type = SPICE_MODEL_GATE_AND; + } else { + VTR_ASSERT ('1' == tri_state_map[pin]); + /* We need a 2-input OR gate, in order to tri-state the input + * Detailed circuit is as follow: + * +---------+ + * SRAM --->| 2-input |----> mode_select_output_port + * LUT input--->| OR | + * +---------+ + * When SRAM is set to logic 1, the LUT input is tri-stated + * When SRAM is set to logic 0, the LUT input is effective to the downstream circuits + */ + required_gate_type = SPICE_MODEL_GATE_OR; + } + /* Get the circuit model of the gate */ + CircuitModelId gate_model = circuit_lib.port_tri_state_model(lut_input_ports[0]); + /* Check this is the gate we want ! */ + VTR_ASSERT (required_gate_type == circuit_lib.gate_type(gate_model)); + + /* Prepare for the gate instanciation */ + /* Get the input ports from the gate */ + std::vector gate_input_ports = circuit_lib.model_ports_by_type(gate_model, SPICE_MODEL_PORT_INPUT, true); + /* Get the output ports from the gate */ + std::vector gate_output_ports = circuit_lib.model_ports_by_type(gate_model, SPICE_MODEL_PORT_OUTPUT, true); + /* Check the port sizes and width: + * we should have only 2 input ports, each of which has a size of 1 + * we should have only 1 output port, each of which has a size of 1 + */ + VTR_ASSERT (2 == gate_input_ports.size()); + VTR_ASSERT (1 == gate_output_ports.size()); + /* Find the module id of gate_model in the module manager */ + ModuleId gate_module = module_manager.find_module(circuit_lib.model_name(gate_model)); + /* We must have a valid id */ + VTR_ASSERT (true == module_manager.valid_module_id(gate_module)); + size_t gate_instance = module_manager.num_instance(lut_module, gate_module); + module_manager.add_child_module(lut_module, gate_module); + + /* Create a port-to-port net connection: + * Input[0] of the gate is wired to a SRAM mode-select port + * Input[1] of the gate is wired to the input port of LUT + * Output[0] of the gate is wired to the mode_select_output_port + */ + /* Create a module net for the connection */ + ModuleNetId gate_sram_net = module_manager.create_module_net(lut_module); + + /* Find the module port id of the SRAM port of LUT module */ + ModulePortId lut_module_mode_select_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(lut_mode_select_sram_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id(lut_module, lut_module_mode_select_port_id)); + /* Set the source of the net to an mode-select SRAM port of the LUT module */ + module_manager.add_module_net_source(lut_module, gate_sram_net, lut_module, 0, lut_module_mode_select_port_id, mode_select_port_lsb); + + /* Find the module port id of the SRAM port of LUT module */ + ModulePortId gate_module_input0_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_input_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_input0_port_id)); + /* Set the sink of the net to an input[0] port of the gate module */ + VTR_ASSERT(1 == module_manager.module_port(gate_module, gate_module_input0_port_id).get_width()); + for (const size_t& gate_pin : module_manager.module_port(gate_module, gate_module_input0_port_id).pins()) { + module_manager.add_module_net_sink(lut_module, gate_sram_net, gate_module, gate_instance, gate_module_input0_port_id, gate_pin); + } + + /* Use the existing net to connect to the input[1] port of the gate module */ + ModulePortId gate_module_input1_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_input_ports[1])); + VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_input1_port_id)); + VTR_ASSERT(1 == module_manager.module_port(gate_module, gate_module_input1_port_id).get_width()); + for (const size_t& gate_pin : module_manager.module_port(gate_module, gate_module_input1_port_id).pins()) { + module_manager.add_module_net_sink(lut_module, net, gate_module, gate_instance, gate_module_input1_port_id, gate_pin); + } + + /* Create a module net for the output connection */ + ModuleNetId gate_output_net = module_manager.create_module_net(lut_module); + ModulePortId gate_module_output_port_id = module_manager.find_module_port(gate_module, circuit_lib.port_lib_name(gate_output_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id(gate_module, gate_module_output_port_id)); + BasicPort gate_module_output_port = module_manager.module_port(gate_module, gate_module_output_port_id); + VTR_ASSERT(1 == gate_module_output_port.get_width()); + module_manager.add_module_net_source(lut_module, gate_output_net, gate_module, gate_instance, gate_module_output_port_id, gate_module_output_port.get_lsb()); + + /* Update the output nets of the mode-select layer */ + mode_selected_nets.push_back(gate_output_net); + + /* update the lsb of mode select port size */ + mode_select_port_lsb++; + } + + /* Sanitity check */ + if ( true == circuit_lib.is_lut_fracturable(lut_model) ) { + if (mode_select_port_lsb != circuit_lib.port_size(lut_mode_select_sram_ports[0])) { + vpr_printf(TIO_MESSAGE_ERROR, + "(FILE:%s,LINE[%d]) Circuit model LUT (name=%s) has a unmatched tri-state map (%s) implied by mode_port size(%d)!\n", + __FILE__, __LINE__, + circuit_lib.model_name(lut_model).c_str(), + tri_state_map.c_str(), + circuit_lib.port_size(lut_mode_select_sram_ports[0])); + exit(1); + } + } + + /*********************************************** + * Child module addition: Input inverters + ***********************************************/ + /* Find the circuit model of the input inverter */ + CircuitModelId input_inverter_model = circuit_lib.lut_input_inverter_model(lut_model); + VTR_ASSERT( CircuitModelId::INVALID() != input_inverter_model ); + + std::vector 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) { + 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]); + /* Update the net vector */ + lut_mux_sram_inv_nets.push_back(lut_mux_sram_inv_net); + } + + /*********************************************** + * Child module addition: Input buffers + ***********************************************/ + /* Add buffers to mode_select output ports */ + /* Find the circuit model of the input inverter */ + CircuitModelId input_buffer_model = circuit_lib.lut_input_buffer_model(lut_model); + VTR_ASSERT( CircuitModelId::INVALID() != input_buffer_model ); + + std::vector 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) { + 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]); + /* Update the net vector */ + lut_mux_sram_nets.push_back(lut_mux_sram_net); + } + + /*********************************************** + * Child module addition: LUT MUX + ***********************************************/ + /* Find the name of LUT MUX: no need to provide a mux size, just give an invalid number (=-1) */ + std::string lut_mux_module_name = generate_mux_subckt_name(circuit_lib, lut_model, size_t(-1), std::string("")); + /* Find the module id of LUT MUX in the module manager */ + ModuleId lut_mux_module = module_manager.find_module(lut_mux_module_name); + /* We must have a valid id */ + VTR_ASSERT (ModuleId::INVALID() != lut_mux_module); + /* Instanciate a LUT MUX as child module */ + size_t lut_mux_instance = module_manager.num_instance(lut_module, lut_mux_module); + module_manager.add_child_module(lut_module, lut_mux_module); + + /* TODO: Build module nets to connect + * 1. SRAM ports of LUT MUX module to output ports of input buffer + * 2. Inverted SRAM ports of LUT MUX module to output ports of input inverters + * 3. Data input of LUT MUX module to SRAM port of LUT + * 4. Data output of LUT MUX module to output ports of LUT + */ + ModulePortId lut_mux_sram_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_lib_name(lut_regular_sram_ports[0])); + BasicPort lut_mux_sram_port = module_manager.module_port(lut_mux_module, lut_mux_sram_port_id); + VTR_ASSERT(lut_mux_sram_port.get_width() == lut_mux_sram_nets.size()); + /* Wire the port to lut_mux_sram_net */ + for (const size_t& pin : lut_mux_sram_port.pins()) { + module_manager.add_module_net_sink(lut_module, lut_mux_sram_nets[pin], lut_mux_module, lut_mux_instance, lut_mux_sram_port_id, pin); + } + + ModulePortId lut_mux_sram_inv_port_id = module_manager.find_module_port(lut_mux_module, std::string(circuit_lib.port_lib_name(lut_regular_sram_ports[0]) + "_inv")); + BasicPort lut_mux_sram_inv_port = module_manager.module_port(lut_mux_module, lut_mux_sram_inv_port_id); + VTR_ASSERT(lut_mux_sram_inv_port.get_width() == lut_mux_sram_inv_nets.size()); + /* Wire the port to lut_mux_sram_net */ + for (const size_t& pin : lut_mux_sram_inv_port.pins()) { + module_manager.add_module_net_sink(lut_module, lut_mux_sram_inv_nets[pin], lut_mux_module, lut_mux_instance, lut_mux_sram_inv_port_id, pin); + } + + /* lut_module + * +------------ + * | +------ + * sram -->|---->| (lut_mux_input_port) + * | ^ | LUT MUX + * | | | + * | + * net + */ + ModulePortId lut_sram_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(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_lib_name(lut_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 */ + for (size_t pin_id = 0; pin_id < lut_mux_input_port.pins().size(); ++pin_id) { + ModuleNetId net = module_manager.create_module_net(lut_module); + module_manager.add_module_net_source(lut_module, net, lut_module, 0, lut_sram_port_id, lut_sram_port.pins()[pin_id]); + 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) { + ModulePortId lut_output_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_lib_name(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_lib_name(port)); + BasicPort lut_mux_output_port = module_manager.module_port(lut_mux_module, lut_mux_output_port_id); + VTR_ASSERT(lut_mux_output_port.get_width() == lut_output_port.get_width()); + /* Wire the port to lut_mux_sram_net */ + for (size_t pin_id = 0; pin_id < lut_output_port.pins().size(); ++pin_id) { + ModuleNetId net = module_manager.create_module_net(lut_module); + module_manager.add_module_net_source(lut_module, net, lut_mux_module, lut_mux_instance, lut_mux_output_port_id, lut_mux_output_port.pins()[pin_id]); + module_manager.add_module_net_sink(lut_module, net, lut_module, 0, lut_output_port_id, lut_output_port.pins()[pin_id]); + } + } + + /* Add global ports to the pb_module: + * This is a much easier job after adding sub modules (instances), + * we just need to find all the global ports from the child modules and build a list of it + */ + add_module_global_ports_from_child_modules(module_manager, lut_module); +} + +/******************************************************************** + * Print Verilog modules for the Look-Up Tables (LUTs) + * in the circuit library + ********************************************************************/ +void build_lut_modules(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib) { + + /* Search for each LUT circuit model */ + for (const auto& lut_model : circuit_lib.models()) { + /* Bypas non-LUT modules */ + if (SPICE_MODEL_LUT != circuit_lib.model_type(lut_model)) { + continue; + } + build_lut_module(module_manager, circuit_lib, lut_model); + } +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.h new file mode 100644 index 000000000..68990d2cc --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_lut_modules.h @@ -0,0 +1,13 @@ +/******************************************************************** + * Header file for build_lut_modules.cpp + ********************************************************************/ +#ifndef BUILD_LUT_MODULES_H +#define BUILD_LUT_MODULES_H + +#include "circuit_library.h" +#include "module_manager.h" + +void build_lut_modules(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp index c97f031ba..36b23e401 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph.cpp @@ -13,6 +13,7 @@ #include "build_essential_modules.h" #include "build_decoder_modules.h" #include "build_mux_modules.h" +#include "build_lut_modules.h" #include "build_module_graph.h" /******************************************************************** @@ -86,7 +87,8 @@ ModuleManager build_device_module_graph(const t_vpr_setup& vpr_setup, /* Build multiplexer modules */ build_mux_modules(module_manager, mux_lib, arch.spice->circuit_lib); - /* TODO: Build LUT modules */ + /* Build LUT modules */ + build_lut_modules(module_manager, arch.spice->circuit_lib); /* TODO: Build wire modules */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp new file mode 100644 index 000000000..6b1df195a --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.cpp @@ -0,0 +1,82 @@ +/******************************************************************** + * This file includes most utilized functions that are used to + * build module graphs + ********************************************************************/ +#include +#include "vtr_assert.h" + +#include "build_module_graph_utils.h" + +/******************************************************************** + * Find input port of a buffer/inverter module + ********************************************************************/ +ModulePortId find_inverter_buffer_module_port(const ModuleManager& module_manager, + const ModuleId& module_id, + const CircuitLibrary& circuit_lib, + const CircuitModelId& model_id, + const e_spice_model_port_type& port_type) { + /* We must have a valid module id */ + VTR_ASSERT(true == module_manager.valid_module_id(module_id)); + /* Check the type of model */ + VTR_ASSERT(SPICE_MODEL_INVBUF == circuit_lib.model_type(model_id)); + + /* Add module nets to wire to the buffer module */ + /* To match the context, Buffer should have only 2 non-global ports: 1 input port and 1 output port */ + std::vector model_ports = circuit_lib.model_ports_by_type(model_id, port_type, true); + VTR_ASSERT(1 == model_ports.size()); + + /* Find the input and output module ports */ + ModulePortId module_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(model_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id(module_id, module_port_id)); + + return module_port_id; +} + +/******************************************************************** + * Add inverter/buffer module to a parent module + * and complete the wiring to the input port of inverter/buffer + * This function will return the wire created for the output port of inverter/buffer + * + * parent_module + * +----------------------------------------------------------------- + * | + * | input_net output_net + * | | | + * | v +---------------+ v + * | src_module_port --------->| child_module |--------> + * | +---------------+ + * + ********************************************************************/ +ModuleNetId add_inverter_buffer_child_module_and_nets(ModuleManager& module_manager, + const ModuleId& parent_module, + const CircuitLibrary& circuit_lib, + const CircuitModelId& model_id, + const ModuleNetId& input_net) { + /* We must have a valid module id */ + VTR_ASSERT(true == module_manager.valid_module_id(parent_module)); + + std::string module_name = circuit_lib.model_name(model_id); + ModuleId child_module = module_manager.find_module(module_name); + VTR_ASSERT(true == module_manager.valid_module_id(child_module)); + + ModulePortId module_input_port_id = find_inverter_buffer_module_port(module_manager, child_module, circuit_lib, model_id, SPICE_MODEL_PORT_INPUT); + ModulePortId module_output_port_id = find_inverter_buffer_module_port(module_manager, child_module, circuit_lib, model_id, SPICE_MODEL_PORT_OUTPUT); + + /* Port size should be 1 ! */ + VTR_ASSERT(1 == module_manager.module_port(child_module, module_input_port_id).get_width()); + VTR_ASSERT(1 == module_manager.module_port(child_module, module_output_port_id).get_width()); + + /* Instanciate a child module */ + size_t child_instance = module_manager.num_instance(parent_module, child_module); + module_manager.add_child_module(parent_module, child_module); + + /* Use the net to connect to the input net of buffer */ + module_manager.add_module_net_sink(parent_module, input_net, child_module, child_instance, module_input_port_id, 0); + + /* Create a net to bridge the input inverter and LUT MUX */ + ModuleNetId output_net = module_manager.create_module_net(parent_module); + module_manager.add_module_net_source(parent_module, output_net, child_module, child_instance, module_output_port_id, 0); + + return output_net; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.h new file mode 100644 index 000000000..e5b3de2ca --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/module_builder/build_module_graph_utils.h @@ -0,0 +1,22 @@ +/******************************************************************** + * Header file for build_module_graph_utils.cpp + ********************************************************************/ +#ifndef BUILD_MODULE_GRAPH_UTILS_H +#define BUILD_MODULE_GRAPH_UTILS_H + +#include "module_manager.h" +#include "circuit_library.h" + +ModulePortId find_inverter_buffer_module_port(const ModuleManager& module_manager, + const ModuleId& module_id, + const CircuitLibrary& circuit_lib, + const CircuitModelId& model_id, + const e_spice_model_port_type& port_type); + +ModuleNetId add_inverter_buffer_child_module_and_nets(ModuleManager& module_manager, + const ModuleId& parent_module, + const CircuitLibrary& circuit_lib, + const CircuitModelId& model_id, + const ModuleNetId& input_net); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp index 50f924c32..b5fa63060 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp @@ -20,324 +20,10 @@ #include "fpga_x2p_utils.h" /* FPGA-Verilog context header files */ -#include "verilog_global.h" #include "verilog_writer_utils.h" -#include "verilog_submodule_utils.h" +#include "verilog_module_writer.h" #include "verilog_lut.h" -/******************************************************************** - * Print a Verilog module for a LUT circuit model - * This function supports both single-output and fracturable LUTs - * The Verilog module will be organized in structural Verilog codes. - * It will instanciate: - * 1. Multiplexer used inside LUT - * 2. Input buffers - * 3. Input inverters - * 4. Output buffers. - * 6. AND/OR gates to tri-state LUT inputs - ********************************************************************/ -static -void print_verilog_submodule_lut(ModuleManager& module_manager, - const CircuitLibrary& circuit_lib, - std::fstream& fp, - const CircuitModelId& circuit_model) { - /* Ensure a valid file handler*/ - check_file_handler(fp); - - /* Get the global ports required by MUX (and any submodules) */ - std::vector lut_global_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true, true); - /* Get the input ports from the mux */ - std::vector lut_input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true); - /* Get the output ports from the mux */ - std::vector lut_output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true); - - /* Classify SRAM ports into two categories: regular (not for mode select) and mode-select */ - std::vector lut_regular_sram_ports; - std::vector lut_mode_select_sram_ports; - - { /* Create a code block to keep some variables in local */ - /* Get the sram ports from the mux */ - std::vector lut_sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true); - for (const auto& port : lut_sram_ports) { - /* Bypass mode_select ports */ - if (true == circuit_lib.port_is_mode_select(port)) { - lut_mode_select_sram_ports.push_back(port); - continue; - } - VTR_ASSERT_SAFE (false == circuit_lib.port_is_mode_select(port)); - lut_regular_sram_ports.push_back(port); - } - } - - /* Make sure that the number of ports and sizes of ports are what we want */ - if (false == circuit_lib.is_lut_fracturable(circuit_model)) { - /* 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_regular_sram_ports.size()); - VTR_ASSERT (0 == lut_mode_select_sram_ports.size()); - } else { - VTR_ASSERT (true == circuit_lib.is_lut_fracturable(circuit_model)); - /* Fracturable LUT: - * 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_regular_sram_ports.size()); - VTR_ASSERT (1 == lut_mode_select_sram_ports.size()); - } - - /* Create a Verilog Module based on the circuit model, and add to module manager */ - ModuleId module_id = module_manager.add_module(circuit_lib.model_name(circuit_model)); - VTR_ASSERT(ModuleId::INVALID() != module_id); - /* Add module ports */ - /* Add each global port */ - for (const auto& port : lut_global_ports) { - /* Configure each global port */ - BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT); - } - /* Add each input port */ - for (const auto& port : lut_input_ports) { - BasicPort input_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT); - /* Set the port to be wire-connection */ - module_manager.set_port_is_wire(module_id, input_port.get_name(), true); - } - /* Add each output port */ - for (const auto& port : lut_output_ports) { - BasicPort output_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT); - /* Set the port to be wire-connection */ - module_manager.set_port_is_wire(module_id, output_port.get_name(), true); - } - /* Add each regular (not mode select) SRAM port */ - for (const auto& port : lut_regular_sram_ports) { - BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, mem_port, ModuleManager::MODULE_INPUT_PORT); - BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port)); - module_manager.add_port(module_id, mem_inv_port, ModuleManager::MODULE_INPUT_PORT); - } - - /* Add each mode-select SRAM port */ - for (const auto& port : lut_mode_select_sram_ports) { - BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port)); - module_manager.add_port(module_id, mem_port, ModuleManager::MODULE_INPUT_PORT); - BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), circuit_lib.port_size(port)); - module_manager.add_port(module_id, mem_inv_port, ModuleManager::MODULE_INPUT_PORT); - } - - /* dump module definition + ports */ - print_verilog_module_declaration(fp, module_manager, module_id); - - /* Print local wires for mode selector */ - /* Local wires for the output of mode selector */ - BasicPort mode_select_output_port(std::string(circuit_lib.port_lib_name(lut_input_ports[0]) + "_mode"), circuit_lib.port_size(lut_input_ports[0])); - fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, mode_select_output_port) << ";" << std::endl; - /* Local wires for the output of input inverters */ - BasicPort inverted_input_port(std::string(circuit_lib.port_lib_name(lut_input_ports[0]) + "_b"), circuit_lib.port_size(lut_input_ports[0])); - fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, inverted_input_port) << ";" << std::endl; - /* Local wires for the output of input buffers */ - BasicPort buffered_input_port(std::string(circuit_lib.port_lib_name(lut_input_ports[0]) + "_buf"), circuit_lib.port_size(lut_input_ports[0])); - fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, buffered_input_port) << ";" << std::endl; - - /* Instanciate mode selecting circuit: AND/OR gate - * By following the tri-state map of LUT input port - * The wiring of input ports will be organized as follows - * - * LUT input - * | - * v - * +----------+ - * | mode | - * | selector | - * +----------+ - * | mode_select_output_port - * +-----------------+------------+ - * | | - * +----------+ +---------+ - * | Inverter | | Buffer | - * +----------+ +---------+ - * | inverter_input_port | buffered_input_port - * v v - * +--------------------------------------+ - * | LUT Multiplexing Structure | - * +--------------------------------------+ - */ - print_verilog_comment(fp, std::string("---- BEGIN Instanciation of model-select gates -----")); - /* 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]); - size_t mode_select_port_lsb = 0; - for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) { - BasicPort cur_mode_select_output_port(mode_select_output_port.get_name(), pin, pin); - BasicPort cur_input_port(circuit_lib.port_lib_name(lut_input_ports[0]), pin, pin); - /* For an empty tri-state map or a '-' sign in tri-state map, we can short-wire mode select_output_ports */ - if (tri_state_map.empty() || ('-' == tri_state_map[pin]) ) { - print_verilog_wire_connection(fp, cur_mode_select_output_port, cur_input_port, false); - continue; /* Finish here */ - } - /* Reach here, it means that we need a circuit for mode selection */ - BasicPort cur_lut_mode_select_sram_port(circuit_lib.port_lib_name(lut_mode_select_sram_ports[0]), mode_select_port_lsb, mode_select_port_lsb); - enum e_spice_model_gate_type required_gate_type; - if ('0' == tri_state_map[pin]) { - /* We need a 2-input AND gate, in order to tri-state the input - * Detailed circuit is as follow: - * +---------+ - * SRAM --->| 2-input |----> mode_select_output_port - * LUT input--->| AND | - * +---------+ - * When SRAM is set to logic 0, the LUT input is tri-stated - * When SRAM is set to logic 1, the LUT input is effective to the downstream circuits - */ - required_gate_type = SPICE_MODEL_GATE_AND; - } else { - VTR_ASSERT ('1' == tri_state_map[pin]); - /* We need a 2-input OR gate, in order to tri-state the input - * Detailed circuit is as follow: - * +---------+ - * SRAM --->| 2-input |----> mode_select_output_port - * LUT input--->| OR | - * +---------+ - * When SRAM is set to logic 1, the LUT input is tri-stated - * When SRAM is set to logic 0, the LUT input is effective to the downstream circuits - */ - required_gate_type = SPICE_MODEL_GATE_OR; - } - /* Get the circuit model of the gate */ - CircuitModelId gate_model = circuit_lib.port_tri_state_model(lut_input_ports[0]); - /* Check this is the gate we want ! */ - VTR_ASSERT (required_gate_type == circuit_lib.gate_type(gate_model)); - - /* Prepare for the gate instanciation */ - /* Get the input ports from the gate */ - std::vector gate_input_ports = circuit_lib.model_ports_by_type(gate_model, SPICE_MODEL_PORT_INPUT, true); - /* Get the output ports from the gate */ - std::vector gate_output_ports = circuit_lib.model_ports_by_type(gate_model, SPICE_MODEL_PORT_OUTPUT, true); - /* Check the port sizes and width: - * we should have only 2 input ports, each of which has a size of 1 - * we should have only 1 output port, each of which has a size of 1 - */ - VTR_ASSERT (2 == gate_input_ports.size()); - for (const auto& port : gate_input_ports) { - VTR_ASSERT (1 == circuit_lib.port_size(port)); - } - VTR_ASSERT (1 == gate_output_ports.size()); - for (const auto& port : gate_output_ports) { - VTR_ASSERT (1 == circuit_lib.port_size(port)); - } - /* Find the module id of gate_model in the module manager */ - ModuleId gate_module_id = module_manager.find_module(circuit_lib.model_name(gate_model)); - /* We must have a valid id */ - VTR_ASSERT (ModuleId::INVALID() != gate_module_id); - /* Create a port-to-port map: - * Input[0] of the gate is wired to a SRAM mode-select port - * Input[1] of the gate is wired to the input port of LUT - * Output[0] of the gate is wired to the mode_select_output_port - */ - std::map port2port_name_map; - port2port_name_map[circuit_lib.port_lib_name(gate_input_ports[0])] = cur_lut_mode_select_sram_port; - port2port_name_map[circuit_lib.port_lib_name(gate_input_ports[1])] = cur_input_port; - port2port_name_map[circuit_lib.port_lib_name(gate_output_ports[0])] = cur_mode_select_output_port; - - /* Instanciate the gate */ - print_verilog_module_instance(fp, module_manager, module_id, gate_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model)); - /* IMPORTANT: this update MUST be called after the instance outputting!!!! - * update the module manager with the relationship between the parent and child modules - */ - module_manager.add_child_module(module_id, gate_module_id); - /* update the lsb of mode select port size */ - mode_select_port_lsb++; - } - print_verilog_comment(fp, std::string("---- END Instanciation of model-select gates -----")); - /* Sanitity check */ - if ( true == circuit_lib.is_lut_fracturable(circuit_model) ) { - if (mode_select_port_lsb != circuit_lib.port_size(lut_mode_select_sram_ports[0])) { - vpr_printf(TIO_MESSAGE_ERROR, - "(FILE:%s,LINE[%d]) Circuit model LUT (name=%s) has a unmatched tri-state map (%s) implied by mode_port size(%d)!\n", - __FILE__, __LINE__, - circuit_lib.model_name(circuit_model).c_str(), - tri_state_map.c_str(), - circuit_lib.port_size(lut_mode_select_sram_ports[0])); - exit(1); - } - } - - /* Add a blank-line splitter */ - fp << std::endl; - - /* Add inverters to mode_select output ports */ - print_verilog_comment(fp, std::string("---- BEGIN Instanciation of an input inverters modules -----")); - /* Find the circuit model of the input inverter */ - CircuitModelId input_inverter_model = circuit_lib.lut_input_inverter_model(circuit_model); - VTR_ASSERT( CircuitModelId::INVALID() != input_inverter_model ); - /* Now we need to add inverters by instanciating the modules */ - for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) { - /* Input of inverter is the output of mode select circuits */ - BasicPort inverter_instance_input_port(mode_select_output_port.get_name(), pin, pin); - /* Output of inverter is the inverted input port */ - BasicPort inverter_instance_output_port(inverted_input_port.get_name(), pin, pin); - - print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, input_inverter_model, inverter_instance_input_port, inverter_instance_output_port); - } - print_verilog_comment(fp, std::string("---- END Instanciation of an input inverters modules -----")); - - /* Add buffers to mode_select output ports */ - print_verilog_comment(fp, std::string("---- BEGIN Instanciation of an input buffer modules -----")); - /* Find the circuit model of the input inverter */ - CircuitModelId input_buffer_model = circuit_lib.lut_input_buffer_model(circuit_model); - VTR_ASSERT( CircuitModelId::INVALID() != input_buffer_model ); - /* Now we need to add inverters by instanciating the modules */ - for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) { - /* Input of inverter is the output of mode select circuits */ - BasicPort buffer_instance_input_port(mode_select_output_port.get_name(), pin, pin); - /* Output of inverter is the inverted input port */ - BasicPort buffer_instance_output_port(buffered_input_port.get_name(), pin, pin); - - print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, input_buffer_model, buffer_instance_input_port, buffer_instance_output_port); - } - print_verilog_comment(fp, std::string("---- END Instanciation of an input buffer modules -----")); - - /* Instanciate the multiplexing structure for the LUT */ - print_verilog_comment(fp, std::string("---- BEGIN Instanciation of LUT multiplexer module -----")); - /* Find the name of LUT MUX: no need to provide a mux size, just give an invalid number (=-1) */ - std::string lut_mux_module_name = generate_mux_subckt_name(circuit_lib, circuit_model, size_t(-1), std::string("")); - /* Find the module id of LUT MUX in the module manager */ - ModuleId lut_mux_module_id = module_manager.find_module(lut_mux_module_name); - /* We must have a valid id */ - VTR_ASSERT (ModuleId::INVALID() != lut_mux_module_id); - /* Create a port-to-port map: - * Input of the LUT MUX is wired to a regular SRAM port of LUT - * Outputs of the LUT MUX is wired to the output ports of LUT by name - * SRAM of the LUT MUX is wired to the buffered input port of LUT - * SRAM_inv of the LUT MUX is wired to the inverted input port of LUT - */ - std::map port2port_name_map; - port2port_name_map[circuit_lib.port_lib_name(lut_input_ports[0])] = BasicPort(circuit_lib.port_lib_name(lut_regular_sram_ports[0]), circuit_lib.port_size(lut_regular_sram_ports[0])); - /* Skip the output ports, if we do not need a new name for the port of instance */ - port2port_name_map[circuit_lib.port_lib_name(lut_regular_sram_ports[0])] = buffered_input_port; - /* TODO: be more flexible in naming !!! */ - port2port_name_map[std::string(circuit_lib.port_lib_name(lut_regular_sram_ports[0]) + "_inv")] = inverted_input_port; - - /* Instanciate the gate */ - print_verilog_module_instance(fp, module_manager, module_id, lut_mux_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model)); - /* IMPORTANT: this update MUST be called after the instance outputting!!!! - * update the module manager with the relationship between the parent and child modules - */ - module_manager.add_child_module(module_id, lut_mux_module_id); - - /* Print timing info */ - print_verilog_submodule_timing(fp, circuit_lib, circuit_model); - - /* Print signal initialization */ - print_verilog_submodule_signal_init(fp, circuit_lib, circuit_model); - - /* Put an end to the Verilog module */ - print_verilog_module_end(fp, circuit_lib.model_name(circuit_model)); -} - /******************************************************************** * Print Verilog modules for the Look-Up Tables (LUTs) * in the circuit library @@ -366,13 +52,16 @@ void print_verilog_submodule_luts(ModuleManager& module_manager, print_verilog_include_defines_preproc_file(fp, verilog_dir); /* Search for each LUT circuit model */ - for (const auto& circuit_model : circuit_lib.models()) { + for (const auto& lut_model : circuit_lib.models()) { /* Bypass user-defined and non-LUT modules */ - if ( (!circuit_lib.model_verilog_netlist(circuit_model).empty()) - || (SPICE_MODEL_LUT != circuit_lib.model_type(circuit_model)) ) { + if ( (!circuit_lib.model_verilog_netlist(lut_model).empty()) + || (SPICE_MODEL_LUT != circuit_lib.model_type(lut_model)) ) { continue; } - print_verilog_submodule_lut(module_manager, circuit_lib, fp, circuit_model); + /* Find the module id */ + ModuleId lut_module = module_manager.find_module(circuit_lib.model_name(lut_model)); + VTR_ASSERT(true == module_manager.valid_module_id(lut_module)); + write_verilog_module_to_file(fp, module_manager, lut_module, circuit_lib.dump_explicit_port_map(lut_model)); } /* Close the file handler */