From 03993192120e7854ecd9344fb3aa8c68f6b8bd0c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 11 Sep 2019 17:04:43 -0600 Subject: [PATCH] refactored LUT Verilog generation --- .../libarchfpga/SRC/check_circuit_library.cpp | 18 + vpr7_x2p/libarchfpga/SRC/circuit_library.cpp | 42 +- vpr7_x2p/libarchfpga/SRC/circuit_library.h | 4 + .../vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp | 384 ++++++++++++++++++ .../vpr/SRC/fpga_x2p/verilog/verilog_lut.h | 20 + .../SRC/fpga_x2p/verilog/verilog_submodules.c | 2 + 6 files changed, 469 insertions(+), 1 deletion(-) create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp create mode 100644 vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h diff --git a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp index 0b08d8f58..d32578d2d 100644 --- a/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp +++ b/vpr7_x2p/libarchfpga/SRC/check_circuit_library.cpp @@ -376,6 +376,24 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) { } } + /* Check the tri-state map of ports, the length should match the port size! */ + for (const auto& port : circuit_lib.ports()) { + if (circuit_lib.port_tri_state_map(port).empty()) { + continue; /* No tri-state map is found, go to the next */ + } + if (circuit_lib.port_tri_state_map(port).length() == circuit_lib.port_size(port)) { + continue; /* Sizes match, go to the next */ + } + /* We have a problem here, sizes do not match, leave a message and raise the error flag */ + vpr_printf(TIO_MESSAGE_ERROR, + "Tri-state map (=%s) of circuit port (type=%s) of model (name=%s) does not match the port size (=%lu)!\n", + circuit_lib.port_tri_state_map(port).c_str(), + CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))], + circuit_lib.model_name(port).c_str(), + circuit_lib.port_size(port)); + num_err++; + } + return num_err; } diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp b/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp index d22574e09..7d0ea6ddc 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library.cpp @@ -192,6 +192,32 @@ bool CircuitLibrary::is_lut_fracturable(const CircuitModelId& model_id) const { return lut_is_fracturable_[model_id]; } +/* Return the circuit model of input buffers + * that are inserted between multiplexing structure and LUT inputs + */ +CircuitModelId CircuitLibrary::lut_input_inverter_model(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_LUT == model_type(model_id)); + /* We MUST have an input inverter */ + VTR_ASSERT(true == buffer_existence_[model_id][LUT_INPUT_INVERTER]); + return buffer_model_ids_[model_id][LUT_INPUT_INVERTER]; +} + +/* Return the circuit model of input buffers + * that are inserted between multiplexing structure and LUT inputs + */ +CircuitModelId CircuitLibrary::lut_input_buffer_model(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_LUT == model_type(model_id)); + /* We MUST have an input buffer */ + VTR_ASSERT(true == buffer_existence_[model_id][LUT_INPUT_BUFFER]); + return buffer_model_ids_[model_id][LUT_INPUT_BUFFER]; +} + /* Return the circuit model of intermediate buffers * that are inserted inside LUT multiplexing structures */ @@ -200,7 +226,7 @@ CircuitModelId CircuitLibrary::lut_intermediate_buffer_model(const CircuitModelI VTR_ASSERT(valid_model_id(model_id)); /* validate the circuit model type is BUF */ VTR_ASSERT(SPICE_MODEL_LUT == model_type(model_id)); - /* if we have an intermediate buffer, we return something, otherwise return an empty map */ + /* if we have an intermediate buffer, we return something, otherwise return an invalid id */ if (true == is_lut_intermediate_buffered(model_id)) { return buffer_model_ids_[model_id][LUT_INTER_BUFFER]; } else { @@ -749,6 +775,20 @@ std::vector CircuitLibrary::port_lut_output_masks(const CircuitPortId& c return port_lut_output_masks_[circuit_port_id]; } +/* Return tri-state map of a port */ +std::string CircuitLibrary::port_tri_state_map(const CircuitPortId& circuit_port_id) const { + /* validate the circuit_port_id */ + VTR_ASSERT(valid_circuit_port_id(circuit_port_id)); + return port_tri_state_maps_[circuit_port_id]; +} + +/* Return circuit model id which is used to tri-state a port */ +CircuitModelId CircuitLibrary::port_tri_state_model(const CircuitPortId& circuit_port_id) const { + /* validate the circuit_port_id */ + VTR_ASSERT(valid_circuit_port_id(circuit_port_id)); + return port_tri_state_model_ids_[circuit_port_id]; +} + /* Return the id of parent circuit model for a circuit port */ CircuitModelId CircuitLibrary::port_parent_model(const CircuitPortId& circuit_port_id) const { /* validate the circuit_port_id */ diff --git a/vpr7_x2p/libarchfpga/SRC/circuit_library.h b/vpr7_x2p/libarchfpga/SRC/circuit_library.h index d74c61a45..acdf2efe6 100644 --- a/vpr7_x2p/libarchfpga/SRC/circuit_library.h +++ b/vpr7_x2p/libarchfpga/SRC/circuit_library.h @@ -226,6 +226,8 @@ class CircuitLibrary { /* LUT-related information */ bool is_lut_intermediate_buffered(const CircuitModelId& model_id) const; bool is_lut_fracturable(const CircuitModelId& model_id) const; + CircuitModelId lut_input_buffer_model(const CircuitModelId& model_id) const; + CircuitModelId lut_input_inverter_model(const CircuitModelId& model_id) const; CircuitModelId lut_intermediate_buffer_model(const CircuitModelId& model_id) const; std::string lut_intermediate_buffer_location_map(const CircuitModelId& model_id) const; /* Pass-gate-logic information */ @@ -277,6 +279,8 @@ class CircuitLibrary { bool port_is_prog(const CircuitPortId& circuit_port_id) const; size_t port_lut_frac_level(const CircuitPortId& circuit_port_id) const; std::vector port_lut_output_masks(const CircuitPortId& circuit_port_id) const; + std::string port_tri_state_map(const CircuitPortId& circuit_port_id) const; + CircuitModelId port_tri_state_model(const CircuitPortId& circuit_port_id) const; CircuitModelId port_parent_model(const CircuitPortId& circuit_port_id) const; std::string model_name(const CircuitPortId& port_id) const; public: /* Public Accessors: Timing graph */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp new file mode 100644 index 000000000..25a691935 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.cpp @@ -0,0 +1,384 @@ +/******************************************************************** + * This file includes functions to generate Verilog submodules for LUTs + ********************************************************************/ +#include +#include + +#include "util.h" +#include "vtr_assert.h" + +/* Device-level header files */ +#include "mux_graph.h" +#include "module_manager.h" +#include "physical_types.h" +#include "vpr_types.h" +#include "mux_utils.h" + +/* FPGA-X2P context header files */ +#include "spice_types.h" +#include "fpga_x2p_naming.h" +#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_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); + /* 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); + } + /* 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); + } + /* 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_verilog_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 + ********************************************************************/ +void print_verilog_submodule_luts(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::string& verilog_dir, + const std::string& submodule_dir) { + /* TODO: remove .bak when this part is completed and tested */ + std::string verilog_fname = submodule_dir + luts_verilog_file_name + ".bak"; + + std::fstream fp; + + /* Create the file stream */ + fp.open(verilog_fname, std::fstream::out | std::fstream::trunc); + /* Check if the file stream if valid or not */ + check_file_handler(fp); + + /* Create file */ + vpr_printf(TIO_MESSAGE_INFO, + "Generating Verilog netlist for LUTs (%s)...\n", + __FILE__, __LINE__, verilog_fname.c_str()); + + print_verilog_file_header(fp, "Look-Up Tables"); + + print_verilog_include_defines_preproc_file(fp, verilog_dir); + + /* Search for each LUT circuit model */ + for (const auto& circuit_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)) ) { + continue; + } + print_verilog_submodule_lut(module_manager, circuit_lib, fp, circuit_model); + } + + /* Close the file handler */ + fp.close(); + + /* Add fname to the linked list */ + /* Add it when the Verilog generation is refactored + submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str()); + */ + + return; +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h new file mode 100644 index 000000000..d6a8dba35 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_lut.h @@ -0,0 +1,20 @@ +/*********************************************** + * Header file for verilog_lut.cpp + **********************************************/ + +#ifndef VERILOG_LUT_H +#define VERILOG_LUT_H + +/* Include other header files which are dependency on the function declared below */ +#include +#include + +#include "circuit_library.h" +#include "module_manager.h" + +void print_verilog_submodule_luts(ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const std::string& verilog_dir, + const std::string& submodule_dir); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c index 0a2319edc..1d8acb2ef 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_submodules.c @@ -43,6 +43,7 @@ #include "verilog_mux.h" #include "verilog_essential_gates.h" #include "verilog_decoders.h" +#include "verilog_lut.h" /***** Subroutines *****/ @@ -3344,6 +3345,7 @@ void dump_verilog_submodules(ModuleManager& module_manager, fpga_verilog_opts.include_timing, fpga_verilog_opts.include_signal_init, fpga_verilog_opts.dump_explicit_verilog); + print_verilog_submodule_luts(module_manager, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir)); /* 3. Hardwires */ vpr_printf(TIO_MESSAGE_INFO, "Generating modules of hardwires...\n");