<commit_before>#include "OpenGLSystem.h"
#include "GLSLShader.h"
#include "GLSixDOFView.h"
#include "../components/GLSprite.h"
#include "../components/GLIcoSphere.h"
#include "../components/GLCubeSphere.h"
#include "../components/GLMesh.h"

OpenGLSystem::OpenGLSystem() : windowWidth(800), windowHeight(600), deltaAccumulator(0.0) {
	this->view = new GLSixDOFView();
}

OpenGLSystem::~OpenGLSystem() {
	delete this->view;
}

std::map<std::string, Sigma::IFactory::FactoryFunction>
        OpenGLSystem::getFactoryFunctions()
{
    using namespace std::placeholders;
    std::map<std::string, Sigma::IFactory::FactoryFunction> retval;
	retval["GLSprite"] = std::bind(&OpenGLSystem::createGLSprite,this,_1,_2);
    retval["GLIcoSphere"] = std::bind(&OpenGLSystem::createGLIcoSphere,this,_1,_2);
    retval["GLCubeSphere"] = std::bind(&OpenGLSystem::createGLCubeSphere,this,_1,_2);
    retval["GLMesh"] = std::bind(&OpenGLSystem::createGLMesh,this,_1,_2);

	// Not supported in VS2012
    /*{
        {"GLSprite",std::bind(&OpenGLSystem::createGLSprite,this,_1,_2,_3)},
        {"GLIcoSphere",std::bind(&OpenGLSystem::createGLIcoSphere,this,_1,_2,_3)},
        {"GLCubeSphere",std::bind(&OpenGLSystem::createGLCubeSphere,this,_1,_2,_3)},
        {"GLMesh",std::bind(&OpenGLSystem::createGLMesh,this,_1,_2,_3)}
    };*/
    return retval;
}

void OpenGLSystem::createGLSprite(const unsigned int entityID, std::vector<Property> &properties) {
	GLSprite* spr = new GLSprite(entityID);
	float scale = 1.0f;
	float x = 0.0f;
	float y = 0.0f;
	float z = 0.0f;
	int componentID = 0;
	std::string textureFilename;
	spr->InitializeBuffers();

	for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
		Property*  p = &(*propitr);
		if (p->GetName() == "scale") {
			scale = p->Get<float>();
		} else if (p->GetName() == "x") {
			x = p->Get<float>();
		} else if (p->GetName() == "y") {
			y = p->Get<float>();
		} else if (p->GetName() == "z") {
			z = p->Get<float>();
		} else if (p->GetName() == "id") {
			componentID = p->Get<int>();
		} else if (p->GetName() == "textureFilename"){
			textureFilename = p->Get<std::string>();
		}
	}
	spr->LoadTexture(textureFilename);
	spr->Transform()->Scale(glm::vec3(scale));
	spr->Transform()->Translate(x,y,z);
	this->addComponent(entityID,spr);
}

void OpenGLSystem::createGLIcoSphere(const unsigned int entityID, std::vector<Property> &properties) {
		Sigma::GLIcoSphere* sphere = new Sigma::GLIcoSphere(entityID);
		float scale = 1.0f;
		float x = 0.0f;
		float y = 0.0f;
		float z = 0.0f;
		int componentID = 0;
		std::string shader_name = "shaders/icosphere";

		for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
			Property*  p = &(*propitr);
			if (p->GetName() == "scale") {
				scale = p->Get<float>();
				continue;
			} else if (p->GetName() == "x") {
				x = p->Get<float>();
				continue;
			} else if (p->GetName() == "y") {
				y = p->Get<float>();
				continue;
			} else if (p->GetName() == "z") {
				z = p->Get<float>();
				continue;
			} else if (p->GetName() == "id") {
				componentID = p->Get<int>();
			} else if (p->GetName() == "shader"){
                shader_name = p->Get<std::string>();
			}
		}
		sphere->Transform()->Scale(scale,scale,scale);
		sphere->Transform()->Translate(x,y,z);
		sphere->LoadShader(shader_name);
		sphere->InitializeBuffers();
		sphere->SetCullFace("back");
		this->addComponent(entityID,sphere);
}

void OpenGLSystem::createGLCubeSphere(const unsigned int entityID, std::vector<Property> &properties) {
		Sigma::GLCubeSphere* sphere = new Sigma::GLCubeSphere(entityID);

		std::string texture_name = "";
		std::string shader_name = "shaders/cubesphere";
		std::string cull_face = "back";
		int subdivision_levels = 1;
		float rotation_speed = 0.0f;
		bool fix_to_camera = false;

		float scale = 1.0f;
		float x = 0.0f;
		float y = 0.0f;
		float z = 0.0f;
		int componentID = 0;
		for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
			Property*  p = &(*propitr);
			if (p->GetName() == "scale") {
				scale = p->Get<float>();
				continue;
			} else if (p->GetName() == "x") {
				x = p->Get<float>();
				continue;
			} else if (p->GetName() == "y") {
				y = p->Get<float>();
				continue;
			} else if (p->GetName() == "z") {
				z = p->Get<float>();
				continue;
			} else if (p->GetName() == "subdivision_levels") {
				subdivision_levels = p->Get<int>();
			} else if (p->GetName() == "texture") {
				texture_name = p->Get<std::string>();
			} else if (p->GetName() == "shader") {
				shader_name = p->Get<std::string>();
			} else if (p->GetName() == "id") {
				componentID = p->Get<int>();
			} else if (p->GetName() == "cullface") {
				cull_face = p->Get<std::string>();
			} else if (p->GetName() == "rotation_speed") {
				rotation_speed = p->Get<float>();
			} else if (p->GetName() == "fix_to_camera") {
				fix_to_camera = p->Get<bool>();
			}
		}

		sphere->SetFixToCamera(fix_to_camera);
		sphere->SetRotationSpeed(rotation_speed);
		sphere->SetCullFace(cull_face);
		sphere->SetSubdivisions(subdivision_levels);
		sphere->LoadShader(shader_name);
		sphere->LoadTexture(texture_name);

		sphere->Transform()->Scale(scale,scale,scale);
		sphere->Transform()->Translate(x,y,z);
		sphere->InitializeBuffers();
		this->addComponent(entityID,sphere);
}
void OpenGLSystem::createGLMesh(const unsigned int entityID, std::vector<Property> &properties) {
        Sigma::GLMesh* mesh = new Sigma::GLMesh(entityID);

		float scale = 1.0f;
		float x = 0.0f;
		float y = 0.0f;
		float z = 0.0f;
		float rx = 0.0f;
		float ry = 0.0f;
		float rz = 0.0f;
		int componentID = 0;
		std::string cull_face = "back";
		std::string shaderfile = "";

		for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
			Property*  p = &*propitr;
			if (p->GetName() == "scale") {
				scale = p->Get<float>();
				continue;
			} else if (p->GetName() == "x") {
				x = p->Get<float>();
				continue;
			} else if (p->GetName() == "y") {
				y = p->Get<float>();
				continue;
			} else if (p->GetName() == "z") {
				z = p->Get<float>();
				continue;
			} else if (p->GetName() == "rx") {
				rx = p->Get<float>();
				continue;
			} else if (p->GetName() == "ry") {
				ry = p->Get<float>();
				continue;
			} else if (p->GetName() == "rz") {
				rz = p->Get<float>();
				continue;
			} else if (p->GetName() == "meshFile") {
				mesh->LoadMesh(p->Get<std::string>());
			} else if (p->GetName() == "shader"){
                shaderfile = p->Get<std::string>();
            } else if (p->GetName() == "id") {
				componentID = p->Get<int>();
			} else if (p->GetName() == "cullface") {
				cull_face = p->Get<std::string>();
			}
		}

		mesh->SetCullFace(cull_face);
		mesh->Transform()->Scale(scale,scale,scale);
		mesh->Transform()->Translate(x,y,z);
		mesh->Transform()->Rotate(rx,ry,rz);
		if(shaderfile != "") mesh->LoadShader(shaderfile);
        else mesh->LoadShader(); // load default
		mesh->InitializeBuffers();
		this->addComponent(entityID,mesh);
}

bool OpenGLSystem::Update(const double delta) {
	this->deltaAccumulator += delta;
	this->view->UpdateViewMatrix();

	// Check if the deltaAccumulator is greater than 1/60 of a second.
	if (deltaAccumulator > 16.7) {
		this->view->UpdateViewMatrix();
		// Set up the scene to a "clean" state.
		glClearColor(0.0f,0.0f,0.0f,0.0f);
		glViewport(0, 0, windowWidth, windowHeight); // Set the viewport size to fill the window
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers

		// Set the ViewProjection matrix to be used in the shader.
		// Loop through and draw each component.
		for (auto eitr = this->_Components.begin(); eitr != this->_Components.end(); ++eitr) {
			for (auto citr = eitr->second.begin(); citr != eitr->second.end(); ++citr) {
				citr->second->Render(&this->view->ViewMatrix[0][0], &this->ProjectionMatrix[0][0]);
			}
		}

		this->deltaAccumulator = 0.0;
		return true;
	}
	return false;
}

const int* OpenGLSystem::Start() {
	//Checking GL version
	const GLubyte *GLVersionString = glGetString(GL_VERSION);

	//Or better yet, use the GL3 way to get the version number
	glGetIntegerv(GL_MAJOR_VERSION, &OpenGLVersion[0]);
	glGetIntegerv(GL_MINOR_VERSION, &OpenGLVersion[1]);

	// Now that GL is up and running load the shaders
	GLSprite::LoadShader();

	// Generates a floatly hard-to-read matrix, but a normal, standard 4x4 matrix nonetheless
	this->ProjectionMatrix = glm::perspective(
		45.0f,
		(float)this->windowWidth / (float)this->windowHeight,
		0.1f,
		10000.0f
		);

	this->view->Move(4.0f,50.0f,-10.f);

	// App specific global gl settings
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
	glEnable(GL_MULTISAMPLE_ARB);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);

	return OpenGLVersion;
}

void OpenGLSystem::Move(float x, float y, float z) {
	this->view->Move(x,y,z);
}

void OpenGLSystem::Rotate(float x, float y, float z) {
	this->view->Rotate(x,y,z);
}

void OpenGLSystem::SetViewportSize(const unsigned int width, const unsigned int height) {
	this->windowHeight = height;
	this->windowWidth = width;
	this->ProjectionMatrix = glm::perspective(
		45.0f,
		(float)this->windowWidth / (float)this->windowHeight,
		0.1f,
		10000.0f
		);
}
<commit_msg>Fixed camera placement with new scaling<commit_after>#include "OpenGLSystem.h"
#include "GLSLShader.h"
#include "GLSixDOFView.h"
#include "../components/GLSprite.h"
#include "../components/GLIcoSphere.h"
#include "../components/GLCubeSphere.h"
#include "../components/GLMesh.h"

OpenGLSystem::OpenGLSystem() : windowWidth(800), windowHeight(600), deltaAccumulator(0.0) {
	this->view = new GLSixDOFView();
}

OpenGLSystem::~OpenGLSystem() {
	delete this->view;
}

std::map<std::string, Sigma::IFactory::FactoryFunction>
        OpenGLSystem::getFactoryFunctions()
{
    using namespace std::placeholders;
    std::map<std::string, Sigma::IFactory::FactoryFunction> retval;
	retval["GLSprite"] = std::bind(&OpenGLSystem::createGLSprite,this,_1,_2);
    retval["GLIcoSphere"] = std::bind(&OpenGLSystem::createGLIcoSphere,this,_1,_2);
    retval["GLCubeSphere"] = std::bind(&OpenGLSystem::createGLCubeSphere,this,_1,_2);
    retval["GLMesh"] = std::bind(&OpenGLSystem::createGLMesh,this,_1,_2);

	// Not supported in VS2012
    /*{
        {"GLSprite",std::bind(&OpenGLSystem::createGLSprite,this,_1,_2,_3)},
        {"GLIcoSphere",std::bind(&OpenGLSystem::createGLIcoSphere,this,_1,_2,_3)},
        {"GLCubeSphere",std::bind(&OpenGLSystem::createGLCubeSphere,this,_1,_2,_3)},
        {"GLMesh",std::bind(&OpenGLSystem::createGLMesh,this,_1,_2,_3)}
    };*/
    return retval;
}

void OpenGLSystem::createGLSprite(const unsigned int entityID, std::vector<Property> &properties) {
	GLSprite* spr = new GLSprite(entityID);
	float scale = 1.0f;
	float x = 0.0f;
	float y = 0.0f;
	float z = 0.0f;
	int componentID = 0;
	std::string textureFilename;
	spr->InitializeBuffers();

	for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
		Property*  p = &(*propitr);
		if (p->GetName() == "scale") {
			scale = p->Get<float>();
		} else if (p->GetName() == "x") {
			x = p->Get<float>();
		} else if (p->GetName() == "y") {
			y = p->Get<float>();
		} else if (p->GetName() == "z") {
			z = p->Get<float>();
		} else if (p->GetName() == "id") {
			componentID = p->Get<int>();
		} else if (p->GetName() == "textureFilename"){
			textureFilename = p->Get<std::string>();
		}
	}
	spr->LoadTexture(textureFilename);
	spr->Transform()->Scale(glm::vec3(scale));
	spr->Transform()->Translate(x,y,z);
	this->addComponent(entityID,spr);
}

void OpenGLSystem::createGLIcoSphere(const unsigned int entityID, std::vector<Property> &properties) {
		Sigma::GLIcoSphere* sphere = new Sigma::GLIcoSphere(entityID);
		float scale = 1.0f;
		float x = 0.0f;
		float y = 0.0f;
		float z = 0.0f;
		int componentID = 0;
		std::string shader_name = "shaders/icosphere";

		for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
			Property*  p = &(*propitr);
			if (p->GetName() == "scale") {
				scale = p->Get<float>();
				continue;
			} else if (p->GetName() == "x") {
				x = p->Get<float>();
				continue;
			} else if (p->GetName() == "y") {
				y = p->Get<float>();
				continue;
			} else if (p->GetName() == "z") {
				z = p->Get<float>();
				continue;
			} else if (p->GetName() == "id") {
				componentID = p->Get<int>();
			} else if (p->GetName() == "shader"){
                shader_name = p->Get<std::string>();
			}
		}
		sphere->Transform()->Scale(scale,scale,scale);
		sphere->Transform()->Translate(x,y,z);
		sphere->LoadShader(shader_name);
		sphere->InitializeBuffers();
		sphere->SetCullFace("back");
		this->addComponent(entityID,sphere);
}

void OpenGLSystem::createGLCubeSphere(const unsigned int entityID, std::vector<Property> &properties) {
		Sigma::GLCubeSphere* sphere = new Sigma::GLCubeSphere(entityID);

		std::string texture_name = "";
		std::string shader_name = "shaders/cubesphere";
		std::string cull_face = "back";
		int subdivision_levels = 1;
		float rotation_speed = 0.0f;
		bool fix_to_camera = false;

		float scale = 1.0f;
		float x = 0.0f;
		float y = 0.0f;
		float z = 0.0f;
		int componentID = 0;
		for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
			Property*  p = &(*propitr);
			if (p->GetName() == "scale") {
				scale = p->Get<float>();
				continue;
			} else if (p->GetName() == "x") {
				x = p->Get<float>();
				continue;
			} else if (p->GetName() == "y") {
				y = p->Get<float>();
				continue;
			} else if (p->GetName() == "z") {
				z = p->Get<float>();
				continue;
			} else if (p->GetName() == "subdivision_levels") {
				subdivision_levels = p->Get<int>();
			} else if (p->GetName() == "texture") {
				texture_name = p->Get<std::string>();
			} else if (p->GetName() == "shader") {
				shader_name = p->Get<std::string>();
			} else if (p->GetName() == "id") {
				componentID = p->Get<int>();
			} else if (p->GetName() == "cullface") {
				cull_face = p->Get<std::string>();
			} else if (p->GetName() == "rotation_speed") {
				rotation_speed = p->Get<float>();
			} else if (p->GetName() == "fix_to_camera") {
				fix_to_camera = p->Get<bool>();
			}
		}

		sphere->SetFixToCamera(fix_to_camera);
		sphere->SetRotationSpeed(rotation_speed);
		sphere->SetCullFace(cull_face);
		sphere->SetSubdivisions(subdivision_levels);
		sphere->LoadShader(shader_name);
		sphere->LoadTexture(texture_name);

		sphere->Transform()->Scale(scale,scale,scale);
		sphere->Transform()->Translate(x,y,z);
		sphere->InitializeBuffers();
		this->addComponent(entityID,sphere);
}
void OpenGLSystem::createGLMesh(const unsigned int entityID, std::vector<Property> &properties) {
        Sigma::GLMesh* mesh = new Sigma::GLMesh(entityID);

		float scale = 1.0f;
		float x = 0.0f;
		float y = 0.0f;
		float z = 0.0f;
		float rx = 0.0f;
		float ry = 0.0f;
		float rz = 0.0f;
		int componentID = 0;
		std::string cull_face = "back";
		std::string shaderfile = "";

		for (auto propitr = properties.begin(); propitr != properties.end(); ++propitr) {
			Property*  p = &*propitr;
			if (p->GetName() == "scale") {
				scale = p->Get<float>();
				continue;
			} else if (p->GetName() == "x") {
				x = p->Get<float>();
				continue;
			} else if (p->GetName() == "y") {
				y = p->Get<float>();
				continue;
			} else if (p->GetName() == "z") {
				z = p->Get<float>();
				continue;
			} else if (p->GetName() == "rx") {
				rx = p->Get<float>();
				continue;
			} else if (p->GetName() == "ry") {
				ry = p->Get<float>();
				continue;
			} else if (p->GetName() == "rz") {
				rz = p->Get<float>();
				continue;
			} else if (p->GetName() == "meshFile") {
				mesh->LoadMesh(p->Get<std::string>());
			} else if (p->GetName() == "shader"){
                shaderfile = p->Get<std::string>();
            } else if (p->GetName() == "id") {
				componentID = p->Get<int>();
			} else if (p->GetName() == "cullface") {
				cull_face = p->Get<std::string>();
			}
		}

		mesh->SetCullFace(cull_face);
		mesh->Transform()->Scale(scale,scale,scale);
		mesh->Transform()->Translate(x,y,z);
		mesh->Transform()->Rotate(rx,ry,rz);
		if(shaderfile != "") mesh->LoadShader(shaderfile);
        else mesh->LoadShader(); // load default
		mesh->InitializeBuffers();
		this->addComponent(entityID,mesh);
}

bool OpenGLSystem::Update(const double delta) {
	this->deltaAccumulator += delta;
	this->view->UpdateViewMatrix();

	// Check if the deltaAccumulator is greater than 1/60 of a second.
	if (deltaAccumulator > 16.7) {
		this->view->UpdateViewMatrix();
		// Set up the scene to a "clean" state.
		glClearColor(0.0f,0.0f,0.0f,0.0f);
		glViewport(0, 0, windowWidth, windowHeight); // Set the viewport size to fill the window
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers

		// Set the ViewProjection matrix to be used in the shader.
		// Loop through and draw each component.
		for (auto eitr = this->_Components.begin(); eitr != this->_Components.end(); ++eitr) {
			for (auto citr = eitr->second.begin(); citr != eitr->second.end(); ++citr) {
				citr->second->Render(&this->view->ViewMatrix[0][0], &this->ProjectionMatrix[0][0]);
			}
		}

		this->deltaAccumulator = 0.0;
		return true;
	}
	return false;
}

const int* OpenGLSystem::Start() {
	//Checking GL version
	const GLubyte *GLVersionString = glGetString(GL_VERSION);

	//Or better yet, use the GL3 way to get the version number
	glGetIntegerv(GL_MAJOR_VERSION, &OpenGLVersion[0]);
	glGetIntegerv(GL_MINOR_VERSION, &OpenGLVersion[1]);

	// Now that GL is up and running load the shaders
	GLSprite::LoadShader();

	// Generates a floatly hard-to-read matrix, but a normal, standard 4x4 matrix nonetheless
	this->ProjectionMatrix = glm::perspective(
		45.0f,
		(float)this->windowWidth / (float)this->windowHeight,
		0.1f,
		10000.0f
		);

	this->view->Move(0.0f,1.0f,2.0f);
	this->view->Rotate(0.0f,180.0f,0.0f);

	// App specific global gl settings
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
	glEnable(GL_MULTISAMPLE_ARB);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);

	return OpenGLVersion;
}

void OpenGLSystem::Move(float x, float y, float z) {
	this->view->Move(x,y,z);
}

void OpenGLSystem::Rotate(float x, float y, float z) {
	this->view->Rotate(x,y,z);
}

void OpenGLSystem::SetViewportSize(const unsigned int width, const unsigned int height) {
	this->windowHeight = height;
	this->windowWidth = width;
	this->ProjectionMatrix = glm::perspective(
		45.0f,
		(float)this->windowWidth / (float)this->windowHeight,
		0.1f,
		10000.0f
		);
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "qmakestep.h"

#include "qt4project.h"
#include "qt4projectmanagerconstants.h"
#include "qt4projectmanager.h"
#include "makestep.h"
#include "qtversionmanager.h"

#include <coreplugin/icore.h>
#include <utils/qtcassert.h>

#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QCoreApplication>

using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
using namespace ProjectExplorer;

QMakeStep::QMakeStep(Qt4Project *project)
    : AbstractProcessStep(project), m_pro(project), m_forced(false)
{
}

QMakeStep::~QMakeStep()
{
}

QStringList QMakeStep::arguments(const QString &buildConfiguration)
{
    QStringList additonalArguments = value(buildConfiguration, "qmakeArgs").toStringList();
    QStringList arguments;
    arguments << project()->file()->fileName();
    if (!additonalArguments.contains("-spec")) {
        if (m_pro->value("useVBOX").toBool()) { //NBS TODO don't special case VBOX like this
            arguments << "-spec" << "linux-i686fb-g++";
            arguments << "-unix";
        } else {
            arguments << "-spec" << m_pro->qtVersion(buildConfiguration)->mkspec();
        }
    }

    arguments << "-r";

    if (value(buildConfiguration, "buildConfiguration").isValid()) {
        QStringList configarguments;
        QtVersion::QmakeBuildConfig defaultBuildConfiguration = m_pro->qtVersion(buildConfiguration)->defaultBuildConfig();
        QtVersion::QmakeBuildConfig projectBuildConfiguration = QtVersion::QmakeBuildConfig(value(buildConfiguration, "buildConfiguration").toInt());
        if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(projectBuildConfiguration & QtVersion::BuildAll))
            configarguments << "CONFIG-=debug_and_release";
        if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (projectBuildConfiguration & QtVersion::BuildAll))
            configarguments << "CONFIG+=debug_and_release";
        if ((defaultBuildConfiguration & QtVersion::DebugBuild) && !(projectBuildConfiguration & QtVersion::DebugBuild))
            configarguments << "CONFIG+=release";
        if (!(defaultBuildConfiguration & QtVersion::DebugBuild) && (projectBuildConfiguration & QtVersion::DebugBuild))
            configarguments << "CONFIG+=debug";
        if (!configarguments.isEmpty())
            arguments << "-after" << configarguments;
    } else {
        arguments << "CONFIG+=debug_and_release";
    }

    if (!additonalArguments.isEmpty())
        arguments << additonalArguments;

    return arguments;
}

bool QMakeStep::init(const QString &name)
{
    m_buildConfiguration = name;
    const QtVersion *qtVersion = m_pro->qtVersion(name);

    if (!qtVersion->isValid()) {
#if defined(Q_OS_MAC)
        emit addToOutputWindow(tr("\nNo valid Qt version set. Set one in Preferences \n"));
#else
        emit addToOutputWindow(tr("\nNo valid Qt version set. Set one in Tools/Options \n"));
#endif
        return false;
    }

    QStringList args = arguments(name);
    QString workingDirectory = m_pro->buildDirectory(name);

    Environment environment = m_pro->environment(name);
    if (!environment.value("QMAKESPEC").isEmpty() && environment.value("QMAKESPEC") != qtVersion->mkspec())
        emit addToOutputWindow(tr("QMAKESPEC set to ") + environment.value("QMAKESPEC") +
                               tr(" overrides mkspec of selected qt ")+qtVersion->mkspec());

    QString program = qtVersion->qmakeCommand();

    // Check wheter we need to run qmake
    bool needToRunQMake = true;
    if (QDir(workingDirectory).exists(QLatin1String("Makefile")))
        needToRunQMake = false;

    QStringList newEnv = environment.toStringList();
    newEnv.sort();

    if (m_lastEnv != newEnv) {
        m_lastEnv = newEnv;
        needToRunQMake = true;
    }
    if (m_lastWorkingDirectory != workingDirectory) {
        m_lastWorkingDirectory = workingDirectory;
        needToRunQMake = true;
    }

    if (m_lastArguments != args) {
        m_lastArguments = args;
        needToRunQMake = true;
    }

    if (m_lastProgram != program) {
        m_lastProgram = program;
        needToRunQMake = true;
    }

    if (m_forced) {
        m_forced = false;
        needToRunQMake = true;
    }

    setEnabled(name, needToRunQMake);
    setWorkingDirectory(name, workingDirectory);
    setCommand(name, program);
    setArguments(name, args);
    setEnvironment(name, environment);
    return AbstractProcessStep::init(name);
}

void QMakeStep::run(QFutureInterface<bool> &fi)
{
    if (qobject_cast<Qt4Project *>(project())->rootProjectNode()->projectType() == ScriptTemplate) {
        fi.reportResult(true);
        return;
    }

    if (!enabled(m_buildConfiguration)) {
        emit addToOutputWindow(tr("Configuration unchanged, skipping QMake step."));
        fi.reportResult(true);
        return;
    }
    AbstractProcessStep::run(fi);
}

QString QMakeStep::name()
{
    return Constants::QMAKESTEP;
}

QString QMakeStep::displayName()
{
    return "QMake";
}

void QMakeStep::setForced(bool b)
{
    m_forced = b;
}

bool QMakeStep::forced()
{
    return m_forced;
}

ProjectExplorer::BuildStepConfigWidget *QMakeStep::createConfigWidget()
{
    return new QMakeStepConfigWidget(this);
}

bool QMakeStep::immutable() const
{
    return true;
}

void QMakeStep::processStartupFailed()
{
    m_forced = true;
    AbstractProcessStep::processStartupFailed();
}

bool QMakeStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
    bool result = AbstractProcessStep::processFinished(exitCode, status);
    if (!result)
        m_forced = true;
    return result;
}

QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
    : BuildStepConfigWidget(), m_step(step)
{
    m_ui.setupUi(this);
    connect(m_ui.qmakeAdditonalArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
            this, SLOT(qmakeArgumentsLineEditTextEdited()));
    connect(m_ui.buildConfigurationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(buildConfigurationChanged()));
}

void QMakeStepConfigWidget::qmakeArgumentsLineEditTextEdited()
{
    Q_ASSERT(!m_buildConfiguration.isNull());
    m_step->setValue(m_buildConfiguration, "qmakeArgs", ProjectExplorer::Environment::parseCombinedArgString(m_ui.qmakeAdditonalArgumentsLineEdit->text()));
    m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(m_buildConfiguration)));
    static_cast<Qt4Project *>(m_step->project())->invalidateCachedTargetInformation();
}

void QMakeStepConfigWidget::buildConfigurationChanged()
{
    QtVersion::QmakeBuildConfig buildConfiguration = QtVersion::QmakeBuildConfig(m_step->value(m_buildConfiguration, "buildConfiguration").toInt());
    if (m_ui.buildConfigurationComboBox->currentIndex() == 0) {
        // debug
        buildConfiguration = QtVersion::QmakeBuildConfig(buildConfiguration | QtVersion::DebugBuild);
    } else {
        buildConfiguration = QtVersion::QmakeBuildConfig(buildConfiguration & ~QtVersion::DebugBuild);
    }
    m_step->setValue(m_buildConfiguration, "buildConfiguration", int(buildConfiguration));
    m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(m_buildConfiguration)));
    static_cast<Qt4Project *>(m_step->project())->invalidateCachedTargetInformation();
}

QString QMakeStepConfigWidget::displayName() const
{
    return m_step->displayName();
}

void QMakeStepConfigWidget::init(const QString &buildConfiguration)
{
    m_buildConfiguration = buildConfiguration;
    if (buildConfiguration.isEmpty()){
        m_ui.stackedWidget->setCurrentWidget(m_ui.page_2);
    } else {
        m_ui.stackedWidget->setCurrentWidget(m_ui.page_1);
        QString qmakeArgs = ProjectExplorer::Environment::joinArgumentList(m_step->value(buildConfiguration, "qmakeArgs").toStringList());
        m_ui.qmakeAdditonalArgumentsLineEdit->setText(qmakeArgs);
        m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(buildConfiguration)));
        bool debug = QtVersion::QmakeBuildConfig(m_step->value(buildConfiguration, "buildConfiguration").toInt()) & QtVersion::DebugBuild;
        m_ui.buildConfigurationComboBox->setCurrentIndex(debug? 0 : 1);
    }
}

<commit_msg>Revert recent change to -after CONFIG<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "qmakestep.h"

#include "qt4project.h"
#include "qt4projectmanagerconstants.h"
#include "qt4projectmanager.h"
#include "makestep.h"
#include "qtversionmanager.h"

#include <coreplugin/icore.h>
#include <utils/qtcassert.h>

#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QCoreApplication>

using namespace Qt4ProjectManager;
using namespace Qt4ProjectManager::Internal;
using namespace ProjectExplorer;

QMakeStep::QMakeStep(Qt4Project *project)
    : AbstractProcessStep(project), m_pro(project), m_forced(false)
{
}

QMakeStep::~QMakeStep()
{
}

QStringList QMakeStep::arguments(const QString &buildConfiguration)
{
    QStringList additonalArguments = value(buildConfiguration, "qmakeArgs").toStringList();
    QStringList arguments;
    arguments << project()->file()->fileName();
    if (!additonalArguments.contains("-spec")) {
        if (m_pro->value("useVBOX").toBool()) { //NBS TODO don't special case VBOX like this
            arguments << "-spec" << "linux-i686fb-g++";
            arguments << "-unix";
        } else {
            arguments << "-spec" << m_pro->qtVersion(buildConfiguration)->mkspec();
        }
    }

    arguments << "-r";

    if (value(buildConfiguration, "buildConfiguration").isValid()) {
        QStringList configarguments;
        QtVersion::QmakeBuildConfig defaultBuildConfiguration = m_pro->qtVersion(buildConfiguration)->defaultBuildConfig();
        QtVersion::QmakeBuildConfig projectBuildConfiguration = QtVersion::QmakeBuildConfig(value(buildConfiguration, "buildConfiguration").toInt());
        if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(projectBuildConfiguration & QtVersion::BuildAll))
            configarguments << "CONFIG-=debug_and_release";
        if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (projectBuildConfiguration & QtVersion::BuildAll))
            configarguments << "CONFIG+=debug_and_release";
        if ((defaultBuildConfiguration & QtVersion::DebugBuild) && !(projectBuildConfiguration & QtVersion::DebugBuild))
            configarguments << "CONFIG+=release";
        if (!(defaultBuildConfiguration & QtVersion::DebugBuild) && (projectBuildConfiguration & QtVersion::DebugBuild))
            configarguments << "CONFIG+=debug";
        if (!configarguments.isEmpty())
            arguments << configarguments;
    } else {
        arguments << "CONFIG+=debug_and_release";
    }

    if (!additonalArguments.isEmpty())
        arguments << additonalArguments;

    return arguments;
}

bool QMakeStep::init(const QString &name)
{
    m_buildConfiguration = name;
    const QtVersion *qtVersion = m_pro->qtVersion(name);

    if (!qtVersion->isValid()) {
#if defined(Q_OS_MAC)
        emit addToOutputWindow(tr("\nNo valid Qt version set. Set one in Preferences \n"));
#else
        emit addToOutputWindow(tr("\nNo valid Qt version set. Set one in Tools/Options \n"));
#endif
        return false;
    }

    QStringList args = arguments(name);
    QString workingDirectory = m_pro->buildDirectory(name);

    Environment environment = m_pro->environment(name);
    if (!environment.value("QMAKESPEC").isEmpty() && environment.value("QMAKESPEC") != qtVersion->mkspec())
        emit addToOutputWindow(tr("QMAKESPEC set to ") + environment.value("QMAKESPEC") +
                               tr(" overrides mkspec of selected qt ")+qtVersion->mkspec());

    QString program = qtVersion->qmakeCommand();

    // Check wheter we need to run qmake
    bool needToRunQMake = true;
    if (QDir(workingDirectory).exists(QLatin1String("Makefile")))
        needToRunQMake = false;

    QStringList newEnv = environment.toStringList();
    newEnv.sort();

    if (m_lastEnv != newEnv) {
        m_lastEnv = newEnv;
        needToRunQMake = true;
    }
    if (m_lastWorkingDirectory != workingDirectory) {
        m_lastWorkingDirectory = workingDirectory;
        needToRunQMake = true;
    }

    if (m_lastArguments != args) {
        m_lastArguments = args;
        needToRunQMake = true;
    }

    if (m_lastProgram != program) {
        m_lastProgram = program;
        needToRunQMake = true;
    }

    if (m_forced) {
        m_forced = false;
        needToRunQMake = true;
    }

    setEnabled(name, needToRunQMake);
    setWorkingDirectory(name, workingDirectory);
    setCommand(name, program);
    setArguments(name, args);
    setEnvironment(name, environment);
    return AbstractProcessStep::init(name);
}

void QMakeStep::run(QFutureInterface<bool> &fi)
{
    if (qobject_cast<Qt4Project *>(project())->rootProjectNode()->projectType() == ScriptTemplate) {
        fi.reportResult(true);
        return;
    }

    if (!enabled(m_buildConfiguration)) {
        emit addToOutputWindow(tr("Configuration unchanged, skipping QMake step."));
        fi.reportResult(true);
        return;
    }
    AbstractProcessStep::run(fi);
}

QString QMakeStep::name()
{
    return Constants::QMAKESTEP;
}

QString QMakeStep::displayName()
{
    return "QMake";
}

void QMakeStep::setForced(bool b)
{
    m_forced = b;
}

bool QMakeStep::forced()
{
    return m_forced;
}

ProjectExplorer::BuildStepConfigWidget *QMakeStep::createConfigWidget()
{
    return new QMakeStepConfigWidget(this);
}

bool QMakeStep::immutable() const
{
    return true;
}

void QMakeStep::processStartupFailed()
{
    m_forced = true;
    AbstractProcessStep::processStartupFailed();
}

bool QMakeStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
    bool result = AbstractProcessStep::processFinished(exitCode, status);
    if (!result)
        m_forced = true;
    return result;
}

QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step)
    : BuildStepConfigWidget(), m_step(step)
{
    m_ui.setupUi(this);
    connect(m_ui.qmakeAdditonalArgumentsLineEdit, SIGNAL(textEdited(const QString&)),
            this, SLOT(qmakeArgumentsLineEditTextEdited()));
    connect(m_ui.buildConfigurationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(buildConfigurationChanged()));
}

void QMakeStepConfigWidget::qmakeArgumentsLineEditTextEdited()
{
    Q_ASSERT(!m_buildConfiguration.isNull());
    m_step->setValue(m_buildConfiguration, "qmakeArgs", ProjectExplorer::Environment::parseCombinedArgString(m_ui.qmakeAdditonalArgumentsLineEdit->text()));
    m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(m_buildConfiguration)));
    static_cast<Qt4Project *>(m_step->project())->invalidateCachedTargetInformation();
}

void QMakeStepConfigWidget::buildConfigurationChanged()
{
    QtVersion::QmakeBuildConfig buildConfiguration = QtVersion::QmakeBuildConfig(m_step->value(m_buildConfiguration, "buildConfiguration").toInt());
    if (m_ui.buildConfigurationComboBox->currentIndex() == 0) {
        // debug
        buildConfiguration = QtVersion::QmakeBuildConfig(buildConfiguration | QtVersion::DebugBuild);
    } else {
        buildConfiguration = QtVersion::QmakeBuildConfig(buildConfiguration & ~QtVersion::DebugBuild);
    }
    m_step->setValue(m_buildConfiguration, "buildConfiguration", int(buildConfiguration));
    m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(m_buildConfiguration)));
    static_cast<Qt4Project *>(m_step->project())->invalidateCachedTargetInformation();
}

QString QMakeStepConfigWidget::displayName() const
{
    return m_step->displayName();
}

void QMakeStepConfigWidget::init(const QString &buildConfiguration)
{
    m_buildConfiguration = buildConfiguration;
    if (buildConfiguration.isEmpty()){
        m_ui.stackedWidget->setCurrentWidget(m_ui.page_2);
    } else {
        m_ui.stackedWidget->setCurrentWidget(m_ui.page_1);
        QString qmakeArgs = ProjectExplorer::Environment::joinArgumentList(m_step->value(buildConfiguration, "qmakeArgs").toStringList());
        m_ui.qmakeAdditonalArgumentsLineEdit->setText(qmakeArgs);
        m_ui.qmakeArgumentsEdit->setPlainText(ProjectExplorer::Environment::joinArgumentList(m_step->arguments(buildConfiguration)));
        bool debug = QtVersion::QmakeBuildConfig(m_step->value(buildConfiguration, "buildConfiguration").toInt()) & QtVersion::DebugBuild;
        m_ui.buildConfigurationComboBox->setCurrentIndex(debug? 0 : 1);
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2010 Nickolas Pohilets
//
// This file is a part of the unit test suit for the CppEvents library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <Cpp/Events.hpp>
#include <gtest/gtest.h>

namespace /*anonymous*/ {

class Sender
{
public:
	void fire() { somethingHappened_.fire(); }
	Cpp::EventRef<> somethingHappened() { return somethingHappened_; }
private:
	Cpp::Event<> somethingHappened_;
};

class Reciever
{
public:
	Reciever() : val_() {}

	void increment() { ++val_; }
	void decrement() { --val_; }
	int value() const { return val_; }
	void setValue(int v) { val_ = v; }
private:
	int val_;
};

class SenderEx : public Sender
{
public:
	SenderEx()
	{
		stageNo_ = 0; // 1 2 3 4 ...
		stageStep_ = 1; // 2 4 8 16 ...
	}

	int stageNo() const { return stageNo_; }
	int stageStep() const { return stageStep_; }

	void runStage()
	{
		fire();
		++stageNo_;
		stageStep_ *= 2;
	}
private:
	int stageNo_;
	int stageStep_;
};

template<int ArraySize> class RecieverEx
{
public:
	RecieverEx()
		: sender_()
		, scope_()
		, index_(-1)
		, val_()
	{}

	int index() const { return index_; }
	int value() const { return val_; }

	void connect(int ind, SenderEx * sender, Cpp::ConnectionScope * scope)
	{
		index_ = ind;
		sender_ = sender;
		scope_ = scope;
		scope->connect(sender->somethingHappened(), this, &RecieverEx<ArraySize>::work);
	}

	void work()
	{
		++val_;

		int step = sender_->stageStep();
		int nextIndex = index_ + step;
		if(nextIndex < ArraySize)
		{
			RecieverEx<ArraySize> * next = this + step;
			next->connect(nextIndex, sender_, scope_);
		}
	}
private:
	SenderEx * sender_;
	Cpp::ConnectionScope * scope_;
	int index_;
	int val_;
};

} //namespace /*anonymous*/

////////////////////////////////////////////////////////////////////////////////
// This test checks basic connection management
TEST(Test_ConnectDisconnect, ManualConnectDisconnect)
{
	Sender sender;
	Reciever r1, r2;
	Cpp::ConnectionScope scope;

	ASSERT_EQ(0, r1.value()); ASSERT_EQ(0, r2.value());
	sender.fire();
	ASSERT_EQ(0, r1.value()); ASSERT_EQ(0, r2.value());

	scope.connect(sender.somethingHappened(), &r1, &Reciever::increment);
	sender.fire();	// +1-0 +0-0
	ASSERT_EQ(1, r1.value()); ASSERT_EQ(0, r2.value());
	sender.fire();	// +1-0 +0-0
	ASSERT_EQ(2, r1.value()); ASSERT_EQ(0, r2.value());

	scope.connect(sender.somethingHappened(), &r2, &Reciever::increment);
	sender.fire();	// +1-0 +1-0
	ASSERT_EQ(3, r1.value()); ASSERT_EQ(1, r2.value());

	scope.connect(sender.somethingHappened(), &r1, &Reciever::decrement);
	sender.fire();	// +1-1 +1-0
	ASSERT_EQ(3, r1.value()); ASSERT_EQ(2, r2.value());

	scope.connect(sender.somethingHappened(), &r1, &Reciever::decrement);
	sender.fire();	// +1-2 +1-0
	ASSERT_EQ(2, r1.value()); ASSERT_EQ(3, r2.value());

	scope.connect(sender.somethingHappened(), &r2, &Reciever::decrement);
	sender.fire();	// +1-2 +1-1
	ASSERT_EQ(1, r1.value()); ASSERT_EQ(3, r2.value());

	scope.connect(sender.somethingHappened(), &r2, &Reciever::increment);
	sender.fire();	// +1-2 +2-1
	ASSERT_EQ(0, r1.value()); ASSERT_EQ(4, r2.value());

	sender.somethingHappened().disconnectAll(&r2, &Reciever::decrement);
	sender.fire();	// +1-2 +2-0
	ASSERT_EQ(-1, r1.value()); ASSERT_EQ(6, r2.value());

	sender.somethingHappened().disconnectOne(&r1, &Reciever::decrement);
	sender.fire();	// +1-1 +2-0
	ASSERT_EQ(-1, r1.value()); ASSERT_EQ(8, r2.value());

	sender.somethingHappened().disconnectAll(&r1, &Reciever::increment);
	sender.fire();	// +0-1 +2-0
	ASSERT_EQ(-2, r1.value()); ASSERT_EQ(10, r2.value());

	sender.somethingHappened().disconnectOne(&r2, &Reciever::increment);
	sender.fire();	// +0-1 +1-0
	ASSERT_EQ(-3, r1.value()); ASSERT_EQ(11, r2.value());

	sender.somethingHappened().disconnectAll();
	sender.fire();	// +0-0 +0-0
	ASSERT_EQ(-3, r1.value()); ASSERT_EQ(11, r2.value());
}

////////////////////////////////////////////////////////////////////////////////
// This test checks automatic disconnection
TEST(Test_ConnectDisconnect, AutomaticDisconnect)
{
	Cpp::ConnectionScope scope0;
	Reciever r0;
	{
		Sender sender;

		sender.fire();
		{
			Reciever r1;
			{
				Cpp::ConnectionScope scope1;
				scope1.connect(sender.somethingHappened(), &r1, &Reciever::increment);
				ASSERT_EQ(0, r1.value());
				sender.fire();
				ASSERT_EQ(1, r1.value());
			}
			sender.fire();
			ASSERT_EQ(1, r1.value());
			{
				Cpp::ConnectionScope scope2;
				scope2.connect(sender.somethingHappened(), &r1, &Reciever::decrement);
				ASSERT_EQ(1, r1.value());
				sender.fire();
				ASSERT_EQ(0, r1.value());
			}
			sender.fire();
			ASSERT_EQ(0, r1.value());

			{
				scope0.connect(sender.somethingHappened(), &r0, &Reciever::setValue, 5);
				sender.fire();
				ASSERT_EQ(5, r0.value());
				r0.setValue(-1);
				sender.fire();
				ASSERT_EQ(5, r0.value());
			}
		}
		r0.setValue(-1);
		sender.fire();
		ASSERT_EQ(5, r0.value());
		ASSERT_NE(0, scope0.connectionCount());
	}
	ASSERT_EQ(0, scope0.connectionCount());
}

////////////////////////////////////////////////////////////////////////////////
// This test ensures that adding connections inside delegate works fine.
TEST(Test_ConnectDisconnect, ConnectFromDelegate)
{
	RecieverEx<8> rcv[8];
	Cpp::ConnectionScope scope;
	SenderEx sender;

	rcv[0].connect(0, &sender, &scope);

	ASSERT_EQ(0, rcv[0].value());
	ASSERT_EQ(0, rcv[1].value());
	ASSERT_EQ(0, rcv[2].value());
	ASSERT_EQ(0, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(1, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(1, rcv[0].value());
	ASSERT_EQ(0, rcv[1].value());
	ASSERT_EQ(0, rcv[2].value());
	ASSERT_EQ(0, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(2, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(2, rcv[0].value());
	ASSERT_EQ(1, rcv[1].value());
	ASSERT_EQ(0, rcv[2].value());
	ASSERT_EQ(0, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(4, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(3, rcv[0].value());
	ASSERT_EQ(2, rcv[1].value());
	ASSERT_EQ(1, rcv[2].value());
	ASSERT_EQ(1, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(8, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(4, rcv[0].value());
	ASSERT_EQ(3, rcv[1].value());
	ASSERT_EQ(2, rcv[2].value());
	ASSERT_EQ(2, rcv[3].value());
	ASSERT_EQ(1, rcv[4].value());
	ASSERT_EQ(1, rcv[5].value());
	ASSERT_EQ(1, rcv[6].value());
	ASSERT_EQ(1, rcv[7].value());
	ASSERT_EQ(8, sender.somethingHappened().connectionCount());
}
<commit_msg>*: RecieverEx made non-template class, array size passed as an argument to connect()<commit_after>// Copyright (c) 2010 Nickolas Pohilets
//
// This file is a part of the unit test suit for the CppEvents library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <Cpp/Events.hpp>
#include <gtest/gtest.h>

namespace /*anonymous*/ {

class Sender
{
public:
	void fire() { somethingHappened_.fire(); }
	Cpp::EventRef<> somethingHappened() { return somethingHappened_; }
private:
	Cpp::Event<> somethingHappened_;
};

class Reciever
{
public:
	Reciever() : val_() {}

	void increment() { ++val_; }
	void decrement() { --val_; }
	int value() const { return val_; }
	void setValue(int v) { val_ = v; }
private:
	int val_;
};

class SenderEx : public Sender
{
public:
	SenderEx()
	{
		stageNo_ = 0; // 1 2 3 4 ...
		stageStep_ = 1; // 2 4 8 16 ...
	}

	int stageNo() const { return stageNo_; }
	int stageStep() const { return stageStep_; }

	void runStage()
	{
		fire();
		++stageNo_;
		stageStep_ *= 2;
	}
private:
	int stageNo_;
	int stageStep_;
};

class RecieverEx
{
public:
	RecieverEx()
		: sender_()
		, scope_()
		, index_(-1)
		, val_()
	{}

	int index() const { return index_; }
	int value() const { return val_; }

	void connect(int ind, int arraySize, SenderEx * sender, Cpp::ConnectionScope * scope)
	{
		index_ = ind;
		arraySize_ = arraySize;
		sender_ = sender;
		scope_ = scope;
		scope->connect(sender->somethingHappened(), this, &RecieverEx::work);
	}

	void work()
	{
		++val_;

		int step = sender_->stageStep();
		int nextIndex = index_ + step;
		if(nextIndex < arraySize_)
		{
			RecieverEx * next = this + step;
			next->connect(nextIndex, arraySize_, sender_, scope_);
		}
	}
private:
	SenderEx * sender_;
	Cpp::ConnectionScope * scope_;
	int index_;
	int arraySize_;
	int val_;
};

} //namespace /*anonymous*/

////////////////////////////////////////////////////////////////////////////////
// This test checks basic connection management
TEST(Test_ConnectDisconnect, ManualConnectDisconnect)
{
	Sender sender;
	Reciever r1, r2;
	Cpp::ConnectionScope scope;

	ASSERT_EQ(0, r1.value()); ASSERT_EQ(0, r2.value());
	sender.fire();
	ASSERT_EQ(0, r1.value()); ASSERT_EQ(0, r2.value());

	scope.connect(sender.somethingHappened(), &r1, &Reciever::increment);
	sender.fire();	// +1-0 +0-0
	ASSERT_EQ(1, r1.value()); ASSERT_EQ(0, r2.value());
	sender.fire();	// +1-0 +0-0
	ASSERT_EQ(2, r1.value()); ASSERT_EQ(0, r2.value());

	scope.connect(sender.somethingHappened(), &r2, &Reciever::increment);
	sender.fire();	// +1-0 +1-0
	ASSERT_EQ(3, r1.value()); ASSERT_EQ(1, r2.value());

	scope.connect(sender.somethingHappened(), &r1, &Reciever::decrement);
	sender.fire();	// +1-1 +1-0
	ASSERT_EQ(3, r1.value()); ASSERT_EQ(2, r2.value());

	scope.connect(sender.somethingHappened(), &r1, &Reciever::decrement);
	sender.fire();	// +1-2 +1-0
	ASSERT_EQ(2, r1.value()); ASSERT_EQ(3, r2.value());

	scope.connect(sender.somethingHappened(), &r2, &Reciever::decrement);
	sender.fire();	// +1-2 +1-1
	ASSERT_EQ(1, r1.value()); ASSERT_EQ(3, r2.value());

	scope.connect(sender.somethingHappened(), &r2, &Reciever::increment);
	sender.fire();	// +1-2 +2-1
	ASSERT_EQ(0, r1.value()); ASSERT_EQ(4, r2.value());

	sender.somethingHappened().disconnectAll(&r2, &Reciever::decrement);
	sender.fire();	// +1-2 +2-0
	ASSERT_EQ(-1, r1.value()); ASSERT_EQ(6, r2.value());

	sender.somethingHappened().disconnectOne(&r1, &Reciever::decrement);
	sender.fire();	// +1-1 +2-0
	ASSERT_EQ(-1, r1.value()); ASSERT_EQ(8, r2.value());

	sender.somethingHappened().disconnectAll(&r1, &Reciever::increment);
	sender.fire();	// +0-1 +2-0
	ASSERT_EQ(-2, r1.value()); ASSERT_EQ(10, r2.value());

	sender.somethingHappened().disconnectOne(&r2, &Reciever::increment);
	sender.fire();	// +0-1 +1-0
	ASSERT_EQ(-3, r1.value()); ASSERT_EQ(11, r2.value());

	sender.somethingHappened().disconnectAll();
	sender.fire();	// +0-0 +0-0
	ASSERT_EQ(-3, r1.value()); ASSERT_EQ(11, r2.value());
}

////////////////////////////////////////////////////////////////////////////////
// This test checks automatic disconnection
TEST(Test_ConnectDisconnect, AutomaticDisconnect)
{
	Cpp::ConnectionScope scope0;
	Reciever r0;
	{
		Sender sender;

		sender.fire();
		{
			Reciever r1;
			{
				Cpp::ConnectionScope scope1;
				scope1.connect(sender.somethingHappened(), &r1, &Reciever::increment);
				ASSERT_EQ(0, r1.value());
				sender.fire();
				ASSERT_EQ(1, r1.value());
			}
			sender.fire();
			ASSERT_EQ(1, r1.value());
			{
				Cpp::ConnectionScope scope2;
				scope2.connect(sender.somethingHappened(), &r1, &Reciever::decrement);
				ASSERT_EQ(1, r1.value());
				sender.fire();
				ASSERT_EQ(0, r1.value());
			}
			sender.fire();
			ASSERT_EQ(0, r1.value());

			{
				scope0.connect(sender.somethingHappened(), &r0, &Reciever::setValue, 5);
				sender.fire();
				ASSERT_EQ(5, r0.value());
				r0.setValue(-1);
				sender.fire();
				ASSERT_EQ(5, r0.value());
			}
		}
		r0.setValue(-1);
		sender.fire();
		ASSERT_EQ(5, r0.value());
		ASSERT_NE(0, scope0.connectionCount());
	}
	ASSERT_EQ(0, scope0.connectionCount());
}

////////////////////////////////////////////////////////////////////////////////
// This test ensures that adding connections inside delegate works fine.
TEST(Test_ConnectDisconnect, ConnectFromDelegate)
{
	int const arraySize= 8;
	RecieverEx rcv[arraySize];
	Cpp::ConnectionScope scope;
	SenderEx sender;

	rcv[0].connect(0, arraySize, &sender, &scope);

	ASSERT_EQ(0, rcv[0].value());
	ASSERT_EQ(0, rcv[1].value());
	ASSERT_EQ(0, rcv[2].value());
	ASSERT_EQ(0, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(1, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(1, rcv[0].value());
	ASSERT_EQ(0, rcv[1].value());
	ASSERT_EQ(0, rcv[2].value());
	ASSERT_EQ(0, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(2, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(2, rcv[0].value());
	ASSERT_EQ(1, rcv[1].value());
	ASSERT_EQ(0, rcv[2].value());
	ASSERT_EQ(0, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(4, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(3, rcv[0].value());
	ASSERT_EQ(2, rcv[1].value());
	ASSERT_EQ(1, rcv[2].value());
	ASSERT_EQ(1, rcv[3].value());
	ASSERT_EQ(0, rcv[4].value());
	ASSERT_EQ(0, rcv[5].value());
	ASSERT_EQ(0, rcv[6].value());
	ASSERT_EQ(0, rcv[7].value());
	ASSERT_EQ(8, sender.somethingHappened().connectionCount());

	sender.runStage();
	ASSERT_EQ(4, rcv[0].value());
	ASSERT_EQ(3, rcv[1].value());
	ASSERT_EQ(2, rcv[2].value());
	ASSERT_EQ(2, rcv[3].value());
	ASSERT_EQ(1, rcv[4].value());
	ASSERT_EQ(1, rcv[5].value());
	ASSERT_EQ(1, rcv[6].value());
	ASSERT_EQ(1, rcv[7].value());
	ASSERT_EQ(8, sender.somethingHappened().connectionCount());
}
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

struct SplitnetsWorker
{
	std::map<RTLIL::Wire*, std::vector<RTLIL::SigBit>> splitmap;

	void append_wire(RTLIL::Module *module, RTLIL::Wire *wire, int offset, int width, std::string format)
	{
		RTLIL::Wire *new_wire = new RTLIL::Wire;

		new_wire->port_id = wire->port_id;
		new_wire->port_input = wire->port_input;
		new_wire->port_output = wire->port_output;
		new_wire->name = wire->name;
		new_wire->width = width;

		if (format.size() > 0)
			new_wire->name += format.substr(0, 1);

		if (width > 1) {
			new_wire->name += stringf("%d", offset+width-1);
			if (format.size() > 2)
				new_wire->name += format.substr(2, 1);
			else
				new_wire->name += ":";
		}

		new_wire->name += stringf("%d", offset);

		if (format.size() > 1)
			new_wire->name += format.substr(1, 1);

		while (module->count_id(new_wire->name) > 0)
			new_wire->name = new_wire->name + "_";
		module->add(new_wire);

		std::vector<RTLIL::SigBit> sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector();
		splitmap[wire].insert(splitmap[wire].end(), sigvec.begin(), sigvec.end());
	}

	void operator()(RTLIL::SigSpec &sig)
	{
		sig.expand();
		for (auto &c : sig.chunks)
			if (splitmap.count(c.wire) > 0)
				c = splitmap.at(c.wire).at(c.offset);
		sig.optimize();
	}
};

struct SplitnetsPass : public Pass {
	SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    splitnets [options] [selection]\n");
		log("\n");
		log("This command splits multi-bit nets into single-bit nets.\n");
		log("\n");
		log("    -format char1[char2[char3]]\n");
		log("        the first char is inserted between the net name and the bit index, the\n");
		log("        second char is appended to the netname. e.g. -format () creates net\n");
		log("        names like 'mysignal(42)'. the 3rd character is the range seperation\n");
		log("        character when creating multi-bit wires. the default is '[]:'.\n");
		log("\n");
		log("    -ports\n");
		log("        also split module ports. per default only internal signals are split.\n");
		log("\n");
		log("    -driver\n");
		log("        don't blindly split nets in individual bits. instead look at the driver\n");
		log("        and split nets so that no driver drives only part of a net.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		bool flag_ports = false;
		bool flag_driver = false;
		std::string format = "[]:";

		log_header("Executing SPLITNETS pass (splitting up multi-bit signals).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-format" && argidx+1 < args.size()) {
				format = args[++argidx];
				continue;
			}
			if (args[argidx] == "-ports") {
				flag_ports = true;
				continue;
			}
			if (args[argidx] == "-driver") {
				flag_driver = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod_it : design->modules)
		{
			RTLIL::Module *module = mod_it.second;
			if (!design->selected(module))
				continue;

			SplitnetsWorker worker;

			if (flag_driver)
			{
				CellTypes ct(design);

				std::map<RTLIL::Wire*, std::set<int>> split_wires_at;

				for (auto &c : module->cells)
				for (auto &p : c.second->connections)
				{
					if (!ct.cell_known(c.second->type))
						continue;
					if (!ct.cell_output(c.second->type, p.first))
						continue;

					RTLIL::SigSpec sig = p.second.optimized();
					for (auto &chunk : sig.chunks) {
						if (chunk.wire == NULL)
							continue;
						if (chunk.wire->port_id == 0 || flag_ports) {
							if (chunk.offset != 0)
								split_wires_at[chunk.wire].insert(chunk.offset);
							if (chunk.offset + chunk.width < chunk.wire->width)
								split_wires_at[chunk.wire].insert(chunk.offset + chunk.width);
						}
					}
				}

				for (auto &it : split_wires_at) {
					int cursor = 0;
					for (int next_cursor : it.second) {
						worker.append_wire(module, it.first, cursor, next_cursor - cursor, format);
						cursor = next_cursor;
					}
					worker.append_wire(module, it.first, cursor, it.first->width - cursor, format);
				}
			}
			else
			{
				for (auto &w : module->wires) {
					RTLIL::Wire *wire = w.second;
					if (wire->width > 1 && (wire->port_id == 0 || flag_ports))
						worker.splitmap[wire] = std::vector<RTLIL::SigBit>();
				}

				for (auto &it : worker.splitmap)
					for (int i = 0; i < it.first->width; i++)
						worker.append_wire(module, it.first, i, 1, format);
			}

			module->rewrite_sigspecs(worker);

			for (auto &it : worker.splitmap) {
				module->wires.erase(it.first->name);
				delete it.first;
			}

			module->fixup_ports();
		}
	}
} SplitnetsPass;

<commit_msg>Fixed use of selection in splitnets command<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

struct SplitnetsWorker
{
	std::map<RTLIL::Wire*, std::vector<RTLIL::SigBit>> splitmap;

	void append_wire(RTLIL::Module *module, RTLIL::Wire *wire, int offset, int width, std::string format)
	{
		RTLIL::Wire *new_wire = new RTLIL::Wire;

		new_wire->port_id = wire->port_id;
		new_wire->port_input = wire->port_input;
		new_wire->port_output = wire->port_output;
		new_wire->name = wire->name;
		new_wire->width = width;

		if (format.size() > 0)
			new_wire->name += format.substr(0, 1);

		if (width > 1) {
			new_wire->name += stringf("%d", offset+width-1);
			if (format.size() > 2)
				new_wire->name += format.substr(2, 1);
			else
				new_wire->name += ":";
		}

		new_wire->name += stringf("%d", offset);

		if (format.size() > 1)
			new_wire->name += format.substr(1, 1);

		while (module->count_id(new_wire->name) > 0)
			new_wire->name = new_wire->name + "_";
		module->add(new_wire);

		std::vector<RTLIL::SigBit> sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector();
		splitmap[wire].insert(splitmap[wire].end(), sigvec.begin(), sigvec.end());
	}

	void operator()(RTLIL::SigSpec &sig)
	{
		sig.expand();
		for (auto &c : sig.chunks)
			if (splitmap.count(c.wire) > 0)
				c = splitmap.at(c.wire).at(c.offset);
		sig.optimize();
	}
};

struct SplitnetsPass : public Pass {
	SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    splitnets [options] [selection]\n");
		log("\n");
		log("This command splits multi-bit nets into single-bit nets.\n");
		log("\n");
		log("    -format char1[char2[char3]]\n");
		log("        the first char is inserted between the net name and the bit index, the\n");
		log("        second char is appended to the netname. e.g. -format () creates net\n");
		log("        names like 'mysignal(42)'. the 3rd character is the range seperation\n");
		log("        character when creating multi-bit wires. the default is '[]:'.\n");
		log("\n");
		log("    -ports\n");
		log("        also split module ports. per default only internal signals are split.\n");
		log("\n");
		log("    -driver\n");
		log("        don't blindly split nets in individual bits. instead look at the driver\n");
		log("        and split nets so that no driver drives only part of a net.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		bool flag_ports = false;
		bool flag_driver = false;
		std::string format = "[]:";

		log_header("Executing SPLITNETS pass (splitting up multi-bit signals).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-format" && argidx+1 < args.size()) {
				format = args[++argidx];
				continue;
			}
			if (args[argidx] == "-ports") {
				flag_ports = true;
				continue;
			}
			if (args[argidx] == "-driver") {
				flag_driver = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod_it : design->modules)
		{
			RTLIL::Module *module = mod_it.second;
			if (!design->selected(module))
				continue;

			SplitnetsWorker worker;

			if (flag_driver)
			{
				CellTypes ct(design);

				std::map<RTLIL::Wire*, std::set<int>> split_wires_at;

				for (auto &c : module->cells)
				for (auto &p : c.second->connections)
				{
					if (!ct.cell_known(c.second->type))
						continue;
					if (!ct.cell_output(c.second->type, p.first))
						continue;

					RTLIL::SigSpec sig = p.second.optimized();
					for (auto &chunk : sig.chunks) {
						if (chunk.wire == NULL)
							continue;
						if (chunk.wire->port_id == 0 || flag_ports) {
							if (chunk.offset != 0)
								split_wires_at[chunk.wire].insert(chunk.offset);
							if (chunk.offset + chunk.width < chunk.wire->width)
								split_wires_at[chunk.wire].insert(chunk.offset + chunk.width);
						}
					}
				}

				for (auto &it : split_wires_at) {
					int cursor = 0;
					for (int next_cursor : it.second) {
						worker.append_wire(module, it.first, cursor, next_cursor - cursor, format);
						cursor = next_cursor;
					}
					worker.append_wire(module, it.first, cursor, it.first->width - cursor, format);
				}
			}
			else
			{
				for (auto &w : module->wires) {
					RTLIL::Wire *wire = w.second;
					if (wire->width > 1 && (wire->port_id == 0 || flag_ports) && design->selected(module, w.second))
						worker.splitmap[wire] = std::vector<RTLIL::SigBit>();
				}

				for (auto &it : worker.splitmap)
					for (int i = 0; i < it.first->width; i++)
						worker.append_wire(module, it.first, i, 1, format);
			}

			module->rewrite_sigspecs(worker);

			for (auto &it : worker.splitmap) {
				module->wires.erase(it.first->name);
				delete it.first;
			}

			module->fixup_ports();
		}
	}
} SplitnetsPass;

<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

struct SplitnetsWorker
{
	std::map<RTLIL::Wire*, std::vector<RTLIL::Wire*>> splitmap;

	void operator()(RTLIL::SigSpec &sig)
	{
		sig.expand();
		for (auto &c : sig.chunks)
			if (splitmap.count(c.wire) > 0) {
				c.wire = splitmap.at(c.wire).at(c.offset);
				c.offset = 0;
			}
		sig.optimize();
	}
};

struct SplitnetsPass : public Pass {
	SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    splitnets [options] [selection]\n");
		log("\n");
		log("This command splits multi-bit nets into single-bit nets.\n");
		log("\n");
		log("    -format char1[char2]\n");
		log("        the first char is inserted between the net name and the bit index, the\n");
		log("        second char is appended to the netname. e.g. -format () creates net\n");
		log("        names like 'mysignal(42)'. the default is '[]'.\n");
		log("\n");
		log("    -ports\n");
		log("        also split module ports. per default only internal signals are split.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		bool flag_ports = false;
		std::string format = "[]";

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-format" && argidx+1 < args.size()) {
				format = args[++argidx];
				continue;
			}
			if (args[argidx] == "-ports") {
				flag_ports = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod_it : design->modules)
		{
			RTLIL::Module *module = mod_it.second;
			if (!design->selected(module))
				continue;

			SplitnetsWorker worker;

			for (auto &w : module->wires) {
				RTLIL::Wire *wire = w.second;
				if (wire->width > 1 && (wire->port_id == 0 || flag_ports))
					worker.splitmap[wire] = std::vector<RTLIL::Wire*>();
			}

			for (auto &it : worker.splitmap)
				for (int i = 0; i < it.first->width; i++) {
					RTLIL::Wire *wire = new RTLIL::Wire;
					wire->port_id = it.first->port_id;
					wire->port_input = it.first->port_input;
					wire->port_output = it.first->port_output;
					wire->name = it.first->name;
					if (format.size() > 0)
						wire->name += format.substr(0, 1);
					wire->name += stringf("%d", i);
					if (format.size() > 0)
						wire->name += format.substr(1);
					while (module->count_id(wire->name) > 0)
						wire->name = wire->name + "_";
					module->add(wire);
					it.second.push_back(wire);
				}

			module->rewrite_sigspecs(worker);

			for (auto &it : worker.splitmap) {
				module->wires.erase(it.first->name);
				delete it.first;
			}

			module->fixup_ports();
		}
	}
} SplitnetsPass;

<commit_msg>Added "splitnets -driver"<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

struct SplitnetsWorker
{
	std::map<RTLIL::Wire*, std::vector<RTLIL::SigBit>> splitmap;

	void append_wire(RTLIL::Module *module, RTLIL::Wire *wire, int offset, int width, std::string format)
	{
		RTLIL::Wire *new_wire = new RTLIL::Wire;

		new_wire->port_id = wire->port_id;
		new_wire->port_input = wire->port_input;
		new_wire->port_output = wire->port_output;
		new_wire->name = wire->name;
		new_wire->width = width;

		if (format.size() > 0)
			new_wire->name += format.substr(0, 1);

		if (width > 1) {
			new_wire->name += stringf("%d", offset+width-1);
			if (format.size() > 2)
				new_wire->name += format.substr(2, 1);
			else
				new_wire->name += ":";
		}

		new_wire->name += stringf("%d", offset);

		if (format.size() > 1)
			new_wire->name += format.substr(1, 1);

		while (module->count_id(new_wire->name) > 0)
			new_wire->name = new_wire->name + "_";
		module->add(new_wire);

		std::vector<RTLIL::SigBit> sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector();
		splitmap[wire].insert(splitmap[wire].end(), sigvec.begin(), sigvec.end());
	}

	void operator()(RTLIL::SigSpec &sig)
	{
		sig.expand();
		for (auto &c : sig.chunks)
			if (splitmap.count(c.wire) > 0)
				c = splitmap.at(c.wire).at(c.offset);
		sig.optimize();
	}
};

struct SplitnetsPass : public Pass {
	SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    splitnets [options] [selection]\n");
		log("\n");
		log("This command splits multi-bit nets into single-bit nets.\n");
		log("\n");
		log("    -format char1[char2[char3]]\n");
		log("        the first char is inserted between the net name and the bit index, the\n");
		log("        second char is appended to the netname. e.g. -format () creates net\n");
		log("        names like 'mysignal(42)'. the 3rd character is the range seperation\n");
		log("        character when creating multi-bit wires. the default is '[]:'.\n");
		log("\n");
		log("    -ports\n");
		log("        also split module ports. per default only internal signals are split.\n");
		log("\n");
		log("    -driver\n");
		log("        don't blindly split nets in individual bits. instead look at the driver\n");
		log("        and split nets so that no driver drives only part of a net.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		bool flag_ports = false;
		bool flag_driver = false;
		std::string format = "[]:";

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-format" && argidx+1 < args.size()) {
				format = args[++argidx];
				continue;
			}
			if (args[argidx] == "-ports") {
				flag_ports = true;
				continue;
			}
			if (args[argidx] == "-driver") {
				flag_driver = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod_it : design->modules)
		{
			RTLIL::Module *module = mod_it.second;
			if (!design->selected(module))
				continue;

			SplitnetsWorker worker;

			if (flag_driver)
			{
				CellTypes ct(design);

				std::map<RTLIL::Wire*, std::set<int>> split_wires_at;

				for (auto &c : module->cells)
				for (auto &p : c.second->connections)
				{
					if (!ct.cell_known(c.second->type))
						continue;
					if (!ct.cell_output(c.second->type, p.first))
						continue;

					RTLIL::SigSpec sig = p.second.optimized();
					for (auto &chunk : sig.chunks) {
						if (chunk.wire == NULL)
							continue;
						if (chunk.wire->port_id == 0 || flag_ports) {
							if (chunk.offset != 0)
								split_wires_at[chunk.wire].insert(chunk.offset);
							if (chunk.offset + chunk.width < chunk.wire->width)
								split_wires_at[chunk.wire].insert(chunk.offset + chunk.width);
						}
					}
				}

				for (auto &it : split_wires_at) {
					int cursor = 0;
					for (int next_cursor : it.second) {
						worker.append_wire(module, it.first, cursor, next_cursor - cursor, format);
						cursor = next_cursor;
					}
					worker.append_wire(module, it.first, cursor, it.first->width - cursor, format);
				}
			}
			else
			{
				for (auto &w : module->wires) {
					RTLIL::Wire *wire = w.second;
					if (wire->width > 1 && (wire->port_id == 0 || flag_ports))
						worker.splitmap[wire] = std::vector<RTLIL::SigBit>();
				}

				for (auto &it : worker.splitmap)
					for (int i = 0; i < it.first->width; i++)
						worker.append_wire(module, it.first, i, 1, format);
			}

			module->rewrite_sigspecs(worker);

			for (auto &it : worker.splitmap) {
				module->wires.erase(it.first->name);
				delete it.first;
			}

			module->fixup_ports();
		}
	}
} SplitnetsPass;

<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"
#include "kernel/ff.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct Async2syncPass : public Pass {
	Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
	void help() override
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    async2sync [options] [selection]\n");
		log("\n");
		log("This command replaces async FF inputs with sync circuits emulating the same\n");
		log("behavior for when the async signals are actually synchronized to the clock.\n");
		log("\n");
		log("This pass assumes negative hold time for the async FF inputs. For example when\n");
		log("a reset deasserts with the clock edge, then the FF output will still drive the\n");
		log("reset value in the next cycle regardless of the data-in value at the time of\n");
		log("the clock edge.\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
	{
		// bool flag_noinit = false;

		log_header(design, "Executing ASYNC2SYNC pass.\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			// if (args[argidx] == "-noinit") {
			// 	flag_noinit = true;
			// 	continue;
			// }
			break;
		}
		extra_args(args, argidx, design);

		for (auto module : design->selected_modules())
		{
			SigMap sigmap(module);
			FfInitVals initvals(&sigmap, module);

			for (auto cell : vector<Cell*>(module->selected_cells()))
			{
				if (!RTLIL::builtin_ff_cell_types().count(cell->type))
					continue;

				FfData ff(&initvals, cell);

				// Skip for $_FF_ and $ff cells.
				if (ff.has_gclk)
					continue;

				if (ff.has_clk)
				{
					if (ff.has_sr) {
						ff.unmap_ce_srst();

						log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
								log_id(module), log_id(cell), log_id(cell->type),
								log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_d), log_signal(ff.sig_q));

						initvals.remove_init(ff.sig_q);

						Wire *new_d = module->addWire(NEW_ID, ff.width);
						Wire *new_q = module->addWire(NEW_ID, ff.width);

						SigSpec sig_set = ff.sig_set;
						SigSpec sig_clr = ff.sig_clr;

						if (!ff.pol_set) {
							if (!ff.is_fine)
								sig_set = module->Not(NEW_ID, sig_set);
							else
								sig_set = module->NotGate(NEW_ID, sig_set);
						}

						if (ff.pol_clr) {
							if (!ff.is_fine)
								sig_clr = module->Not(NEW_ID, sig_clr);
							else
								sig_clr = module->NotGate(NEW_ID, sig_clr);
						}

						if (!ff.is_fine) {
							SigSpec tmp = module->Or(NEW_ID, ff.sig_d, sig_set);
							module->addAnd(NEW_ID, tmp, sig_clr, new_d);

							tmp = module->Or(NEW_ID, new_q, sig_set);
							module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
						} else {
							SigSpec tmp = module->OrGate(NEW_ID, ff.sig_d, sig_set);
							module->addAndGate(NEW_ID, tmp, sig_clr, new_d);

							tmp = module->OrGate(NEW_ID, new_q, sig_set);
							module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
						}

						ff.sig_d = new_d;
						ff.sig_q = new_q;
						ff.has_sr = false;
					} else if (ff.has_aload) {
						ff.unmap_ce_srst();

						log("Replacing %s.%s (%s): ALOAD=%s, AD=%s, D=%s, Q=%s\n",
								log_id(module), log_id(cell), log_id(cell->type),
								log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_d), log_signal(ff.sig_q));

						initvals.remove_init(ff.sig_q);

						Wire *new_d = module->addWire(NEW_ID, ff.width);
						Wire *new_q = module->addWire(NEW_ID, ff.width);

						if (ff.pol_aload) {
							if (!ff.is_fine) {
								module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
								module->addMux(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
							} else {
								module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
								module->addMuxGate(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
							}
						} else {
							if (!ff.is_fine) {
								module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
								module->addMux(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
							} else {
								module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
								module->addMuxGate(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
							}
						}

						ff.sig_d = new_d;
						ff.sig_q = new_q;
						ff.has_aload = false;
					} else if (ff.has_arst) {
						ff.unmap_srst();

						log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
								log_id(module), log_id(cell), log_id(cell->type),
								log_signal(ff.sig_arst), log_signal(ff.sig_d), log_signal(ff.sig_q));

						initvals.remove_init(ff.sig_q);

						Wire *new_q = module->addWire(NEW_ID, ff.width);

						if (ff.pol_arst) {
							if (!ff.is_fine)
								module->addMux(NEW_ID, new_q, ff.val_arst, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, new_q, ff.val_arst[0], ff.sig_arst, ff.sig_q);
						} else {
							if (!ff.is_fine)
								module->addMux(NEW_ID, ff.val_arst, new_q, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, ff.val_arst[0], new_q, ff.sig_arst, ff.sig_q);
						}

						ff.sig_q = new_q;
						ff.has_arst = false;
						ff.has_srst = true;
						ff.ce_over_srst = false;
						ff.val_srst = ff.val_arst;
						ff.sig_srst = ff.sig_arst;
						ff.pol_srst = ff.pol_arst;
					} else {
						continue;
					}
				}
				else
				{
					// Latch.
					log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
							log_id(module), log_id(cell), log_id(cell->type),
							log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));

					initvals.remove_init(ff.sig_q);

					Wire *new_q = module->addWire(NEW_ID, ff.width);
					Wire *new_d;

					if (ff.has_aload) {
						new_d = module->addWire(NEW_ID, ff.width);
						if (ff.pol_aload) {
							if (!ff.is_fine)
								module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
							else
								module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
						} else {
							if (!ff.is_fine)
								module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
							else
								module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
						}
					} else {
						new_d = new_q;
					}

					if (ff.has_sr) {
						SigSpec sig_set = ff.sig_set;
						SigSpec sig_clr = ff.sig_clr;

						if (!ff.pol_set) {
							if (!ff.is_fine)
								sig_set = module->Not(NEW_ID, sig_set);
							else
								sig_set = module->NotGate(NEW_ID, sig_set);
						}

						if (ff.pol_clr) {
							if (!ff.is_fine)
								sig_clr = module->Not(NEW_ID, sig_clr);
							else
								sig_clr = module->NotGate(NEW_ID, sig_clr);
						}

						if (!ff.is_fine) {
							SigSpec tmp = module->Or(NEW_ID, new_d, sig_set);
							module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
						} else {
							SigSpec tmp = module->OrGate(NEW_ID, new_d, sig_set);
							module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
						}
					} else if (ff.has_arst) {
						if (ff.pol_arst) {
							if (!ff.is_fine)
								module->addMux(NEW_ID, new_d, ff.val_arst, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, new_d, ff.val_arst[0], ff.sig_arst, ff.sig_q);
						} else {
							if (!ff.is_fine)
								module->addMux(NEW_ID, ff.val_arst, new_d, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, ff.val_arst[0], new_d, ff.sig_arst, ff.sig_q);
						}
					} else {
						module->connect(ff.sig_q, new_d);
					}

					ff.sig_d = new_d;
					ff.sig_q = new_q;
					ff.has_aload = false;
					ff.has_arst = false;
					ff.has_sr = false;
					ff.has_gclk = true;
				}
				ff.emit();
			}
		}
	}
} Async2syncPass;

PRIVATE_NAMESPACE_END
<commit_msg>async2sync: turn FFs with const clks into gclk FFs with feedback<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"
#include "kernel/ff.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct Async2syncPass : public Pass {
	Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
	void help() override
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    async2sync [options] [selection]\n");
		log("\n");
		log("This command replaces async FF inputs with sync circuits emulating the same\n");
		log("behavior for when the async signals are actually synchronized to the clock.\n");
		log("\n");
		log("This pass assumes negative hold time for the async FF inputs. For example when\n");
		log("a reset deasserts with the clock edge, then the FF output will still drive the\n");
		log("reset value in the next cycle regardless of the data-in value at the time of\n");
		log("the clock edge.\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
	{
		// bool flag_noinit = false;

		log_header(design, "Executing ASYNC2SYNC pass.\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			// if (args[argidx] == "-noinit") {
			// 	flag_noinit = true;
			// 	continue;
			// }
			break;
		}
		extra_args(args, argidx, design);

		for (auto module : design->selected_modules())
		{
			SigMap sigmap(module);
			FfInitVals initvals(&sigmap, module);

			for (auto cell : vector<Cell*>(module->selected_cells()))
			{
				if (!RTLIL::builtin_ff_cell_types().count(cell->type))
					continue;

				FfData ff(&initvals, cell);

				// Skip for $_FF_ and $ff cells.
				if (ff.has_gclk)
					continue;

				if (ff.has_clk && ff.sig_clk.is_fully_const())
					ff.has_ce = ff.has_clk = ff.has_srst = false;

				if (ff.has_clk)
				{
					if (ff.has_sr) {
						ff.unmap_ce_srst();

						log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n",
								log_id(module), log_id(cell), log_id(cell->type),
								log_signal(ff.sig_set), log_signal(ff.sig_clr), log_signal(ff.sig_d), log_signal(ff.sig_q));

						initvals.remove_init(ff.sig_q);

						Wire *new_d = module->addWire(NEW_ID, ff.width);
						Wire *new_q = module->addWire(NEW_ID, ff.width);

						SigSpec sig_set = ff.sig_set;
						SigSpec sig_clr = ff.sig_clr;

						if (!ff.pol_set) {
							if (!ff.is_fine)
								sig_set = module->Not(NEW_ID, sig_set);
							else
								sig_set = module->NotGate(NEW_ID, sig_set);
						}

						if (ff.pol_clr) {
							if (!ff.is_fine)
								sig_clr = module->Not(NEW_ID, sig_clr);
							else
								sig_clr = module->NotGate(NEW_ID, sig_clr);
						}

						if (!ff.is_fine) {
							SigSpec tmp = module->Or(NEW_ID, ff.sig_d, sig_set);
							module->addAnd(NEW_ID, tmp, sig_clr, new_d);

							tmp = module->Or(NEW_ID, new_q, sig_set);
							module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
						} else {
							SigSpec tmp = module->OrGate(NEW_ID, ff.sig_d, sig_set);
							module->addAndGate(NEW_ID, tmp, sig_clr, new_d);

							tmp = module->OrGate(NEW_ID, new_q, sig_set);
							module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
						}

						ff.sig_d = new_d;
						ff.sig_q = new_q;
						ff.has_sr = false;
					} else if (ff.has_aload) {
						ff.unmap_ce_srst();

						log("Replacing %s.%s (%s): ALOAD=%s, AD=%s, D=%s, Q=%s\n",
								log_id(module), log_id(cell), log_id(cell->type),
								log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_d), log_signal(ff.sig_q));

						initvals.remove_init(ff.sig_q);

						Wire *new_d = module->addWire(NEW_ID, ff.width);
						Wire *new_q = module->addWire(NEW_ID, ff.width);

						if (ff.pol_aload) {
							if (!ff.is_fine) {
								module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
								module->addMux(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
							} else {
								module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, ff.sig_q);
								module->addMuxGate(NEW_ID, ff.sig_d, ff.sig_ad, ff.sig_aload, new_d);
							}
						} else {
							if (!ff.is_fine) {
								module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
								module->addMux(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
							} else {
								module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, ff.sig_q);
								module->addMuxGate(NEW_ID, ff.sig_ad, ff.sig_d, ff.sig_aload, new_d);
							}
						}

						ff.sig_d = new_d;
						ff.sig_q = new_q;
						ff.has_aload = false;
					} else if (ff.has_arst) {
						ff.unmap_srst();

						log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
								log_id(module), log_id(cell), log_id(cell->type),
								log_signal(ff.sig_arst), log_signal(ff.sig_d), log_signal(ff.sig_q));

						initvals.remove_init(ff.sig_q);

						Wire *new_q = module->addWire(NEW_ID, ff.width);

						if (ff.pol_arst) {
							if (!ff.is_fine)
								module->addMux(NEW_ID, new_q, ff.val_arst, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, new_q, ff.val_arst[0], ff.sig_arst, ff.sig_q);
						} else {
							if (!ff.is_fine)
								module->addMux(NEW_ID, ff.val_arst, new_q, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, ff.val_arst[0], new_q, ff.sig_arst, ff.sig_q);
						}

						ff.sig_q = new_q;
						ff.has_arst = false;
						ff.has_srst = true;
						ff.ce_over_srst = false;
						ff.val_srst = ff.val_arst;
						ff.sig_srst = ff.sig_arst;
						ff.pol_srst = ff.pol_arst;
					} else {
						continue;
					}
				}
				else
				{
					// Latch.
					log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
							log_id(module), log_id(cell), log_id(cell->type),
							log_signal(ff.sig_aload), log_signal(ff.sig_ad), log_signal(ff.sig_q));

					initvals.remove_init(ff.sig_q);

					Wire *new_q = module->addWire(NEW_ID, ff.width);
					Wire *new_d;

					if (ff.has_aload) {
						new_d = module->addWire(NEW_ID, ff.width);
						if (ff.pol_aload) {
							if (!ff.is_fine)
								module->addMux(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
							else
								module->addMuxGate(NEW_ID, new_q, ff.sig_ad, ff.sig_aload, new_d);
						} else {
							if (!ff.is_fine)
								module->addMux(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
							else
								module->addMuxGate(NEW_ID, ff.sig_ad, new_q, ff.sig_aload, new_d);
						}
					} else {
						new_d = new_q;
					}

					if (ff.has_sr) {
						SigSpec sig_set = ff.sig_set;
						SigSpec sig_clr = ff.sig_clr;

						if (!ff.pol_set) {
							if (!ff.is_fine)
								sig_set = module->Not(NEW_ID, sig_set);
							else
								sig_set = module->NotGate(NEW_ID, sig_set);
						}

						if (ff.pol_clr) {
							if (!ff.is_fine)
								sig_clr = module->Not(NEW_ID, sig_clr);
							else
								sig_clr = module->NotGate(NEW_ID, sig_clr);
						}

						if (!ff.is_fine) {
							SigSpec tmp = module->Or(NEW_ID, new_d, sig_set);
							module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
						} else {
							SigSpec tmp = module->OrGate(NEW_ID, new_d, sig_set);
							module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
						}
					} else if (ff.has_arst) {
						if (ff.pol_arst) {
							if (!ff.is_fine)
								module->addMux(NEW_ID, new_d, ff.val_arst, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, new_d, ff.val_arst[0], ff.sig_arst, ff.sig_q);
						} else {
							if (!ff.is_fine)
								module->addMux(NEW_ID, ff.val_arst, new_d, ff.sig_arst, ff.sig_q);
							else
								module->addMuxGate(NEW_ID, ff.val_arst[0], new_d, ff.sig_arst, ff.sig_q);
						}
					} else {
						module->connect(ff.sig_q, new_d);
					}

					ff.sig_d = new_d;
					ff.sig_q = new_q;
					ff.has_aload = false;
					ff.has_arst = false;
					ff.has_sr = false;
					ff.has_gclk = true;
				}
				ff.emit();
			}
		}
	}
} Async2syncPass;

PRIVATE_NAMESPACE_END
<|endoftext|>