From ba0120bd76456b0ec4f51d24234dad7fb37166b0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 6 Nov 2020 11:10:04 -0700 Subject: [PATCH] [Tool] Remove the limitation on requiring Qb ports for CCFF --- .../src/check_circuit_library.cpp | 2 +- .../fpga_bitstream/build_device_bitstream.cpp | 4 - openfpga/src/fpga_verilog/verilog_api.cpp | 1 + .../verilog_preconfig_top_module.cpp | 108 ++++++++++++------ .../verilog_preconfig_top_module.h | 2 + openfpga/src/utils/module_manager_utils.cpp | 2 +- 6 files changed, 76 insertions(+), 43 deletions(-) diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp index b729ef73b..897c05cfc 100644 --- a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp @@ -302,7 +302,7 @@ size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib, /* Check if we have output */ num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, - 2, 1, false); + 1, 1, false); return num_err; } diff --git a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp index 5172bbef9..1fb2360e9 100644 --- a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp @@ -152,10 +152,6 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx, /* Bitstream manager to be built */ BitstreamManager bitstream_manager; - /* Assign the SRAM model applied to the FPGA fabric */ - CircuitModelId sram_model = openfpga_ctx.arch().config_protocol.memory_model(); - VTR_ASSERT(true == openfpga_ctx.arch().circuit_lib.valid_model_id(sram_model)); - /* Create the top-level block for bitstream * This is related to the top-level module of fpga */ diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index aa207787e..81ad7478f 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -181,6 +181,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager, if (true == options.print_formal_verification_top_netlist()) { std::string formal_verification_top_netlist_file_path = src_dir_path + netlist_name + std::string(FORMAL_VERIFICATION_VERILOG_FILE_POSTFIX); print_verilog_preconfig_top_module(module_manager, bitstream_manager, + config_protocol, circuit_lib, global_ports, atom_ctx, place_ctx, io_location_map, netlist_annotation, diff --git a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp index cf326381b..9500044be 100644 --- a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp +++ b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp @@ -189,7 +189,8 @@ namespace openfpga static void print_verilog_preconfig_top_module_assign_bitstream(std::fstream &fp, const ModuleManager &module_manager, const ModuleId &top_module, - const BitstreamManager &bitstream_manager) + const BitstreamManager &bitstream_manager, + const bool& output_datab_bits) { /* Validate the file stream */ valid_file_stream(fp); @@ -231,44 +232,46 @@ namespace openfpga print_verilog_wire_constant_values(fp, config_data_port, config_data_values); } - fp << "initial begin" << std::endl; + if (true == output_datab_bits) { + fp << "initial begin" << std::endl; - for (const ConfigBlockId &config_block_id : bitstream_manager.blocks()) - { - /* We only cares blocks with configuration bits */ - if (0 == bitstream_manager.block_bits(config_block_id).size()) - { - continue; - } - /* Build the hierarchical path of the configuration bit in modules */ - std::vector block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id); - /* Drop the first block, which is the top module, it should be replaced by the instance name here */ - /* Ensure that this is the module we want to drop! */ - VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0]))); - block_hierarchy.erase(block_hierarchy.begin()); - /* Build the full hierarchy path */ - std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME); - for (const ConfigBlockId &temp_block : block_hierarchy) + for (const ConfigBlockId &config_block_id : bitstream_manager.blocks()) { + /* We only cares blocks with configuration bits */ + if (0 == bitstream_manager.block_bits(config_block_id).size()) + { + continue; + } + /* Build the hierarchical path of the configuration bit in modules */ + std::vector block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id); + /* Drop the first block, which is the top module, it should be replaced by the instance name here */ + /* Ensure that this is the module we want to drop! */ + VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0]))); + block_hierarchy.erase(block_hierarchy.begin()); + /* Build the full hierarchy path */ + std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME); + for (const ConfigBlockId &temp_block : block_hierarchy) + { + bit_hierarchy_path += std::string("."); + bit_hierarchy_path += bitstream_manager.block_name(temp_block); + } bit_hierarchy_path += std::string("."); - bit_hierarchy_path += bitstream_manager.block_name(temp_block); - } - bit_hierarchy_path += std::string("."); - /* Find the bit index in the parent block */ - BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(), - bitstream_manager.block_bits(config_block_id).size()); + /* Find the bit index in the parent block */ + BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(), + bitstream_manager.block_bits(config_block_id).size()); - std::vector config_datab_values; - for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) - { - config_datab_values.push_back(!bitstream_manager.bit_value(config_bit)); + std::vector config_datab_values; + for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) + { + config_datab_values.push_back(!bitstream_manager.bit_value(config_bit)); + } + print_verilog_force_wire_constant_values(fp, config_datab_port, config_datab_values); } - print_verilog_force_wire_constant_values(fp, config_datab_port, config_datab_values); + + fp << "end" << std::endl; } - fp << "end" << std::endl; - print_verilog_comment(fp, std::string("----- End assign bitstream to configuration memories -----")); } @@ -279,7 +282,8 @@ namespace openfpga static void print_verilog_preconfig_top_module_deposit_bitstream(std::fstream &fp, const ModuleManager &module_manager, const ModuleId &top_module, - const BitstreamManager &bitstream_manager) + const BitstreamManager &bitstream_manager, + const bool& output_datab_bits) { /* Validate the file stream */ valid_file_stream(fp); @@ -314,9 +318,6 @@ namespace openfpga BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(), bitstream_manager.block_bits(config_block_id).size()); - BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(), - bitstream_manager.block_bits(config_block_id).size()); - /* Wire it to the configuration bit: access both data out and data outb ports */ std::vector config_data_values; for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) @@ -325,6 +326,15 @@ namespace openfpga } print_verilog_deposit_wire_constant_values(fp, config_data_port, config_data_values); + /* Skip datab ports if specified */ + if (false == output_datab_bits) { + continue; + } + + BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(), + bitstream_manager.block_bits(config_block_id).size()); + + std::vector config_datab_values; for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) { @@ -347,19 +357,37 @@ namespace openfpga static void print_verilog_preconfig_top_module_load_bitstream(std::fstream &fp, const ModuleManager &module_manager, const ModuleId &top_module, + const CircuitLibrary& circuit_lib, + const CircuitModelId& mem_model, const BitstreamManager &bitstream_manager) { + + /* Skip the datab port if there is only 1 output port in memory model + * Currently, it assumes that the data output port is always defined while datab is optional + * If we see only 1 port, we assume datab is not defined by default. + * TODO: this switch could be smarter: it should identify if only data or datab + * ports are defined. + */ + bool output_datab_bits = true; + if (1 == circuit_lib.model_ports_by_type(mem_model, CIRCUIT_MODEL_PORT_OUTPUT).size()) { + output_datab_bits = false; + } + print_verilog_comment(fp, std::string("----- Begin load bitstream to configuration memories -----")); print_verilog_preprocessing_flag(fp, std::string(ICARUS_SIMULATOR_FLAG)); /* Use assign syntax for Icarus simulator */ - print_verilog_preconfig_top_module_assign_bitstream(fp, module_manager, top_module, bitstream_manager); + print_verilog_preconfig_top_module_assign_bitstream(fp, module_manager, top_module, + bitstream_manager, + output_datab_bits); fp << "`else" << std::endl; /* Use assign syntax for Icarus simulator */ - print_verilog_preconfig_top_module_deposit_bitstream(fp, module_manager, top_module, bitstream_manager); + print_verilog_preconfig_top_module_deposit_bitstream(fp, module_manager, top_module, + bitstream_manager, + output_datab_bits); print_verilog_endif(fp); @@ -400,6 +428,7 @@ namespace openfpga *******************************************************************/ void print_verilog_preconfig_top_module(const ModuleManager &module_manager, const BitstreamManager &bitstream_manager, + const ConfigProtocol &config_protocol, const CircuitLibrary &circuit_lib, const std::vector &global_ports, const AtomContext &atom_ctx, @@ -457,8 +486,13 @@ namespace openfpga std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), (size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE); + /* Assign the SRAM model applied to the FPGA fabric */ + CircuitModelId sram_model = config_protocol.memory_model(); + VTR_ASSERT(true == circuit_lib.valid_model_id(sram_model)); + /* Assign FPGA internal SRAM/Memory ports to bitstream values */ print_verilog_preconfig_top_module_load_bitstream(fp, module_manager, top_module, + circuit_lib, sram_model, bitstream_manager); /* Testbench ends*/ diff --git a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h index ba2c0233f..498c67628 100644 --- a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h +++ b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.h @@ -11,6 +11,7 @@ #include "module_manager.h" #include "bitstream_manager.h" #include "io_location_map.h" +#include "config_protocol.h" #include "vpr_netlist_annotation.h" /******************************************************************** @@ -22,6 +23,7 @@ namespace openfpga { void print_verilog_preconfig_top_module(const ModuleManager& module_manager, const BitstreamManager& bitstream_manager, + const ConfigProtocol &config_protocol, const CircuitLibrary& circuit_lib, const std::vector& global_ports, const AtomContext& atom_ctx, diff --git a/openfpga/src/utils/module_manager_utils.cpp b/openfpga/src/utils/module_manager_utils.cpp index d6a62f788..7d4d92d9b 100644 --- a/openfpga/src/utils/module_manager_utils.cpp +++ b/openfpga/src/utils/module_manager_utils.cpp @@ -776,7 +776,7 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man /* Do wiring only when we have sramb ports */ if ( (false == logic_module_sramb_port_ids.empty()) - || (ModulePortId::INVALID() == mem_module_sramb_port_id) ) { + && (ModulePortId::INVALID() != mem_module_sramb_port_id) ) { add_module_nets_between_logic_and_memory_sram_ports(module_manager, parent_module, logic_module, logic_instance_id, memory_module, memory_instance_id,