<commit_before>/***********************************************************************************************************************
 * Copyright (C) 2016 <NAME> and contributors                                                                *
 *                                                                                                                     *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General   *
 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
 * any later version.                                                                                                  *
 *                                                                                                                     *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied  *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for     *
 * more details.                                                                                                       *
 *                                                                                                                     *
 * You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may   *
 * find one here:                                                                                                      *
 * https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt                                                              *
 * or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA                                      *
 **********************************************************************************************************************/

#include "gp4par.h"

using namespace std;

void MakeNetlistEdges(Greenpak4Netlist* netlist);
void MakeDeviceEdges(Greenpak4Device* device);

void MakeNetlistNodes(
	Greenpak4Netlist* netlist,
	PARGraph*& ngraph,
	ilabelmap& ilmap);

void MakeDeviceNodes(
	Greenpak4Device* device,
	PARGraph*& ngraph,
	PARGraph*& dgraph,
	labelmap& lmap);

void MakeSingleNode(
	string type,
	Greenpak4BitstreamEntity* entity,
	PARGraph* ngraph,
	PARGraph* dgraph,
	labelmap& lmap);
	
PARGraphNode* MakeNode(
	uint32_t label,
	Greenpak4BitstreamEntity* entity,
	PARGraph* dgraph);
	
void InferExtraNodes(
	Greenpak4Netlist* netlist,
	Greenpak4Device* device,
	PARGraph*& ngraph,
	ilabelmap& ilap);

/**
	@brief Build the graphs
 */
void BuildGraphs(
	Greenpak4Netlist* netlist,
	Greenpak4Device* device,
	PARGraph*& ngraph,
	PARGraph*& dgraph,
	labelmap& lmap)
{
	//Create the graphs
	ngraph = new PARGraph;
	dgraph = new PARGraph;
	
	//Create the device graph.
	//This is independent of the final netlist and has to be done first to assign graph labels
	MakeDeviceNodes(device, ngraph, dgraph, lmap);
	MakeDeviceEdges(device);
	
	//Build inverse label map
	ilabelmap ilmap;
	for(auto it : lmap)
		ilmap[it.second] = it.first;
	
	//Create all of the nodes for the netlist, then connect with edges.
	//This requires breaking point-to-multipoint nets into multiple point-to-point links.
	MakeNetlistNodes(netlist, ngraph, ilmap);
	MakeNetlistEdges(netlist);
	
	//Infer extra support nodes for things that use hidden functions of others
	InferExtraNodes(netlist, device, ngraph, ilmap);
}

/**
	@brief Add extra nodes to handle dependencies between nodes that share hard IP under the hood
 */
void InferExtraNodes(
	Greenpak4Netlist* netlist,
	Greenpak4Device* device,
	PARGraph*& ngraph,
	ilabelmap& ilmap)
{
	LogVerbose("Replicating nodes to control hard IP dependencies...\n");
	
	bool madeChanges = false;
	
	//Cache power rails, as they're frequently used
	auto top = netlist->GetTopModule();
	auto vdd = top->GetNet("GP_VDD");
	auto vddn = device->GetPowerRail(true)->GetPARNode();

	//If one GP_VREF drives multiple GP_ACMP blocks, split it
	Greenpak4NetlistModule* module = netlist->GetTopModule();
	for(auto it = module->cell_begin(); it != module->cell_end(); it ++)
	{
		//See if we're a VREF
		Greenpak4NetlistCell* cell = it->second;
		if(cell->m_type != "GP_VREF")
			continue;
			
		//See what we drive
		auto net = cell->m_connections["VOUT"][0];
		bool found_acmp = false;
		for(int i=net->m_nodeports.size()-1; i>=0; i--)
		{
			//Skip anything not a comparator
			auto load = net->m_nodeports[i].m_cell;
			if(load->m_type != "GP_ACMP")
				continue;
				
			//If this is the first one, flag it but don't do anything
			if(!found_acmp)
			{
				found_acmp = true;
				continue;
			}
			
			//We have a second ACMP.
			//Need to create a new net and VREF in both netlists to fix it
			LogDebug("    VREF %s drives multiple ACMPs, replicating to drive ACMP %s\n",
				cell->m_name.c_str(),
				load->m_name.c_str());
			madeChanges = true;
			
			//Monotonically increasing counter used to ensure unique node IDs
			static unsigned int vref_id = 1;
				
			//Create a new VREF and copy the input config
			Greenpak4NetlistCell* vref = new Greenpak4NetlistCell(module);
			vref->m_type = "GP_VREF";
			vref->m_connections["VIN"].push_back(cell->m_connections["VIN"][0]);
			vref->m_parameters = cell->m_parameters;
			vref->m_attributes = cell->m_attributes;
			
			//Give it a name
			char tmp[128];
			snprintf(tmp, sizeof(tmp), "$auto$make_graphs.cpp:%d:vref$%u",
				__LINE__,
				vref_id ++);
			vref->m_name = tmp;
			
			//and add it to the module
			module->AddCell(vref);
			
			//Create a net for the output
			snprintf(tmp, sizeof(tmp), "$auto$make_graphs.cpp:%d:vref$%u",
				__LINE__,
				vref_id ++);
			Greenpak4NetlistNode* vout = new Greenpak4NetlistNode;
			vout->m_name = tmp;
			vout->m_src_locations = net->m_src_locations;
			
			//and add it to the module
			module->AddNet(net);
			
			//Hook up the output
			vref->m_connections["VOUT"].push_back(vout);
			load->m_connections["VREF"].clear();
			load->m_connections["VREF"].push_back(vout);
			
			//Remove stale edge in the PAR graph	
			cell->m_parnode->RemoveEdge("VOUT", load->m_parnode, "VREF");
			
			//Create the PAR node for it
			PARGraphNode* nnode = new PARGraphNode(ilmap[vref->m_type], vref);
			vref->m_parnode = nnode;
			ngraph->AddNode(nnode);
			
			//Copy the netlist edges to the PAR graph
			//TODO: automate this somehow? Seems error-prone to do it twice
			//vref->m_parnode->AddEdge("VOUT", nnode, "VREF");
			//vddn->AddEdge("OUT", nnode, "PWREN");
			
			//Done
			madeChanges = true;
		}
	}
	
	//Re-index the graph if we changed it
	if(madeChanges)
	{
		LogVerbose("    Re-indexing graph because we inferred additional nodes..\n");
		netlist->Reindex();
		ngraph->IndexNodesByLabel();
		madeChanges = false;
	}

	//Look for IOBs driven by GP_VREF cells
	for(auto it = module->cell_begin(); it != module->cell_end(); it ++)
	{
		//See if we're an IOB
		Greenpak4NetlistCell* cell = it->second;
		if(!cell->IsIOB())
			continue;
		
		//See if we're driven by a GP_VREF
		auto net = cell->m_connections["IN"][0];
		auto driver = net->m_driver;<commit_msg>gp4par: Added missing graph edge in VREF replication<commit_after>/***********************************************************************************************************************
 * Copyright (C) 2016 <NAME> and contributors                                                                *
 *                                                                                                                     *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General   *
 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
 * any later version.                                                                                                  *
 *                                                                                                                     *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied  *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for     *
 * more details.                                                                                                       *
 *                                                                                                                     *
 * You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may   *
 * find one here:                                                                                                      *
 * https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt                                                              *
 * or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA                                      *
 **********************************************************************************************************************/

#include "gp4par.h"

using namespace std;

void MakeNetlistEdges(Greenpak4Netlist* netlist);
void MakeDeviceEdges(Greenpak4Device* device);

void MakeNetlistNodes(
	Greenpak4Netlist* netlist,
	PARGraph*& ngraph,
	ilabelmap& ilmap);

void MakeDeviceNodes(
	Greenpak4Device* device,
	PARGraph*& ngraph,
	PARGraph*& dgraph,
	labelmap& lmap);

void MakeSingleNode(
	string type,
	Greenpak4BitstreamEntity* entity,
	PARGraph* ngraph,
	PARGraph* dgraph,
	labelmap& lmap);
	
PARGraphNode* MakeNode(
	uint32_t label,
	Greenpak4BitstreamEntity* entity,
	PARGraph* dgraph);
	
void InferExtraNodes(
	Greenpak4Netlist* netlist,
	Greenpak4Device* device,
	PARGraph*& ngraph,
	ilabelmap& ilap);

/**
	@brief Build the graphs
 */
void BuildGraphs(
	Greenpak4Netlist* netlist,
	Greenpak4Device* device,
	PARGraph*& ngraph,
	PARGraph*& dgraph,
	labelmap& lmap)
{
	//Create the graphs
	ngraph = new PARGraph;
	dgraph = new PARGraph;
	
	//Create the device graph.
	//This is independent of the final netlist and has to be done first to assign graph labels
	MakeDeviceNodes(device, ngraph, dgraph, lmap);
	MakeDeviceEdges(device);
	
	//Build inverse label map
	ilabelmap ilmap;
	for(auto it : lmap)
		ilmap[it.second] = it.first;
	
	//Create all of the nodes for the netlist, then connect with edges.
	//This requires breaking point-to-multipoint nets into multiple point-to-point links.
	MakeNetlistNodes(netlist, ngraph, ilmap);
	MakeNetlistEdges(netlist);
	
	//Infer extra support nodes for things that use hidden functions of others
	InferExtraNodes(netlist, device, ngraph, ilmap);
}

/**
	@brief Add extra nodes to handle dependencies between nodes that share hard IP under the hood
 */
void InferExtraNodes(
	Greenpak4Netlist* netlist,
	Greenpak4Device* device,
	PARGraph*& ngraph,
	ilabelmap& ilmap)
{
	LogVerbose("Replicating nodes to control hard IP dependencies...\n");
	
	bool madeChanges = false;
	
	//Cache power rails, as they're frequently used
	auto top = netlist->GetTopModule();
	auto vdd = top->GetNet("GP_VDD");
	auto vddn = device->GetPowerRail(true)->GetPARNode();

	//If one GP_VREF drives multiple GP_ACMP blocks, split it
	Greenpak4NetlistModule* module = netlist->GetTopModule();
	for(auto it = module->cell_begin(); it != module->cell_end(); it ++)
	{
		//See if we're a VREF
		Greenpak4NetlistCell* cell = it->second;
		if(cell->m_type != "GP_VREF")
			continue;
			
		//See what we drive
		auto net = cell->m_connections["VOUT"][0];
		bool found_acmp = false;
		for(int i=net->m_nodeports.size()-1; i>=0; i--)
		{
			//Skip anything not a comparator
			auto load = net->m_nodeports[i].m_cell;
			if(load->m_type != "GP_ACMP")
				continue;
				
			//If this is the first one, flag it but don't do anything
			if(!found_acmp)
			{
				found_acmp = true;
				continue;
			}
			
			//We have a second ACMP.
			//Need to create a new net and VREF in both netlists to fix it
			LogDebug("    VREF %s drives multiple ACMPs, replicating to drive ACMP %s\n",
				cell->m_name.c_str(),
				load->m_name.c_str());
			madeChanges = true;
			
			//Monotonically increasing counter used to ensure unique node IDs
			static unsigned int vref_id = 1;
				
			//Create a new VREF and copy the input config
			Greenpak4NetlistCell* vref = new Greenpak4NetlistCell(module);
			vref->m_type = "GP_VREF";
			vref->m_connections["VIN"].push_back(cell->m_connections["VIN"][0]);
			vref->m_parameters = cell->m_parameters;
			vref->m_attributes = cell->m_attributes;
			
			//Give it a name
			char tmp[128];
			snprintf(tmp, sizeof(tmp), "$auto$make_graphs.cpp:%d:vref$%u",
				__LINE__,
				vref_id ++);
			vref->m_name = tmp;
			
			//and add it to the module
			module->AddCell(vref);
			
			//Create a net for the output
			snprintf(tmp, sizeof(tmp), "$auto$make_graphs.cpp:%d:vref$%u",
				__LINE__,
				vref_id ++);
			Greenpak4NetlistNode* vout = new Greenpak4NetlistNode;
			vout->m_name = tmp;
			vout->m_src_locations = net->m_src_locations;
			
			//and add it to the module
			module->AddNet(net);
			
			//Hook up the output
			vref->m_connections["VOUT"].push_back(vout);
			load->m_connections["VREF"].clear();
			load->m_connections["VREF"].push_back(vout);
			
			//Remove stale edge in the PAR graph	
			cell->m_parnode->RemoveEdge("VOUT", load->m_parnode, "VREF");
			
			//Create the PAR node for it
			PARGraphNode* nnode = new PARGraphNode(ilmap[vref->m_type], vref);
			vref->m_parnode = nnode;
			ngraph->AddNode(nnode);
			
			//Copy the netlist edges to the PAR graph
			//TODO: automate this somehow? Seems error-prone to do it twice
			nnode->AddEdge("VOUT", load->m_parnode, "VREF");
			
			//Done
			madeChanges = true;
		}
	}
	
	//Re-index the graph if we changed it
	if(madeChanges)
	{
		LogVerbose("    Re-indexing graph because we inferred additional nodes..\n");
		netlist->Reindex();
		ngraph->IndexNodesByLabel();
		madeChanges = false;
	}

	//Look for IOBs driven by GP_VREF cells
	for(auto it = module->cell_begin(); it != module->cell_end(); it ++)
	{
		//See if we're an IOB
		Greenpak4NetlistCell* cell = it->second;
		if(!cell->IsIOB())
			continue;
		
		//See if we're driven by a GP_VREF
		auto net = cell->m_connections["IN"][0];
		auto driver = net->m_driver;
{'fraction_non_alphanumeric': 0.13170131291028447, 'fraction_numerical': 0.007179978118161926, 'mean_word_length': 2.41147655703289, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 102, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 64, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2236897', 'n_tokens_mistral': 4803, 'n_tokens_neox': 4268, 'n_words': 1315}