From 47e30c3e4b4dc36fe8606d80220b8eb450a2e369 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 18 Sep 2024 17:26:44 -0700 Subject: [PATCH] [core] support last stage mux --- libs/libarchopenfpga/src/circuit_library.cpp | 59 ++++++++++ libs/libarchopenfpga/src/circuit_library.h | 5 + .../src/read_xml_circuit_library.cpp | 14 +++ .../src/write_xml_circuit_library.cpp | 7 ++ openfpga/src/fabric/build_mux_modules.cpp | 101 ++++++++++++++++-- 5 files changed, 175 insertions(+), 11 deletions(-) diff --git a/libs/libarchopenfpga/src/circuit_library.cpp b/libs/libarchopenfpga/src/circuit_library.cpp index 241f63c7a..e39366aec 100644 --- a/libs/libarchopenfpga/src/circuit_library.cpp +++ b/libs/libarchopenfpga/src/circuit_library.cpp @@ -259,6 +259,28 @@ CircuitModelId CircuitLibrary::pass_gate_logic_model( return pgl_model_id; } +/* Find the id of pass-gate circuit model + * Two cases to be considered: + * 1. this is a pass-gate circuit model, just find the data and return + * 2. this circuit model includes a pass-gate, find the link to pass-gate + * circuit model and go recursively + */ +CircuitModelId CircuitLibrary::last_stage_pass_gate_logic_model( + const CircuitModelId& model_id) const { + /* validate the model_id */ + VTR_ASSERT(valid_model_id(model_id)); + + /* Return the data if this is a pass-gate circuit model */ + if (CIRCUIT_MODEL_PASSGATE == model_type(model_id)) { + return model_ids_[model_id]; + } + + /* Otherwise, we need to make sure this circuit model contains a pass-gate */ + CircuitModelId pgl_model_id = last_stage_pass_gate_logic_model_ids_[model_id]; + VTR_ASSERT(CircuitModelId::INVALID() != pgl_model_id); + return pgl_model_id; +} + /* Find the name of pass-gate circuit model * Two cases to be considered: * 1. this is a pass-gate circuit model, just find the data and return @@ -279,6 +301,26 @@ std::string CircuitLibrary::pass_gate_logic_model_name( return pass_gate_logic_model_names_[model_id]; } +/* Find the name of pass-gate circuit model + * Two cases to be considered: + * 1. this is a pass-gate circuit model, just find the data and return + * 2. this circuit model includes a pass-gate, find the link to pass-gate + * circuit model and go recursively + */ +std::string CircuitLibrary::last_stage_pass_gate_logic_model_name( + const CircuitModelId& model_id) const { + /* validate the model_id */ + VTR_ASSERT(valid_model_id(model_id)); + + /* Return the data if this is a pass-gate circuit model */ + if (CIRCUIT_MODEL_PASSGATE == model_type(model_id)) { + return model_names_[model_id]; + } + + /* Otherwise, we need to make sure this circuit model contains a pass-gate */ + return last_stage_pass_gate_logic_model_names_[model_id]; +} + /* Return the type of pass gate logic module, only applicable to circuit model * whose type is pass-gate logic */ enum e_circuit_model_pass_gate_logic_type CircuitLibrary::pass_gate_logic_type( @@ -1262,6 +1304,8 @@ CircuitModelId CircuitLibrary::add_model( /* Pass-gate-related parameters */ pass_gate_logic_model_names_.emplace_back(); pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID()); + last_stage_pass_gate_logic_model_names_.emplace_back(); + last_stage_pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID()); /* Delay information */ delay_types_.emplace_back(); @@ -1485,6 +1529,15 @@ void CircuitLibrary::set_model_pass_gate_logic(const CircuitModelId& model_id, return; } +/* Set pass-gate logic information of a circuit model */ +void CircuitLibrary::set_model_last_stage_pass_gate_logic(const CircuitModelId& model_id, + const std::string& model_name) { + /* validate the model_id */ + VTR_ASSERT(valid_model_id(model_id)); + last_stage_pass_gate_logic_model_names_[model_id] = model_name; + return; +} + /* Add a port to a circuit model */ CircuitPortId CircuitLibrary::add_model_port( const CircuitModelId& model_id, @@ -2174,6 +2227,12 @@ void CircuitLibrary::link_pass_gate_logic_model( } pass_gate_logic_model_ids_[model_id] = model(pass_gate_logic_model_names_[model_id]); + /* Get the circuit model id by name, skip those with empty names*/ + if (true == last_stage_pass_gate_logic_model_names_[model_id].empty()) { + return; + } + last_stage_pass_gate_logic_model_ids_[model_id] = + model(last_stage_pass_gate_logic_model_names_[model_id]); return; } diff --git a/libs/libarchopenfpga/src/circuit_library.h b/libs/libarchopenfpga/src/circuit_library.h index 30caef09c..75613628c 100644 --- a/libs/libarchopenfpga/src/circuit_library.h +++ b/libs/libarchopenfpga/src/circuit_library.h @@ -272,6 +272,7 @@ class CircuitLibrary { const CircuitModelId& model_id) const; /* Pass-gate-logic information */ CircuitModelId pass_gate_logic_model(const CircuitModelId& model_id) const; + CircuitModelId last_stage_pass_gate_logic_model(const CircuitModelId& model_id) const; std::string pass_gate_logic_model_name(const CircuitModelId& model_id) const; enum e_circuit_model_pass_gate_logic_type pass_gate_logic_type( const CircuitModelId& model_id) const; @@ -448,6 +449,8 @@ class CircuitLibrary { /* Pass-gate-related parameters */ void set_model_pass_gate_logic(const CircuitModelId& model_id, const std::string& model_name); + void set_model_last_stage_pass_gate_logic(const CircuitModelId& model_id, + const std::string& model_name); /* Port information */ CircuitPortId add_model_port(const CircuitModelId& model_id, const enum e_circuit_model_port_type& port_type); @@ -664,6 +667,8 @@ class CircuitLibrary { /* Pass-gate-related parameters */ vtr::vector pass_gate_logic_model_names_; vtr::vector pass_gate_logic_model_ids_; + vtr::vector last_stage_pass_gate_logic_model_names_; + vtr::vector last_stage_pass_gate_logic_model_ids_; /* Port information */ vtr::vector port_ids_; diff --git a/libs/libarchopenfpga/src/read_xml_circuit_library.cpp b/libs/libarchopenfpga/src/read_xml_circuit_library.cpp index 13ff84800..bd534779f 100644 --- a/libs/libarchopenfpga/src/read_xml_circuit_library.cpp +++ b/libs/libarchopenfpga/src/read_xml_circuit_library.cpp @@ -832,6 +832,20 @@ static void read_xml_circuit_model(pugi::xml_node& xml_model, circuit_lib.set_model_pass_gate_logic( model, get_attribute(xml_pass_gate_logic, "circuit_model_name", loc_data) .as_string()); + /* Last stage pass gate is optional */ + size_t num_last_stage_pgl = count_children(xml_model, "last_stage_pass_gate_logic", loc_data, pugiutil::ReqOpt::OPTIONAL); + if (0 < num_last_stage_pgl) { + auto xml_last_stage_pass_gate_logic = + get_single_child(xml_model, "last_stage_pass_gate_logic", loc_data); + circuit_lib.set_model_last_stage_pass_gate_logic( + model, get_attribute(xml_last_stage_pass_gate_logic, "circuit_model_name", loc_data) + .as_string()); + } else { + /* By default, assume the last stage circuit model is the same as others */ + circuit_lib.set_model_last_stage_pass_gate_logic( + model, get_attribute(xml_pass_gate_logic, "circuit_model_name", loc_data) + .as_string()); + } } /* Parse all the ports belonging to this circuit model diff --git a/libs/libarchopenfpga/src/write_xml_circuit_library.cpp b/libs/libarchopenfpga/src/write_xml_circuit_library.cpp index ac6867cea..56da46d77 100644 --- a/libs/libarchopenfpga/src/write_xml_circuit_library.cpp +++ b/libs/libarchopenfpga/src/write_xml_circuit_library.cpp @@ -593,6 +593,13 @@ static void write_xml_circuit_model(std::fstream& fp, const char* fname, circuit_lib.model_name(circuit_lib.pass_gate_logic_model(model)).c_str()); fp << "/>" << "\n"; + fp << "\t\t\t" + << "" + << "\n"; } /* Write the ports of circuit model */ diff --git a/openfpga/src/fabric/build_mux_modules.cpp b/openfpga/src/fabric/build_mux_modules.cpp index 3233db768..e7828eb86 100644 --- a/openfpga/src/fabric/build_mux_modules.cpp +++ b/openfpga/src/fabric/build_mux_modules.cpp @@ -461,6 +461,7 @@ static void build_cmos_mux_module_mux2_multiplexing_structure( /* We must have one */ VTR_ASSERT(ModuleId::INVALID() != std_cell_module_id); + /* Find the module ports of the standard cell MUX2 module */ std::vector std_cell_module_inputs; std::vector std_cell_module_input_ports; @@ -496,6 +497,61 @@ static void build_cmos_mux_module_mux2_multiplexing_structure( module_manager.module_port(std_cell_module_id, std_cell_module_output); VTR_ASSERT(1 == std_cell_module_output_port.get_width()); + /* Find module information of the standard cell MUX2 */ + CircuitModelId last_stage_std_cell_model = circuit_lib.model_last_stage_pass_gate_model(mux_model); + std::string last_stage_std_cell_module_name = circuit_lib.model_name(last_stage_std_cell_model); + /* Get the moduleId for the submodule */ + ModuleId last_stage_std_cell_module_id = + module_manager.find_module(last_stage_std_cell_module_name); + /* We must have one */ + VTR_ASSERT(ModuleId::INVALID() != last_stage_std_cell_module_id); + + /* Find the input ports and output ports of the standard cell */ + std::vector last_stage_std_cell_input_ports = + circuit_lib.model_ports_by_type(last_stage_std_cell_model, CIRCUIT_MODEL_PORT_INPUT, + true); + std::vector last_stage_std_cell_output_ports = + circuit_lib.model_ports_by_type(last_stage_std_cell_model, CIRCUIT_MODEL_PORT_OUTPUT, + true); + /* Quick check the requirements on port map */ + VTR_ASSERT(3 == last_stage_std_cell_input_ports.size()); + VTR_ASSERT(1 == last_stage_std_cell_output_ports.size()); + + /* Find the module ports of the standard cell MUX2 module */ + std::vector last_stage_std_cell_module_inputs; + std::vector last_stage_std_cell_module_input_ports; + /* Input 0 port is the first data path input of the tgate, whose size must be + * 1 ! */ + for (size_t port_id = 0; port_id < 2; ++port_id) { + last_stage_std_cell_module_inputs.push_back(module_manager.find_module_port( + last_stage_std_cell_module_id, + circuit_lib.port_prefix(last_stage_std_cell_input_ports[port_id]))); + VTR_ASSERT(true == module_manager.valid_module_port_id( + last_stage_std_cell_module_id, last_stage_std_cell_module_inputs[port_id])); + last_stage_std_cell_module_input_ports.push_back(module_manager.module_port( + last_stage_std_cell_module_id, last_stage_std_cell_module_inputs[port_id])); + VTR_ASSERT(1 == last_stage_std_cell_module_input_ports[port_id].get_width()); + } + + /* Mem port is the memory of the standard cell MUX2, whose size must be 1 ! */ + ModulePortId last_stage_std_cell_module_mem = module_manager.find_module_port( + last_stage_std_cell_module_id, circuit_lib.port_prefix(last_stage_std_cell_input_ports[2])); + VTR_ASSERT(true == module_manager.valid_module_port_id(last_stage_std_cell_module_id, + last_stage_std_cell_module_mem)); + BasicPort last_stage_std_cell_module_mem_port = + module_manager.module_port(last_stage_std_cell_module_id, last_stage_std_cell_module_mem); + VTR_ASSERT(1 == last_stage_std_cell_module_mem_port.get_width()); + + /* Output port is the data path output of the standard cell MUX2, whose size + * must be 1 ! */ + ModulePortId last_stage_std_cell_module_output = module_manager.find_module_port( + last_stage_std_cell_module_id, circuit_lib.port_prefix(last_stage_std_cell_output_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id( + last_stage_std_cell_module_id, last_stage_std_cell_module_output)); + BasicPort last_stage_std_cell_module_output_port = + module_manager.module_port(last_stage_std_cell_module_id, last_stage_std_cell_module_output); + VTR_ASSERT(1 == last_stage_std_cell_module_output_port.get_width()); + /* Cache Net ids for each level of the multiplexer */ std::vector> module_nets_by_level; module_nets_by_level.resize(mux_graph.num_node_levels()); @@ -518,11 +574,17 @@ static void build_cmos_mux_module_mux2_multiplexing_structure( /* To match the standard cell MUX2: We should have only 2 input_nodes */ VTR_ASSERT(2 == branch_size); + + /* Last stage MUX model may have a different name */ + ModuleId curr_stage_std_cell_module_id = std_cell_module_id; + if (true == mux_graph.is_node_output(node)) { + curr_stage_std_cell_module_id = last_stage_std_cell_module_id; + } /* Find the instance id */ size_t std_cell_instance_id = - module_manager.num_instance(mux_module, std_cell_module_id); + module_manager.num_instance(mux_module, curr_stage_std_cell_module_id); /* Add the module to mux_module */ - module_manager.add_child_module(mux_module, std_cell_module_id); + module_manager.add_child_module(mux_module, curr_stage_std_cell_module_id); /* Get the node level and index in the current level */ size_t output_node_level = mux_graph.node_level(node); @@ -530,7 +592,7 @@ static void build_cmos_mux_module_mux2_multiplexing_structure( /* Set a name for the instance */ std::string std_cell_instance_name = generate_mux_branch_instance_name( output_node_level, output_node_index_at_level, false); - module_manager.set_child_instance_name(mux_module, std_cell_module_id, + module_manager.set_child_instance_name(mux_module, curr_stage_std_cell_module_id, std_cell_instance_id, std_cell_instance_name); @@ -540,13 +602,16 @@ static void build_cmos_mux_module_mux2_multiplexing_structure( /* This is an output node, we should use existing output nets */ MuxOutputId output_id = mux_graph.output_id(node); branch_net = mux_module_output_nets[output_id]; + module_manager.add_module_net_source( + mux_module, branch_net, curr_stage_std_cell_module_id, std_cell_instance_id, + last_stage_std_cell_module_output, last_stage_std_cell_module_output_port.get_lsb()); } else { VTR_ASSERT(false == mux_graph.is_node_output(node)); branch_net = module_manager.create_module_net(mux_module); + module_manager.add_module_net_source( + mux_module, branch_net, curr_stage_std_cell_module_id, std_cell_instance_id, + std_cell_module_output, std_cell_module_output_port.get_lsb()); } - module_manager.add_module_net_source( - mux_module, branch_net, std_cell_module_id, std_cell_instance_id, - std_cell_module_output, std_cell_module_output_port.get_lsb()); /* Record the module net id in the cache */ module_nets_by_level[output_node_level][output_node_index_at_level] = @@ -567,10 +632,17 @@ static void build_cmos_mux_module_mux2_multiplexing_structure( * Note that standard cell MUX2 only needs mem but NOT mem_inv */ for (const MuxMemId& mem : mems) { - module_manager.add_module_net_sink( - mux_module, mux_module_mem_nets[mem], std_cell_module_id, - std_cell_instance_id, std_cell_module_mem, - std_cell_module_mem_port.get_lsb()); + if (true == mux_graph.is_node_output(node)) { + module_manager.add_module_net_sink( + mux_module, mux_module_mem_nets[mem], std_cell_module_id, + std_cell_instance_id, std_cell_module_mem, + std_cell_module_mem_port.get_lsb()); + } else { + module_manager.add_module_net_sink( + mux_module, mux_module_mem_nets[mem], last_stage_std_cell_module_id, + last_stage_std_cell_instance_id, last_stage_std_cell_module_mem, + last_stage_std_cell_module_mem_port.get_lsb()); + } } /* Wire the branch module inputs to the nets in previous stage */ @@ -602,8 +674,15 @@ static void build_cmos_mux_module_mux2_multiplexing_structure( mux_module, mux_module_input_nets[input_id], std_cell_module_id, std_cell_instance_id, std_cell_module_inputs[node_id], std_cell_module_input_ports[node_id].get_lsb()); + } else if (true == mux_graph.is_node_output(node)) { + /* Find the input port of standard cell */ + module_manager.add_module_net_sink( + mux_module, + module_nets_by_level[input_node_level][input_node_index_at_level], + last_stage_std_cell_module_id, std_cell_instance_id, + last_stage_std_cell_module_inputs[node_id], + last_stage_std_cell_module_input_ports[node_id].get_lsb()); } else { - VTR_ASSERT(false == mux_graph.is_node_input(input_nodes[node_id])); /* Find the input port of standard cell */ module_manager.add_module_net_sink( mux_module,