<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 CheckAnalogIbuf(Greenpak4BitstreamEntity* load, Greenpak4IOB* iob);

/**
	@brief The main place-and-route logic
 */
bool DoPAR(Greenpak4Netlist* netlist, Greenpak4Device* device)
{
	labelmap lmap;

	//Create the graphs
	LogNotice("\nCreating netlist graphs...\n");
	PARGraph* ngraph = NULL;
	PARGraph* dgraph = NULL;
	BuildGraphs(netlist, device, ngraph, dgraph, lmap);

	//Create and run the PAR engine
	Greenpak4PAREngine engine(ngraph, dgraph, lmap);
	if(!engine.PlaceAndRoute(lmap, true))
	{
		//Print the placement we have so far
		PrintPlacementReport(ngraph, device);

		LogNotice("PAR failed\n");
		return false;
	}

	//Copy the netlist over
	unsigned int num_routes_used[2];
	if(!CommitChanges(dgraph, device, num_routes_used))
	{
		LogNotice("Final routing failed\n");

		//Placement is done, so print the placement report before we die
		PrintUtilizationReport(ngraph, device, num_routes_used);
		PrintPlacementReport(ngraph, device);
		return false;
	}

	//Final DRC to make sure the placement is sane
	PostPARDRC(ngraph, device);

	//Print reports
	PrintUtilizationReport(ngraph, device, num_routes_used);
	PrintPlacementReport(ngraph, device);

	//Final cleanup
	delete ngraph;
	delete dgraph;
	return true;
}

/**
	@brief Do various sanity checks after the design is routed
 */
void PostPARDRC(PARGraph* netlist, Greenpak4Device* device)
{
	LogNotice("\nChecking post-route design rules...\n");

	//Check for nodes in the netlist that have no load
	for(uint32_t i=0; i<netlist->GetNumNodes(); i++)
	{
		auto node = netlist->GetNodeByIndex(i);
		auto src = static_cast<Greenpak4NetlistEntity*>(node->GetData());
		auto mate = node->GetMate();
		auto dst = static_cast<Greenpak4BitstreamEntity*>(mate->GetData());

		//Sanity check - must be fully PAR'd
		if(mate == NULL)
		{
			LogError(
				"Node \"%s\" is not mapped to any site in the device\n",
				src->m_name.c_str());
			exit(-1);
		}

		//Do not warn if power rails have no load, that's perfectly normal
		if(dynamic_cast<Greenpak4PowerRail*>(dst) != NULL)
			continue;

		//If the node has no output ports, of course it won't have any loads
		if(dst->GetOutputPorts().size() == 0)
			continue;

		//If the node is an IOB configured as an output, there's no internal load for its output.
		//This is perfectly normal, obviously.
		Greenpak4NetlistCell* cell = dynamic_cast<Greenpak4NetlistCell*>(src);
		if( (cell != NULL) &&  ( (cell->m_type == "GP_IOBUF") || (cell->m_type == "GP_OBUF") ) )
			continue;

		//If we have no loads, warn
		if(node->GetEdgeCount() == 0)
		{
			LogWarning(
				"Node \"%s\" has no load\n",
				src->m_name.c_str());
		}

	}

	//TODO: check floating inputs etc

	//Check invalid IOB configuration
	//TODO: driving an input-only pin etc - is this possible?
	for(auto it = device->iobbegin(); it != device->iobend(); it ++)
	{
		Greenpak4IOB* iob = it->second;

		auto signal = iob->GetOutputSignal();
		auto src = signal.GetRealEntity();

		if(!iob->IsAnalogIbuf())
		{
			//Check for analog output driving a pin not configured as analog for the input
			if(	(dynamic_cast<Greenpak4VoltageReference*>(src) != NULL) ||
				(dynamic_cast<Greenpak4PGA*>(src) != NULL) )
			{
				LogError("Pin %d is driven by an analog source (%s) but does not have IBUF_TYPE = ANALOG\n",
					it->first,
					signal.GetOutputName().c_str()
					);
				exit(-1);
			}
		}
	}

	//Check for ACMPs with inputs driven from non-analog IOs
	for(unsigned int i=0; i<device->GetAcmpCount(); i++)
	{
		auto acmp = device->GetAcmp(i);
		CheckAnalogIbuf(acmp, dynamic_cast<Greenpak4IOB*>(acmp->GetInput().GetRealEntity()));
	}

	//Check for ABUF with inputs driven from non-analog IOs
	auto abuf = device->GetAbuf();
	CheckAnalogIbuf(abuf, dynamic_cast<Greenpak4IOB*>(abuf->GetInput().GetRealEntity()));

	//Check for PGA with inputs driven from non-analog IOs
	auto pga = device->GetPGA();
	CheckAnalogIbuf(abuf, dynamic_cast<Greenpak4IOB*>(pga->GetInputP().GetRealEntity()));
	CheckAnalogIbuf(abuf, dynamic_cast<Greenpak4IOB*>(pga->GetInputN().GetRealEntity()));

	//TODO: Check for VREF with inputs driven from non-analog IOs

	//Check for multiple ACMPs using different settings of ACMP0's output mux
	typedef pair<string, Greenpak4EntityOutput> spair;
	switch(device->GetPart())
	{
		case Greenpak4Device::GREENPAK4_SLG46620:
			{
				auto pin6 = device->GetIOB(6)->GetOutput("");
				auto vdd = device->GetPower();
				auto gnd = device->GetGround();

				vector<spair> inputs;

				//Loop over each ACMP that could possibly use the ACMP0 (shared) mux
				for(unsigned int i=0; i<device->GetAcmpCount(); i++)
				{
					auto acmp = device->GetAcmp(i);
					auto input = acmp->GetInput();

					//If this comparator is not using one of ACMP0's inputs, we don't care
					//TODO: buffered pin 6 is a candidate too
					if((input != pin6) && (input != vdd) )
						continue;<commit_msg>gp4par: DRC messages are now indented. Added some skeleton code for PGA conflicts with IOB or ADC, but not yet functional as ADC isn't implemented.<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 CheckAnalogIbuf(Greenpak4BitstreamEntity* load, Greenpak4IOB* iob);

/**
	@brief The main place-and-route logic
 */
bool DoPAR(Greenpak4Netlist* netlist, Greenpak4Device* device)
{
	labelmap lmap;

	//Create the graphs
	LogNotice("\nCreating netlist graphs...\n");
	PARGraph* ngraph = NULL;
	PARGraph* dgraph = NULL;
	BuildGraphs(netlist, device, ngraph, dgraph, lmap);

	//Create and run the PAR engine
	Greenpak4PAREngine engine(ngraph, dgraph, lmap);
	if(!engine.PlaceAndRoute(lmap, true))
	{
		//Print the placement we have so far
		PrintPlacementReport(ngraph, device);

		LogNotice("PAR failed\n");
		return false;
	}

	//Copy the netlist over
	unsigned int num_routes_used[2];
	if(!CommitChanges(dgraph, device, num_routes_used))
	{
		LogNotice("Final routing failed\n");

		//Placement is done, so print the placement report before we die
		PrintUtilizationReport(ngraph, device, num_routes_used);
		PrintPlacementReport(ngraph, device);
		return false;
	}

	//Final DRC to make sure the placement is sane
	PostPARDRC(ngraph, device);

	//Print reports
	PrintUtilizationReport(ngraph, device, num_routes_used);
	PrintPlacementReport(ngraph, device);

	//Final cleanup
	delete ngraph;
	delete dgraph;
	return true;
}

/**
	@brief Do various sanity checks after the design is routed
 */
void PostPARDRC(PARGraph* netlist, Greenpak4Device* device)
{
	LogNotice("\nChecking post-route design rules...\n");
	LogIndenter li;

	//Check for nodes in the netlist that have no load
	for(uint32_t i=0; i<netlist->GetNumNodes(); i++)
	{
		auto node = netlist->GetNodeByIndex(i);
		auto src = static_cast<Greenpak4NetlistEntity*>(node->GetData());
		auto mate = node->GetMate();
		auto dst = static_cast<Greenpak4BitstreamEntity*>(mate->GetData());

		//Sanity check - must be fully PAR'd
		if(mate == NULL)
		{
			LogError(
				"Node \"%s\" is not mapped to any site in the device\n",
				src->m_name.c_str());
			exit(-1);
		}

		//Do not warn if power rails have no load, that's perfectly normal
		if(dynamic_cast<Greenpak4PowerRail*>(dst) != NULL)
			continue;

		//If the node has no output ports, of course it won't have any loads
		if(dst->GetOutputPorts().size() == 0)
			continue;

		//If the node is an IOB configured as an output, there's no internal load for its output.
		//This is perfectly normal, obviously.
		Greenpak4NetlistCell* cell = dynamic_cast<Greenpak4NetlistCell*>(src);
		if( (cell != NULL) &&  ( (cell->m_type == "GP_IOBUF") || (cell->m_type == "GP_OBUF") ) )
			continue;

		//If we have no loads, warn
		if(node->GetEdgeCount() == 0)
		{
			LogWarning(
				"Node \"%s\" has no load\n",
				src->m_name.c_str());
		}

	}

	//TODO: check floating inputs etc

	//Check invalid IOB configuration
	//TODO: driving an input-only pin etc - is this possible?
	for(auto it = device->iobbegin(); it != device->iobend(); it ++)
	{
		Greenpak4IOB* iob = it->second;

		auto signal = iob->GetOutputSignal();
		auto src = signal.GetRealEntity();

		if(!iob->IsAnalogIbuf())
		{
			//Check for analog output driving a pin not configured as analog for the input
			if(	(dynamic_cast<Greenpak4VoltageReference*>(src) != NULL) ||
				(dynamic_cast<Greenpak4PGA*>(src) != NULL) )
			{
				LogError("Pin %d is driven by an analog source (%s) but does not have IBUF_TYPE = ANALOG\n",
					it->first,
					signal.GetOutputName().c_str()
					);
				exit(-1);
			}
		}
	}

	//Check for ACMPs with inputs driven from non-analog IOs
	for(unsigned int i=0; i<device->GetAcmpCount(); i++)
	{
		auto acmp = device->GetAcmp(i);
		CheckAnalogIbuf(acmp, dynamic_cast<Greenpak4IOB*>(acmp->GetInput().GetRealEntity()));
	}

	//Check for ABUF with inputs driven from non-analog IOs
	auto abuf = device->GetAbuf();
	if(abuf)
		CheckAnalogIbuf(abuf, dynamic_cast<Greenpak4IOB*>(abuf->GetInput().GetRealEntity()));

	//Check for PGA with inputs driven from non-analog IOs
	auto pga = device->GetPGA();
	if(pga)
	{
		CheckAnalogIbuf(abuf, dynamic_cast<Greenpak4IOB*>(pga->GetInputP().GetRealEntity()));
		CheckAnalogIbuf(abuf, dynamic_cast<Greenpak4IOB*>(pga->GetInputN().GetRealEntity()));
	}

	//TODO: Check for VREF with inputs driven from non-analog IOs

	//TODO: Check for PGA driving an IOB when ADC is enabled
	//auto adc = device->GetADC();
	if(pga /*&& adc*/)
	{
		//We do not yet implement the ADC
		//so nothing to do here
	}

	//Check for multiple ACMPs using different settings of ACMP0's output mux
	typedef pair<string, Greenpak4EntityOutput> spair;
	switch(device->GetPart())
	{
		case Greenpak4Device::GREENPAK4_SLG46620:
			{
				auto pin6 = device->GetIOB(6)->GetOutput("");
				auto vdd = device->GetPower();
				auto gnd = device->GetGround();

				vector<spair> inputs;

				//Loop over each ACMP that could possibly use the ACMP0 (shared) mux
				for(unsigned int i=0; i<device->GetAcmpCount(); i++)
				{
					auto acmp = device->GetAcmp(i);
					auto input = acmp->GetInput();

					//If this comparator is not using one of ACMP0's inputs, we don't care
					//TODO: buffered pin 6 is a candidate too
					if((input != pin6) && (input != vdd) )
						continue;
{'fraction_non_alphanumeric': 0.1388111888111888, 'fraction_numerical': 0.00916083916083916, 'mean_word_length': 2.4593613933236576, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 96, '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': '2814989', 'n_tokens_mistral': 4491, 'n_tokens_neox': 4046, 'n_words': 1295}