diff --git a/libopenfpga/libarchopenfpga/src/circuit_library.cpp b/libopenfpga/libarchopenfpga/src/circuit_library.cpp index bbf9c50c4..1bc6e840e 100644 --- a/libopenfpga/libarchopenfpga/src/circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/circuit_library.cpp @@ -942,6 +942,12 @@ bool CircuitLibrary::port_is_config_enable(const CircuitPortId& circuit_port_id) return port_is_config_enable_[circuit_port_id]; } +bool CircuitLibrary::port_is_edge_triggered(const CircuitPortId& circuit_port_id) const { + /* validate the circuit_port_id */ + VTR_ASSERT(valid_circuit_port_id(circuit_port_id)); + return port_is_edge_triggered_[circuit_port_id]; +} + /* Return a flag if the port is used during programming a FPGA in a circuit model */ bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const { /* validate the circuit_port_id */ @@ -1493,6 +1499,15 @@ void CircuitLibrary::set_port_is_config_enable(const CircuitPortId& circuit_port return; } +/* Set the is_edge_triggered for a port of a circuit model */ +void CircuitLibrary::set_port_is_edge_triggered(const CircuitPortId& circuit_port_id, + const bool& is_edge_triggered) { + /* validate the circuit_port_id */ + VTR_ASSERT(valid_circuit_port_id(circuit_port_id)); + port_is_edge_triggered_[circuit_port_id] = is_edge_triggered; + return; +} + /* Set the is_prog for a port of a circuit model */ void CircuitLibrary::set_port_is_prog(const CircuitPortId& circuit_port_id, const bool& is_prog) { diff --git a/libopenfpga/libarchopenfpga/src/circuit_library.h b/libopenfpga/libarchopenfpga/src/circuit_library.h index bd082f738..f4b742a27 100644 --- a/libopenfpga/libarchopenfpga/src/circuit_library.h +++ b/libopenfpga/libarchopenfpga/src/circuit_library.h @@ -91,15 +91,16 @@ * 9. port_is_reset: specify if this port is a reset signal which needs special pulse widths in testbenches * 10. port_is_set: specify if this port is a set signal which needs special pulse widths in testbenches * 11. port_is_config_enable: specify if this port is a config_enable signal which needs special pulse widths in testbenches - * 12. port_is_prog: specify if this port is for FPGA programming use which needs special pulse widths in testbenches - * 13. port_tri_state_model_name: the name of circuit model linked to tri-state the port - * 14. port_tri_state_model_ids_: the Id of circuit model linked to tri-state the port - * 15. port_inv_model_names_: the name of inverter circuit model linked to the port - * 16. port_inv_model_ids_: the Id of inverter circuit model linked to the port - * 17. port_tri_state_map_: only applicable to inputs of LUTs, the tri-state map applied to each pin of this port - * 18. port_lut_frac_level_: only applicable to outputs of LUTs, indicate which level of outputs inside LUT multiplexing structure will be used - * 19. port_lut_output_mask_: only applicable to outputs of LUTs, indicate which output at an internal level of LUT multiplexing structure will be used - * 20. port_sram_orgz_: only applicable to SRAM ports, indicate how the SRAMs will be organized, either memory decoders or scan-chains + * 12. port_is_edge_triggered: specify if this port is triggerd by edges like the clock signal of a D-type flip-flop + * 13. port_is_prog: specify if this port is for FPGA programming use which needs special pulse widths in testbenches + * 14. port_tri_state_model_name: the name of circuit model linked to tri-state the port + * 15. port_tri_state_model_ids_: the Id of circuit model linked to tri-state the port + * 16. port_inv_model_names_: the name of inverter circuit model linked to the port + * 17. port_inv_model_ids_: the Id of inverter circuit model linked to the port + * 18. port_tri_state_map_: only applicable to inputs of LUTs, the tri-state map applied to each pin of this port + * 19. port_lut_frac_level_: only applicable to outputs of LUTs, indicate which level of outputs inside LUT multiplexing structure will be used + * 20. port_lut_output_mask_: only applicable to outputs of LUTs, indicate which output at an internal level of LUT multiplexing structure will be used + * 21. port_sram_orgz_: only applicable to SRAM ports, indicate how the SRAMs will be organized, either memory decoders or scan-chains * * ------ Delay information ------ * 1. delay_types_: type of pin-to-pin delay, either rising_edge of falling_edge @@ -284,6 +285,7 @@ class CircuitLibrary { bool port_is_reset(const CircuitPortId& circuit_port_id) const; bool port_is_set(const CircuitPortId& circuit_port_id) const; bool port_is_config_enable(const CircuitPortId& circuit_port_id) const; + bool port_is_edge_triggered(const CircuitPortId& circuit_port_id) const; 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_mask(const CircuitPortId& circuit_port_id) const; @@ -364,6 +366,8 @@ class CircuitLibrary { const bool& is_set); void set_port_is_config_enable(const CircuitPortId& circuit_port_id, const bool& is_config_enable); + void set_port_is_edge_triggered(const CircuitPortId& circuit_port_id, + const bool& is_edge_triggered); void set_port_is_prog(const CircuitPortId& circuit_port_id, const bool& is_prog); void set_port_tri_state_model_name(const CircuitPortId& circuit_port_id, @@ -550,6 +554,7 @@ class CircuitLibrary { vtr::vector port_is_reset_; vtr::vector port_is_set_; vtr::vector port_is_config_enable_; + vtr::vector port_is_edge_triggered_; vtr::vector port_is_prog_; vtr::vector port_tri_state_model_names_; vtr::vector port_tri_state_model_ids_; diff --git a/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp index 36e837814..4136b0463 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp @@ -564,6 +564,9 @@ void read_xml_circuit_port(pugi::xml_node& xml_port, /* Identify if the port is to enable programming for FPGAs, by default it is NOT */ circuit_lib.set_port_is_config_enable(port, get_attribute(xml_port, "is_config_enable", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false)); + /* Identify if the port is to triggered by edges, by default it is NOT */ + circuit_lib.set_port_is_edge_triggered(port, get_attribute(xml_port, "is_edge_triggered", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false)); + /* Find the name of circuit model that this port is linked to */ circuit_lib.set_port_tri_state_model_name(port, get_attribute(xml_port, "circuit_model_name", loc_data, pugiutil::ReqOpt::OPTIONAL).as_string()); diff --git a/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp index b141b0fe2..9165725e2 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp @@ -207,6 +207,10 @@ void write_xml_circuit_port(std::fstream& fp, write_xml_attribute(fp, "is_config_enable", "true"); } + if (true == circuit_lib.port_is_edge_triggered(port)) { + write_xml_attribute(fp, "is_edge_triggered", "true"); + } + /* Output the name of circuit model that this port is linked to */ if (!circuit_lib.port_tri_state_model_name(port).empty()) { write_xml_attribute(fp, "circuit_model_name", circuit_lib.port_tri_state_model_name(port).c_str()); diff --git a/openfpga/src/base/openfpga_verilog.cpp b/openfpga/src/base/openfpga_verilog.cpp index 58ea20f2e..0c6367fc5 100644 --- a/openfpga/src/base/openfpga_verilog.cpp +++ b/openfpga/src/base/openfpga_verilog.cpp @@ -97,7 +97,7 @@ int write_verilog_testbench(OpenfpgaContext& openfpga_ctx, openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.arch().circuit_lib, openfpga_ctx.simulation_setting(), - openfpga_ctx.arch().config_protocol.type(), + openfpga_ctx.arch().config_protocol, options); /* TODO: should identify the error code from internal function execution */ diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index 940d78953..fe5b76196 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -156,7 +156,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager, const VprNetlistAnnotation &netlist_annotation, const CircuitLibrary &circuit_lib, const SimulationSetting &simulation_setting, - const e_config_protocol_type &config_protocol_type, + const ConfigProtocol &config_protocol, const VerilogTestbenchOption &options) { vtr::ScopedStartFinishTimer timer("Write Verilog testbenches for FPGA fabric\n"); @@ -205,7 +205,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager, std::string top_testbench_file_path = src_dir_path + netlist_name + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_FILE_POSTFIX); print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream, - config_protocol_type, + config_protocol, circuit_lib, global_ports, atom_ctx, place_ctx, io_location_map, netlist_annotation, @@ -225,7 +225,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager, src_dir_path, atom_ctx, place_ctx, io_location_map, module_manager, - config_protocol_type, + config_protocol.type(), bitstream_manager.num_bits(), simulation_setting.num_clock_cycles(), simulation_setting.programming_clock_frequency(), diff --git a/openfpga/src/fpga_verilog/verilog_api.h b/openfpga/src/fpga_verilog/verilog_api.h index 94fbf3a29..1af656d7d 100644 --- a/openfpga/src/fpga_verilog/verilog_api.h +++ b/openfpga/src/fpga_verilog/verilog_api.h @@ -10,6 +10,7 @@ #include "mux_library.h" #include "decoder_library.h" #include "circuit_library.h" +#include "config_protocol.h" #include "vpr_context.h" #include "vpr_device_annotation.h" #include "device_rr_gsb.h" @@ -49,7 +50,7 @@ void fpga_verilog_testbench(const ModuleManager& module_manager, const VprNetlistAnnotation& netlist_annotation, const CircuitLibrary& circuit_lib, const SimulationSetting& simulation_parameters, - const e_config_protocol_type& config_protocol_type, + const ConfigProtocol& config_protocol, const VerilogTestbenchOption& options); diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 8a5ec3721..763f7800e 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -153,6 +153,8 @@ void print_verilog_top_testbench_memory_bank_port(std::fstream& fp, *******************************************************************/ static void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp, + const ConfigProtocol& config_protocol, + const CircuitLibrary& circuit_lib, const ModuleManager& module_manager, const ModuleId& top_module) { /* Validate the file stream */ @@ -174,15 +176,32 @@ void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp, fp << generate_verilog_port(VERILOG_PORT_REG, din_port) << ";" << std::endl; /* Wire the INVERTED configuration done signal to the enable signal !!! */ - print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoder to inverted configuration done signal -----")); ModulePortId en_port_id = module_manager.find_module_port(top_module, std::string(DECODER_ENABLE_PORT_NAME)); BasicPort en_port = module_manager.module_port(top_module, en_port_id); - BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1); - fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl; - print_verilog_wire_connection(fp, en_port, config_done_port, true); + /* Find the circuit model of configurable memory + * Spot its BL port and generate stimuli based on BL port's attribute: + * - If the BL port is triggered by edge, use the inverted programming clock signal + * - If the BL port is a regular port, use the inverted configuration done signal + */ + const CircuitModelId& mem_model = config_protocol.memory_model(); + VTR_ASSERT(true == circuit_lib.valid_model_id(mem_model)); + std::vector mem_model_bl_ports = circuit_lib.model_ports_by_type(mem_model, CIRCUIT_MODEL_PORT_BL); + VTR_ASSERT(1 == mem_model_bl_ports.size()); + if (true == circuit_lib.port_is_edge_triggered(mem_model_bl_ports[0])) { + VTR_ASSERT_SAFE(false == circuit_lib.port_is_edge_triggered(mem_model_bl_ports[0])); + BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1); + print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoder to inverted programming clock signal -----")); + fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl; + print_verilog_wire_connection(fp, en_port, prog_clock_port, true); + } else { + BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1); + print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoder to inverted configuration done signal -----")); + fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl; + print_verilog_wire_connection(fp, en_port, config_done_port, true); + } } /******************************************************************** @@ -190,10 +209,11 @@ void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp, *******************************************************************/ static void print_verilog_top_testbench_config_protocol_port(std::fstream& fp, - const e_config_protocol_type& sram_orgz_type, + const ConfigProtocol& config_protocol, + const CircuitLibrary& circuit_lib, const ModuleManager& module_manager, const ModuleId& top_module) { - switch(sram_orgz_type) { + switch(config_protocol.type()) { case CONFIG_MEM_STANDALONE: print_verilog_top_testbench_flatten_memory_port(fp, module_manager, top_module); break; @@ -204,7 +224,8 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp, print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module); break; case CONFIG_MEM_FRAME_BASED: - print_verilog_top_testbench_frame_decoder_port(fp, module_manager, top_module); + print_verilog_top_testbench_frame_decoder_port(fp, config_protocol, circuit_lib, + module_manager, top_module); break; default: VTR_LOGF_ERROR(__FILE__, __LINE__, @@ -435,7 +456,8 @@ void print_verilog_top_testbench_ports(std::fstream& fp, const AtomContext& atom_ctx, const VprNetlistAnnotation& netlist_annotation, const std::vector& clock_port_names, - const e_config_protocol_type& sram_orgz_type, + const ConfigProtocol& config_protocol, + const CircuitLibrary& circuit_lib, const std::string& circuit_name){ /* Validate the file stream */ valid_file_stream(fp); @@ -509,7 +531,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, fp << generate_verilog_port(VERILOG_PORT_REG, set_port) << ";" << std::endl; /* Configuration ports depend on the organization of SRAMs */ - print_verilog_top_testbench_config_protocol_port(fp, sram_orgz_type, + print_verilog_top_testbench_config_protocol_port(fp, config_protocol, circuit_lib, module_manager, top_module); /* Create a clock port if the benchmark have one but not in the default name! @@ -1459,7 +1481,7 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp, void print_verilog_top_testbench(const ModuleManager& module_manager, const BitstreamManager& bitstream_manager, const FabricBitstream& fabric_bitstream, - const e_config_protocol_type& sram_orgz_type, + const ConfigProtocol& config_protocol, const CircuitLibrary& circuit_lib, const std::vector& global_ports, const AtomContext& atom_ctx, @@ -1498,13 +1520,14 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, /* Start of testbench */ print_verilog_top_testbench_ports(fp, module_manager, top_module, atom_ctx, netlist_annotation, clock_port_names, - sram_orgz_type, circuit_name); + config_protocol, circuit_lib, + circuit_name); /* Find the clock period */ float prog_clock_period = (1./simulation_parameters.programming_clock_frequency()); float op_clock_period = (1./simulation_parameters.operating_clock_frequency()); /* Estimate the number of configuration clock cycles */ - size_t num_config_clock_cycles = calculate_num_config_clock_cycles(sram_orgz_type, + size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(), fast_configuration, bitstream_manager, fabric_bitstream); @@ -1543,11 +1566,11 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, /* Print tasks used for loading bitstreams */ print_verilog_top_testbench_load_bitstream_task(fp, - sram_orgz_type, + config_protocol.type(), module_manager, top_module); /* load bitstream to FPGA fabric in a configuration phase */ - print_verilog_top_testbench_bitstream(fp, sram_orgz_type, + print_verilog_top_testbench_bitstream(fp, config_protocol.type(), fast_configuration, module_manager, top_module, bitstream_manager, fabric_bitstream); diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.h b/openfpga/src/fpga_verilog/verilog_top_testbench.h index cbafc6dc4..64d0e0b26 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.h @@ -10,6 +10,7 @@ #include "bitstream_manager.h" #include "fabric_bitstream.h" #include "circuit_library.h" +#include "config_protocol.h" #include "vpr_context.h" #include "io_location_map.h" #include "vpr_netlist_annotation.h" @@ -25,7 +26,7 @@ namespace openfpga { void print_verilog_top_testbench(const ModuleManager& module_manager, const BitstreamManager& bitstream_manager, const FabricBitstream& fabric_bitstream, - const e_config_protocol_type& sram_orgz_type, + const ConfigProtocol& config_protocol, const CircuitLibrary& circuit_lib, const std::vector& global_ports, const AtomContext& atom_ctx,