refactored wire Verilog generation

This commit is contained in:
tangxifan 2019-09-12 20:49:02 -06:00
parent 79fa858f36
commit 2b829238b5
11 changed files with 350 additions and 5 deletions

View File

@ -94,3 +94,37 @@ std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size,
return subckt_name;
}
/************************************************
* Generate the module name of a routing track wire
***********************************************/
std::string generate_segment_wire_subckt_name(const std::string& wire_model_name,
const size_t& segment_id) {
std::string segment_wire_subckt_name = wire_model_name + "_seg" + std::to_string(segment_id);
return segment_wire_subckt_name;
}
/*********************************************************************
* Generate the port name for the mid-output of a routing track wire
* Mid-output is the output that is wired to a Connection block multiplexer.
*
* | CLB |
* +------------+
* ^
* |
* +------------------------------+
* | Connection block multiplexer |
* +------------------------------+
* ^
* | mid-output +--------------
* +--------------------+ |
* input --->| Routing track wire |--------->| Switch Block
* +--------------------+ output |
* +--------------
********************************************************************/
std::string generate_segment_wire_mid_output_name(const std::string& regular_output_name) {
/* TODO: maybe have a postfix? */
return std::string("mid_" + regular_output_name);
}

View File

@ -28,4 +28,9 @@ std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circui
std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size,
const size_t& data_size);
std::string generate_segment_wire_subckt_name(const std::string& wire_model_name,
const size_t& segment_id);
std::string generate_segment_wire_mid_output_name(const std::string& regular_output_name);
#endif

View File

@ -162,6 +162,13 @@ ModulePortId ModuleManager::add_port(const ModuleId& module,
return port;
}
/* Set a name for a module */
void ModuleManager::set_module_name(const ModuleId& module, const std::string& name) {
/* Validate the id of module */
VTR_ASSERT( valid_module_id(module) );
names_[module] = name;
}
/* Set a port to be a register */
void ModuleManager::set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register) {
/* Find the port */

View File

@ -18,6 +18,7 @@
#include <string>
#include <map>
#include "vtr_vector.h"
#include "module_manager_fwd.h"
#include "device_port.h"
@ -53,6 +54,8 @@ class ModuleManager {
/* Add a port to a module */
ModulePortId add_port(const ModuleId& module,
const BasicPort& port_info, const enum e_module_port_type& port_type);
/* Set a name for a module */
void set_module_name(const ModuleId& module, const std::string& name);
/* Set a port to be a register */
void set_port_is_register(const ModuleId& module, const std::string& port_name, const bool& is_register);
/* Add a child module to a parent module */

View File

@ -14,9 +14,17 @@
#include "module_manager.h"
#include "module_manager_utils.h"
/******************************************************************************
* Add a module to the module manager based on the circuit-level
* description of a circuit model
* This function add a module with a given customized name
* as well as add the ports of circuit model to the module manager
******************************************************************************/
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model) {
ModuleId module = module_manager.add_module(circuit_lib.model_name(circuit_model));
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model,
const std::string& module_name) {
ModuleId module = module_manager.add_module(module_name);
VTR_ASSERT(ModuleId::INVALID() != module);
/* Add ports */
/* Find global ports and add one by one */
@ -49,3 +57,18 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
/* Return the new id */
return module;
}
/******************************************************************************
* Add a module to the module manager based on the circuit-level
* description of a circuit model
* This function add a module in the name of the circuit model
* as well as add the ports of circuit model to the module manager
*
* This function is a wrapper of a more customizable function in the same name
******************************************************************************/
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model) {
return add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model, circuit_lib.model_name(circuit_model));
}

View File

@ -6,9 +6,16 @@
#ifndef MODULE_MANAGER_UTILS_H
#define MODULE_MANAGER_UTILS_H
/* Include other header files which are dependency on the function declared below */
#include "circuit_library.h"
#include "module_manager.h"
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model,
const std::string& module_name);
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model);
#endif

View File

@ -209,7 +209,7 @@ void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
print_verilog_mux_local_decoder_module(fp, module_manager, decoder_lib, decoder);
}
/* Close the file steam */
/* Close the file stream */
fp.close();
/* Add fname to the linked list when debugging is finished */

View File

@ -1,5 +1,5 @@
/***********************************************
* Header file for verilog_submodule_mux.cpp
* Header file for verilog_mux.cpp
**********************************************/
#ifndef VERILOG_MUX_H

View File

@ -44,6 +44,7 @@
#include "verilog_essential_gates.h"
#include "verilog_decoders.h"
#include "verilog_lut.h"
#include "verilog_wire.h"
/***** Subroutines *****/
@ -3351,6 +3352,12 @@ void dump_verilog_submodules(ModuleManager& module_manager,
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of hardwires...\n");
dump_verilog_submodule_wires(verilog_dir, submodule_dir, Arch.num_segments, Arch.Segments,
Arch.spice->num_spice_model, Arch.spice->spice_models);
/* Create a vector of segments. TODO: should come from DeviceContext */
std::vector<t_segment_inf> L_segment_vec;
for (int i = 0; i < Arch.num_segments; ++i) {
L_segment_vec.push_back(Arch.Segments[i]);
}
print_verilog_submodule_wires(module_manager, Arch.spice->circuit_lib, L_segment_vec, std::string(verilog_dir), std::string(submodule_dir));
/* 4. Memories */
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of memories...\n");

View File

@ -0,0 +1,236 @@
/***********************************************
* This file includes functions to generate
* Verilog submodules for wires.
**********************************************/
#include <string>
#include <algorithm>
#include "util.h"
#include "vtr_assert.h"
/* Device-level header files */
#include "module_manager.h"
#include "module_manager_utils.h"
#include "physical_types.h"
#include "vpr_types.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_submodule_utils.h"
#include "verilog_writer_utils.h"
#include "verilog_wire.h"
/********************************************************************
* Print a Verilog module of a regular wire segment
* Regular wire, which is 1-input and 1-output
* This type of wires are used in the local routing architecture
* +------+
* input --->| wire |---> output
* +------+
*
*******************************************************************/
static
void print_verilog_wire_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const CircuitModelId& wire_model) {
/* Ensure a valid file handler*/
check_file_handler(fp);
/* Find the input port, output port*/
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_OUTPUT, true);
std::vector<CircuitPortId> global_ports = circuit_lib.model_global_ports_by_type(wire_model, SPICE_MODEL_PORT_INPUT, true, true);
/* Makre sure the port size is what we want */
VTR_ASSERT (1 == input_ports.size());
VTR_ASSERT (1 == output_ports.size());
VTR_ASSERT (1 == circuit_lib.port_size(input_ports[0]));
VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0]));
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, wire_model);
/* dump module definition + ports */
print_verilog_module_declaration(fp, module_manager, module_id);
/* Finish dumping ports */
/* Print the internal logic of Verilog module */
/* Find the input port of the module */
ModulePortId module_input_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(input_ports[0]));
VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id);
BasicPort module_input_port = module_manager.module_port(module_id, module_input_port_id);
/* Find the output port of the module */
ModulePortId module_output_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(output_ports[0]));
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
BasicPort module_output_port = module_manager.module_port(module_id, module_output_port_id);
/* Print wire declaration for the inputs and outputs */
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_input_port) << ";" << std::endl;
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_output_port) << ";" << std::endl;
/* Direct shortcut */
print_verilog_wire_connection(fp, module_output_port, module_input_port, false);
/* Print timing info */
print_verilog_submodule_timing(fp, circuit_lib, wire_model);
/* Put an end to the Verilog module */
print_verilog_module_end(fp, circuit_lib.model_name(wire_model));
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
* Print a Verilog module of a routing track wire segment
* Routing track wire, which is 1-input and dual output
* This type of wires are used in the global routing architecture.
* One of the output is wired to another Switch block multiplexer,
* while the mid-output is wired to a Connection block multiplexer.
*
* | CLB |
* +------------+
* ^
* |
* +------------------------------+
* | Connection block multiplexer |
* +------------------------------+
* ^
* | mid-output +--------------
* +--------------------+ |
* input --->| Routing track wire |--------->| Switch Block
* +--------------------+ output |
* +--------------
*
*******************************************************************/
static
void print_verilog_routing_wire_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const CircuitModelId& wire_model,
const std::string& wire_subckt_name) {
/* Ensure a valid file handler*/
check_file_handler(fp);
/* Find the input port, output port*/
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(wire_model, SPICE_MODEL_PORT_OUTPUT, true);
/* Makre sure the port size is what we want */
VTR_ASSERT (1 == input_ports.size());
VTR_ASSERT (1 == output_ports.size());
VTR_ASSERT (1 == circuit_lib.port_size(input_ports[0]));
VTR_ASSERT (1 == circuit_lib.port_size(output_ports[0]));
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, wire_model, wire_subckt_name);
/* Add a mid-output port to the module */
BasicPort module_mid_output_port(generate_segment_wire_mid_output_name(circuit_lib.port_lib_name(output_ports[0])), circuit_lib.port_size(output_ports[0]));
module_manager.add_port(module_id, module_mid_output_port, ModuleManager::MODULE_OUTPUT_PORT);
/* dump module definition + ports */
print_verilog_module_declaration(fp, module_manager, module_id);
/* Finish dumping ports */
/* Print the internal logic of Verilog module */
/* Find the input port of the module */
ModulePortId module_input_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(input_ports[0]));
VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id);
BasicPort module_input_port = module_manager.module_port(module_id, module_input_port_id);
/* Find the output port of the module */
ModulePortId module_output_port_id = module_manager.find_module_port(module_id, circuit_lib.port_lib_name(output_ports[0]));
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
BasicPort module_output_port = module_manager.module_port(module_id, module_output_port_id);
/* Print wire declaration for the inputs and outputs */
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_input_port) << ";" << std::endl;
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_output_port) << ";" << std::endl;
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_mid_output_port) << ";" << std::endl;
/* Direct shortcut */
print_verilog_wire_connection(fp, module_output_port, module_input_port, false);
print_verilog_wire_connection(fp, module_mid_output_port, module_input_port, false);
/* Print timing info */
print_verilog_submodule_timing(fp, circuit_lib, wire_model);
/* Put an end to the Verilog module */
print_verilog_module_end(fp, circuit_lib.model_name(wire_model));
/* Add an empty line as a splitter */
fp << std::endl;
}
void print_verilog_submodule_wires(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::vector<t_segment_inf> routing_segments,
const std::string& verilog_dir,
const std::string& submodule_dir) {
/* TODO: remove .bak when it is ready to be plugged in */
std::string verilog_fname(submodule_dir + wires_verilog_file_name + ".bak");
/* Create the file stream */
std::fstream fp;
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
check_file_handler(fp);
/* Print out debugging information for if the file is not opened/created properly */
vpr_printf(TIO_MESSAGE_INFO,
"Creating Verilog netlist for wires (%s)...\n",
verilog_fname.c_str());
print_verilog_file_header(fp, "Wires");
print_verilog_include_defines_preproc_file(fp, verilog_dir);
/* Print Verilog models for regular wires*/
print_verilog_comment(fp, std::string("----- BEGIN Verilog modules for regular wires -----"));
for (const auto& model : circuit_lib.models_by_type(SPICE_MODEL_WIRE)) {
/* Bypass user-defined circuit models */
if (!circuit_lib.model_verilog_netlist(model).empty()) {
continue;
}
print_verilog_wire_module(module_manager, circuit_lib, fp, model);
}
print_verilog_comment(fp, std::string("----- END Verilog modules for regular wires -----"));
/* Create wire models for routing segments*/
print_verilog_comment(fp, std::string("----- BEGIN Verilog modules for routing track wires -----"));
for (const auto& seg : routing_segments) {
VTR_ASSERT( CircuitModelId::INVALID() != seg.circuit_model);
VTR_ASSERT( SPICE_MODEL_CHAN_WIRE == circuit_lib.model_type(seg.circuit_model));
/* Bypass user-defined circuit models */
if (!circuit_lib.model_verilog_netlist(seg.circuit_model).empty()) {
continue;
}
/* Give a unique name for subckt of wire_model of segment,
* circuit_model name is unique, and segment id is unique as well
*/
std::string segment_wire_subckt_name = generate_segment_wire_subckt_name(circuit_lib.model_name(seg.circuit_model), &seg - &routing_segments[0]);
/* Print a Verilog module */
print_verilog_routing_wire_module(module_manager, circuit_lib, fp, seg.circuit_model, segment_wire_subckt_name);
}
print_verilog_comment(fp, std::string("----- END Verilog modules for routing track wires -----"));
/* Close the file stream */
fp.close();
/* Add fname to the linked list */
/* Uncomment this when it is ready to be plugged in
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
*/
return;
}

View File

@ -0,0 +1,23 @@
/***********************************************
* Header file for verilog_wire.cpp
**********************************************/
#ifndef VERILOG_WIRE_H
#define VERILOG_WIRE_H
/* Include other header files which are dependency on the function declared below */
#include <fstream>
#include <vector>
#include "physical_types.h"
#include "vpr_types.h"
#include "circuit_library.h"
#include "module_manager.h"
void print_verilog_submodule_wires(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::vector<t_segment_inf> routing_segments,
const std::string& verilog_dir,
const std::string& submodule_dir);
#endif