<commit_before>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CounterImp.h"

namespace org
{
namespace w3c
{
namespace dom
{
namespace bootstrap
{

namespace {

struct AdditiveGlyph
{
    int weight;
    char16_t* glyph;
};

// 1 4999
AdditiveGlyph upperRoman[] =
{
    1000, u"M",
    900, u"CM",
    500, u"D",
    400, u"CD",
    100, u"C",
    90, u"XC",
    50, u"L",
    40, u"XL",
    10, u"X",
    9, u"IX",
    5, u"V",
    4, u"IV",
    1, u"I",
    0, 0
};

// 1 4999
AdditiveGlyph lowerRoman[] =
{
    1000, u"m",
    900, u"cm",
    500, u"d",
    400, u"cd",
    100, u"c",
    90, u"xc",
    50, u"l",
    40, u"xl",
    10, u"x",
    9, u"ix",
    5, u"v",
    4, u"iv",
    1, u"i",
    0, 0
};

std::u16string convertToRoman(int n, AdditiveGlyph* glyphList)
{
    if (n < 0 || 5000 <= n)
        return toString(n);
    std::u16string value;
    for (AdditiveGlyph* i = glyphList; i->glyph; ++i) {
        int t = n / i->weight;
        while (0 < t--)
            value += i->glyph;
    }
    return value;
}

std::u16string emit(int i, unsigned type)
{
    std::u16string value;
    switch (type) {
    case CSSListStyleTypeValueImp::Decimal:
        value = toString(i);
        break;
    case CSSListStyleTypeValueImp::DecimalLeadingZero:
        value = toString(i % 100);
        if (value.length() == 1)
            value = u"0" + value;
        break;
    case CSSListStyleTypeValueImp::LowerAlpha:
    case CSSListStyleTypeValueImp::LowerLatin:
        value = std::u16string(1, u'a' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::UpperAlpha:
    case CSSListStyleTypeValueImp::UpperLatin:
        value = std::u16string(1, u'A' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::LowerGreek:
        // This style is only defined because CSS2.1 has it.
        // It doesn't appear to actually be used in Greek texts.
        value = std::u16string(1, u"αβγδεζηθικλμνξοπρστυφχψω"[static_cast<unsigned>(i - 1) % 24]);
        break;
    case CSSListStyleTypeValueImp::LowerRoman:
        value = convertToRoman(i, lowerRoman);
        break;
    case CSSListStyleTypeValueImp::UpperRoman:
        value = convertToRoman(i, upperRoman);
        break;
    case CSSListStyleTypeValueImp::Armenian:
    case CSSListStyleTypeValueImp::Georgian:
    default:
        value = toString(i);
        break;
    }
    return value;
}

}

void CounterImp::reset(int number)
{
    counters.push_back(number);
}

void CounterImp::increment(int number)
{
    if (counters.empty())
        counters.push_back(0);
    counters.back() += number;
}

bool CounterImp::restore()
{
    counters.pop_back();
    return counters.empty();
}

std::u16string CounterImp::eval(const std::u16string& separator, unsigned type)
{
    this->separator = separator;
    this->listStyle.setValue(type);
    if (counters.empty())
        return u"";
    std::u16string value;
    if (separator.empty())
        value = emit(counters.back(), type);
    else {
        for (auto i = counters.begin(); i != counters.end(); ++i) {
            if (i != counters.begin())
                value += separator;
            value += emit(*i, type);
        }
    }
    return value;
}

std::u16string CounterImp::getIdentifier()
{
    return identifier;
}

std::u16string CounterImp::getListStyle()
{
    return listStyle.getCssText();
}

std::u16string CounterImp::getSeparator()
{
    return separator;
}

}
}
}
}
<commit_msg>(convertToRoman) : Fix a bug.<commit_after>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "CounterImp.h"

namespace org
{
namespace w3c
{
namespace dom
{
namespace bootstrap
{

namespace {

struct AdditiveGlyph
{
    int weight;
    char16_t* glyph;
};

// 1 4999
AdditiveGlyph upperRoman[] =
{
    1000, u"M",
    900, u"CM",
    500, u"D",
    400, u"CD",
    100, u"C",
    90, u"XC",
    50, u"L",
    40, u"XL",
    10, u"X",
    9, u"IX",
    5, u"V",
    4, u"IV",
    1, u"I",
    0, 0
};

// 1 4999
AdditiveGlyph lowerRoman[] =
{
    1000, u"m",
    900, u"cm",
    500, u"d",
    400, u"cd",
    100, u"c",
    90, u"xc",
    50, u"l",
    40, u"xl",
    10, u"x",
    9, u"ix",
    5, u"v",
    4, u"iv",
    1, u"i",
    0, 0
};

std::u16string convertToRoman(int n, AdditiveGlyph* glyphList)
{
    if (n < 0 || 5000 <= n)
        return toString(n);
    std::u16string value;
    for (AdditiveGlyph* i = glyphList; i->glyph; ++i) {
        int t = n / i->weight;
        if (0 < t) {
            n -= t * i->weight;
            while (0 < t--)
                value += i->glyph;
        }
    }
    return value;
}

std::u16string emit(int i, unsigned type)
{
    std::u16string value;
    switch (type) {
    case CSSListStyleTypeValueImp::Decimal:
        value = toString(i);
        break;
    case CSSListStyleTypeValueImp::DecimalLeadingZero:
        value = toString(i % 100);
        if (value.length() == 1)
            value = u"0" + value;
        break;
    case CSSListStyleTypeValueImp::LowerAlpha:
    case CSSListStyleTypeValueImp::LowerLatin:
        value = std::u16string(1, u'a' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::UpperAlpha:
    case CSSListStyleTypeValueImp::UpperLatin:
        value = std::u16string(1, u'A' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::LowerGreek:
        // This style is only defined because CSS2.1 has it.
        // It doesn't appear to actually be used in Greek texts.
        value = std::u16string(1, u"αβγδεζηθικλμνξοπρστυφχψω"[static_cast<unsigned>(i - 1) % 24]);
        break;
    case CSSListStyleTypeValueImp::LowerRoman:
        value = convertToRoman(i, lowerRoman);
        break;
    case CSSListStyleTypeValueImp::UpperRoman:
        value = convertToRoman(i, upperRoman);
        break;
    case CSSListStyleTypeValueImp::Armenian:
    case CSSListStyleTypeValueImp::Georgian:
    default:
        value = toString(i);
        break;
    }
    return value;
}

}

void CounterImp::reset(int number)
{
    counters.push_back(number);
}

void CounterImp::increment(int number)
{
    if (counters.empty())
        counters.push_back(0);
    counters.back() += number;
}

bool CounterImp::restore()
{
    counters.pop_back();
    return counters.empty();
}

std::u16string CounterImp::eval(const std::u16string& separator, unsigned type)
{
    this->separator = separator;
    this->listStyle.setValue(type);
    if (counters.empty())
        return u"";
    std::u16string value;
    if (separator.empty())
        value = emit(counters.back(), type);
    else {
        for (auto i = counters.begin(); i != counters.end(); ++i) {
            if (i != counters.begin())
                value += separator;
            value += emit(*i, type);
        }
    }
    return value;
}

std::u16string CounterImp::getIdentifier()
{
    return identifier;
}

std::u16string CounterImp::getListStyle()
{
    return listStyle.getCssText();
}

std::u16string CounterImp::getSeparator()
{
    return separator;
}

}
}
}
}
<|endoftext|>


<commit_before>#include "FAST/Data/Image.hpp"
#include "FAST/Data/Segmentation.hpp"
#include "FAST/Data/PointSet.hpp"
#include "FAST/DeviceManager.hpp"
#include "FAST/Algorithms/GaussianSmoothingFilter/GaussianSmoothingFilter.hpp"
#include "FAST/Algorithms/ImageGradient/ImageGradient.hpp"
#include "FAST/Utility.hpp"
#include "FAST/SceneGraph.hpp"
#include <boost/shared_array.hpp>
#include <queue>
#include "FAST/Algorithms/UltrasoundVesselDetection/UltrasoundVesselDetection.hpp"
#include "FAST/Algorithms/ImageCropper/ImageCropper.hpp"
#include "FAST/Algorithms/ImageClassifier/ImageClassifier.hpp"

namespace fast {

ProcessObjectPort UltrasoundVesselDetection::getOutputSegmentationPort() {
    mCreateSegmentation = true;
    return getOutputPort(0);
}

UltrasoundVesselDetection::UltrasoundVesselDetection() {
    createInputPort<Image>(0);
    createOutputPort<Segmentation>(0, OUTPUT_DEPENDS_ON_INPUT, 0);
    createOpenCLProgram(std::string(FAST_SOURCE_DIR) + "Algorithms/UltrasoundVesselDetection/UltrasoundVesselDetection.cl");
    mCreateSegmentation = false;

	mClassifier = ImageClassifier::New();
	std::string modelFile = "/home/smistad/vessel_detection_model/deploy.prototxt";
	std::string trainingFile = "/home/smistad/vessel_detection_model/snapshot_iter_540.caffemodel";
	std::string meanFile = "/home/smistad/vessel_detection_model/mean.binaryproto";
	//std::string modelFile = "/home/smistad/vessel_detection_model2/deploy.prototxt";
	//std::string trainingFile = "/home/smistad/vessel_detection_model2/snapshot_iter_960.caffemodel";
	//std::string meanFile = "/home/smistad/vessel_detection_model2/mean.binaryproto";
	mClassifier->loadModel(modelFile, trainingFile, meanFile);

}

struct Candidate {
	float score;
	VesselCrossSection::pointer crossSection;
};

class CandidateComparison {
	public:
		bool operator() (const Candidate& lhs, const Candidate& rhs) const {
			return lhs.score < rhs.score;
		}
};

void UltrasoundVesselDetection::execute() {
    Image::pointer input = getStaticInputData<Image>();
    if(input->getDimensions() != 2) {
        throw Exception("The UltrasoundVesselDetection algorithm is only for 2D");
    }

    mRuntimeManager->startRegularTimer("ellipse fitting");
    // Create kernel
    OpenCLDevice::pointer device = getMainDevice();
    cl::Program program = getOpenCLProgram(device);
    cl::Kernel kernel(program, "vesselDetection");

    // Run GaussianSmoothing on input
    GaussianSmoothingFilter::pointer filter = GaussianSmoothingFilter::New();
    filter->setInputData(input);
    filter->setMaskSize(5);
    filter->setStandardDeviation(2);
    filter->update();
    Image::pointer smoothedImage = filter->getOutputData<Image>();

    // Run ImageGradient on input
    ImageGradient::pointer imageGradient = ImageGradient::New();
    imageGradient->setInputConnection(filter->getOutputPort());
    imageGradient->update();
    Image::pointer gradients = imageGradient->getOutputData<Image>();
    OpenCLImageAccess::pointer inputImageAccess = input->getOpenCLImageAccess(ACCESS_READ, device);
    OpenCLImageAccess::pointer imageAccess = smoothedImage->getOpenCLImageAccess(ACCESS_READ, device);
    OpenCLImageAccess::pointer gradientAccess = gradients->getOpenCLImageAccess(ACCESS_READ, device);

    // Create output image
    boost::shared_array<float> zeros(new float[input->getWidth()*input->getHeight()*4]());
    cl::Image2D result = cl::Image2D(
            device->getContext(),
            CL_MEM_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
            getOpenCLImageFormat(device, CL_MEM_OBJECT_IMAGE2D, TYPE_FLOAT, 4),
            input->getWidth(), input->getHeight(),
			0,
			zeros.get()
    );

    // Run vessel detection kernel on smoothed image and gradient
    kernel.setArg(0, *inputImageAccess->get2DImage());
    kernel.setArg(1, *gradientAccess->get2DImage());
    kernel.setArg(2, result);
    kernel.setArg(3, input->getSpacing().x());

    const float minimumDepthInMM = 5;
    const float spacing = input->getSpacing().y();
    //const float maximumDepthInMM = 20;
    const float maximumDepthInMM = input->getHeight()*spacing*0.85;
    int startPosY = round(minimumDepthInMM/spacing);
    int endPosY = round(maximumDepthInMM/spacing);

    // Only process every second pixel
    cl::NDRange globalSize(input->getWidth() / 4, (endPosY-startPosY) / 4);
    cl::NDRange kernelOffset(0, startPosY / 4);
    device->getCommandQueue().enqueueNDRangeKernel(
            kernel,
			kernelOffset,
			globalSize,
            cl::NullRange
    );

    // Get result back
    boost::shared_array<float> data(new float[input->getWidth()*input->getHeight()*4]);
    device->getCommandQueue().enqueueReadImage(
            result,
            CL_TRUE,
            createOrigoRegion(),
            createRegion(input->getWidth(),input->getHeight(),1),
            0,0,
            data.get()
    );
    mRuntimeManager->stopRegularTimer("ellipse fitting");
    mRuntimeManager->startRegularTimer("candidate selection");

	AffineTransformation::pointer transform = SceneGraph::getAffineTransformationFromData(input);
	transform->scale(input->getSpacing());

    // Find best ellipses
	std::priority_queue<Candidate, std::vector<Candidate>, CandidateComparison> candidates;
	int startPosY2 = (startPosY / 4)*4;
    for(int x = 0; x < input->getWidth(); x+=4) {
        for(int y = startPosY2; y < endPosY; y+=4) {
            int i = x + y*input->getWidth();

            if(data[i*4] > 1.5) { // If score is higher than a threshold
				float posY = floor(data[i*4+3]/input->getWidth());
				float posX = data[i*4+3]-posY*input->getWidth();
				Vector3f voxelPosition(posX, posY, 0);
				Vector3f position = transform->multiply(voxelPosition);
				VesselCrossSection::pointer crossSection = VesselCrossSection::New();
				crossSection->create(position, voxelPosition.head(2), data[i*4+1], data[i*4+2]*data[i*4+1]);
				Candidate candidate;
				candidate.score = data[i*4];
				candidate.crossSection = crossSection;
				candidates.push(candidate);

            }
        }
    }

	mCrossSections.clear();
	// Go through all candidates
	while(!candidates.empty()) {
		Candidate next = candidates.top();
		candidates.pop();

		// Check if valid
		bool invalid = false;
		for(VesselCrossSection::pointer crossSection : mCrossSections) {
			VesselCrossSectionAccess::pointer access = crossSection->getAccess(ACCESS_READ);
			Vector2f imageCenter = access->getImageCenterPosition();
			float majorRadius = access->getMajorRadius();
			VesselCrossSectionAccess::pointer access2 = next.crossSection->getAccess(ACCESS_READ);
			if((access2->getImageCenterPosition() - imageCenter).norm() < majorRadius) {
				invalid = true;
				break;
			}
		}
		if(!invalid) {
			mCrossSections.push_back(next.crossSection);
		}
	}
	std::cout << mCrossSections.size() << " candidate vessels" << std::endl;
    mRuntimeManager->stopRegularTimer("candidate selection");
    mRuntimeManager->startRegularTimer("classifier");

    Vector3ui imageSize = input->getSize();

	// Create sub images and send to classifier
	std::vector<DataObject::pointer> subImages;
    for(int i = 0; i < std::min((int)mCrossSections.size(), 8); ++i) {
        VesselCrossSectionAccess::pointer access = mCrossSections[i]->getAccess(ACCESS_READ);
        Vector2f imageCenter = access->getImageCenterPosition();

        // Radius in pixels
        const float majorRadius = access->getMajorRadius();
        const float minorRadius = access->getMinorRadius();
		const int frameSize = std::max((int)round(majorRadius), 50); // Nr if pixels to include around vessel

        Vector2i offset(
                        round(imageCenter.x() - majorRadius) - frameSize,
                        round(imageCenter.y() - minorRadius) - frameSize
        );
        Vector2ui size(
                        2*majorRadius + 2*frameSize,
                        2*minorRadius + 2*frameSize
        );

        // Clamp to image bounds
        if(offset.x() < 0)
                offset.x() = 0;
        if(offset.y() < 0)
                offset.y() = 0;
        if(offset.x() + size.x() > imageSize.x())
                size.x() = imageSize.x() - offset.x();
        if(offset.y() + size.y() > imageSize.y())
                size.y() = imageSize.y() - offset.y();

        ImageCropper::pointer cropper = ImageCropper::New();
        cropper->setInputData(input);
        cropper->setOffset(offset.cast<uint>());
        cropper->setSize(size);
        cropper->update();
        subImages.push_back(cropper->getOutputData<Image>());
    }
	std::vector<VesselCrossSection::pointer> acceptedVessels;
	if(subImages.size() > 0) {
		mClassifier->setLabels({"Not vessel", "Vessel"});
		mClassifier->setInputData(subImages);
		mClassifier->update();

		std::vector<std::map<std::string, float> > classifierResult = mClassifier->getResult();
		int i = 0;
		for(std::map<std::string, float> res : classifierResult) {
			if(res["Vessel"] > 0.9) {
				acceptedVessels.push_back(mCrossSections[i]);
			}
			++i;
		}
	}
    mRuntimeManager->stopRegularTimer("classifier");

    if(mCreateSegmentation) {
		mRuntimeManager->startRegularTimer("segmentation");
        Segmentation::pointer segmentation = getStaticOutputData<Segmentation>(0);
        segmentation->createFromImage(input);

        OpenCLDevice::pointer device = getMainDevice();

        // Copy contents
        OpenCLImageAccess::pointer writeAccess = segmentation->getOpenCLImageAccess(ACCESS_READ_WRITE, device);
        cl::Image2D* outputData = writeAccess->get2DImage();
        // Create all zero data
        boost::shared_array<uchar> zeroData(new uchar[input->getWidth()*input->getHeight()]());
        device->getCommandQueue().enqueueWriteImage(
                *outputData,
                CL_TRUE,
                createOrigoRegion(),
                createRegion(input->getWidth(), input->getHeight(), 1),
                0, 0,
                zeroData.get()
                );
        cl::Kernel kernel(program, "createSegmentation");

        for(VesselCrossSection::pointer crossSection : acceptedVessels) {
            VesselCrossSectionAccess::pointer access = crossSection->getAccess(ACCESS_READ);
            Vector2f imageCenter = access->getImageCenterPosition();
            kernel.setArg(0, *outputData);
            kernel.setArg(1, imageCenter.x());
            kernel.setArg(2, imageCenter.y());
            kernel.setArg(3, access->getMajorRadius());
            kernel.setArg(4, access->getMinorRadius());

            device->getCommandQueue().enqueueNDRangeKernel(
                    kernel,
                    cl::NullRange,
                    cl::NDRange(input->getWidth(), input->getHeight()),
                    cl::NullRange
            );
        }
		mRuntimeManager->stopRegularTimer("segmentation");
    }
}

std::vector<VesselCrossSection::pointer> UltrasoundVesselDetection::getCrossSections() {
	return mCrossSections;
}

} // end namespace fast

<commit_msg>Code cleanup<commit_after>#include "FAST/Data/Image.hpp"
#include "FAST/Data/Segmentation.hpp"
#include "FAST/Data/PointSet.hpp"
#include "FAST/DeviceManager.hpp"
#include "FAST/Algorithms/GaussianSmoothingFilter/GaussianSmoothingFilter.hpp"
#include "FAST/Algorithms/ImageGradient/ImageGradient.hpp"
#include "FAST/Utility.hpp"
#include "FAST/SceneGraph.hpp"
#include <boost/shared_array.hpp>
#include <queue>
#include "FAST/Algorithms/UltrasoundVesselDetection/UltrasoundVesselDetection.hpp"
#include "FAST/Algorithms/ImageCropper/ImageCropper.hpp"
#include "FAST/Algorithms/ImageClassifier/ImageClassifier.hpp"

namespace fast {

ProcessObjectPort UltrasoundVesselDetection::getOutputSegmentationPort() {
    mCreateSegmentation = true;
    return getOutputPort(0);
}

UltrasoundVesselDetection::UltrasoundVesselDetection() {
    createInputPort<Image>(0);
    createOutputPort<Segmentation>(0, OUTPUT_DEPENDS_ON_INPUT, 0);
    createOpenCLProgram(std::string(FAST_SOURCE_DIR) + "Algorithms/UltrasoundVesselDetection/UltrasoundVesselDetection.cl");
    mCreateSegmentation = false;

	mClassifier = ImageClassifier::New();
	std::string modelFile = "/home/smistad/vessel_detection_model/deploy.prototxt";
	std::string trainingFile = "/home/smistad/vessel_detection_model/snapshot_iter_540.caffemodel";
	std::string meanFile = "/home/smistad/vessel_detection_model/mean.binaryproto";
	//std::string modelFile = "/home/smistad/vessel_detection_model2/deploy.prototxt";
	//std::string trainingFile = "/home/smistad/vessel_detection_model2/snapshot_iter_960.caffemodel";
	//std::string meanFile = "/home/smistad/vessel_detection_model2/mean.binaryproto";
	mClassifier->loadModel(modelFile, trainingFile, meanFile);

}

struct Candidate {
	float score;
	VesselCrossSection::pointer crossSection;
};

class CandidateComparison {
	public:
		bool operator() (const Candidate& lhs, const Candidate& rhs) const {
			return lhs.score < rhs.score;
		}
};

void UltrasoundVesselDetection::execute() {
    Image::pointer input = getStaticInputData<Image>();
    if(input->getDimensions() != 2) {
        throw Exception("The UltrasoundVesselDetection algorithm is only for 2D");
    }

    mRuntimeManager->startRegularTimer("ellipse fitting");
    // Create kernel
    OpenCLDevice::pointer device = getMainDevice();
    cl::Program program = getOpenCLProgram(device);
    cl::Kernel kernel(program, "vesselDetection");

    // Run GaussianSmoothing on input
    GaussianSmoothingFilter::pointer filter = GaussianSmoothingFilter::New();
    filter->setInputData(input);
    filter->setMaskSize(5);
    filter->setStandardDeviation(2);
    filter->update();
    Image::pointer smoothedImage = filter->getOutputData<Image>();

    // Run ImageGradient on input
    ImageGradient::pointer imageGradient = ImageGradient::New();
    imageGradient->setInputConnection(filter->getOutputPort());
    imageGradient->update();
    Image::pointer gradients = imageGradient->getOutputData<Image>();
    OpenCLImageAccess::pointer inputImageAccess = input->getOpenCLImageAccess(ACCESS_READ, device);
    OpenCLImageAccess::pointer imageAccess = smoothedImage->getOpenCLImageAccess(ACCESS_READ, device);
    OpenCLImageAccess::pointer gradientAccess = gradients->getOpenCLImageAccess(ACCESS_READ, device);

    // Create output image
    boost::shared_array<float> zeros(new float[input->getWidth()*input->getHeight()*4]());
    cl::Image2D result = cl::Image2D(
            device->getContext(),
            CL_MEM_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
            getOpenCLImageFormat(device, CL_MEM_OBJECT_IMAGE2D, TYPE_FLOAT, 4),
            input->getWidth(), input->getHeight(),
			0,
			zeros.get()
    );

    // Run vessel detection kernel on smoothed image and gradient
    kernel.setArg(0, *inputImageAccess->get2DImage());
    kernel.setArg(1, *gradientAccess->get2DImage());
    kernel.setArg(2, result);
    kernel.setArg(3, input->getSpacing().x());

    const float minimumDepthInMM = 5;
    const float spacing = input->getSpacing().y();
    //const float maximumDepthInMM = 20;
    const float maximumDepthInMM = input->getHeight()*spacing*0.85;
    int startPosY = round(minimumDepthInMM/spacing);
    int endPosY = round(maximumDepthInMM/spacing);

    // Only process every second pixel
    cl::NDRange globalSize(input->getWidth() / 4, (endPosY-startPosY) / 4);
    cl::NDRange kernelOffset(0, startPosY / 4);
    device->getCommandQueue().enqueueNDRangeKernel(
            kernel,
			kernelOffset,
			globalSize,
            cl::NullRange
    );

    // Get result back
    boost::shared_array<float> data(new float[input->getWidth()*input->getHeight()*4]);
    device->getCommandQueue().enqueueReadImage(
            result,
            CL_TRUE,
            createOrigoRegion(),
            createRegion(input->getWidth(),input->getHeight(),1),
            0,0,
            data.get()
    );
    mRuntimeManager->stopRegularTimer("ellipse fitting");
    mRuntimeManager->startRegularTimer("candidate selection");

	AffineTransformation::pointer transform = SceneGraph::getAffineTransformationFromData(input);
	transform->scale(input->getSpacing());

    // Find best ellipses
	std::priority_queue<Candidate, std::vector<Candidate>, CandidateComparison> candidates;
	int startPosY2 = (startPosY / 4)*4;
    for(int x = 0; x < input->getWidth(); x+=4) {
        for(int y = startPosY2; y < endPosY; y+=4) {
            int i = x + y*input->getWidth();

            if(data[i*4] > 1.5) { // If score is higher than a threshold
				float posY = floor(data[i*4+3]/input->getWidth());
				float posX = data[i*4+3]-posY*input->getWidth();
				Vector3f voxelPosition(posX, posY, 0);
				Vector3f position = transform->multiply(voxelPosition);
				VesselCrossSection::pointer crossSection = VesselCrossSection::New();
				crossSection->create(position, voxelPosition.head(2), data[i*4+1], data[i*4+2]*data[i*4+1]);
				Candidate candidate;
				candidate.score = data[i*4];
				candidate.crossSection = crossSection;
				candidates.push(candidate);

            }
        }
    }

	mCrossSections.clear();
	// Go through all candidates
	while(!candidates.empty()) {
		Candidate next = candidates.top();
		candidates.pop();

		// Check if valid
		bool invalid = false;
		VesselCrossSectionAccess::pointer access2 = next.crossSection->getAccess(ACCESS_READ);
		Vector2f candidateImageCenter = access2->getImageCenterPosition();
		for(VesselCrossSection::pointer crossSection : mCrossSections) {
			VesselCrossSectionAccess::pointer access = crossSection->getAccess(ACCESS_READ);
			Vector2f imageCenter = access->getImageCenterPosition();
			float majorRadius = access->getMajorRadius();
			if((candidateImageCenter - imageCenter).norm() < majorRadius) {
				invalid = true;
				break;
			}
		}
		if(!invalid) {
			mCrossSections.push_back(next.crossSection);
		}
	}
	std::cout << mCrossSections.size() << " candidate vessels" << std::endl;
    mRuntimeManager->stopRegularTimer("candidate selection");
    mRuntimeManager->startRegularTimer("classifier");

    Vector3ui imageSize = input->getSize();

	// Create sub images and send to classifier
	std::vector<DataObject::pointer> subImages;
    for(int i = 0; i < std::min((int)mCrossSections.size(), 8); ++i) {
        VesselCrossSectionAccess::pointer access = mCrossSections[i]->getAccess(ACCESS_READ);
        Vector2f imageCenter = access->getImageCenterPosition();

        // Radius in pixels
        const float majorRadius = access->getMajorRadius();
        const float minorRadius = access->getMinorRadius();
		const int frameSize = std::max((int)round(majorRadius), 50); // Nr if pixels to include around vessel

        Vector2i offset(
                        round(imageCenter.x() - majorRadius) - frameSize,
                        round(imageCenter.y() - minorRadius) - frameSize
        );
        Vector2ui size(
                        2*majorRadius + 2*frameSize,
                        2*minorRadius + 2*frameSize
        );

        // Clamp to image bounds
        if(offset.x() < 0)
                offset.x() = 0;
        if(offset.y() < 0)
                offset.y() = 0;
        if(offset.x() + size.x() > imageSize.x())
                size.x() = imageSize.x() - offset.x();
        if(offset.y() + size.y() > imageSize.y())
                size.y() = imageSize.y() - offset.y();

        ImageCropper::pointer cropper = ImageCropper::New();
        cropper->setInputData(input);
        cropper->setOffset(offset.cast<uint>());
        cropper->setSize(size);
        cropper->update();
        subImages.push_back(cropper->getOutputData<Image>());
    }
	std::vector<VesselCrossSection::pointer> acceptedVessels;
	if(subImages.size() > 0) {
		mClassifier->setLabels({"Not vessel", "Vessel"});
		mClassifier->setInputData(subImages);
		mClassifier->update();

		std::vector<std::map<std::string, float> > classifierResult = mClassifier->getResult();
		int i = 0;
		for(std::map<std::string, float> res : classifierResult) {
			if(res["Vessel"] > 0.9) {
				acceptedVessels.push_back(mCrossSections[i]);
			}
			++i;
		}
	}
    mRuntimeManager->stopRegularTimer("classifier");

    if(mCreateSegmentation) {
		mRuntimeManager->startRegularTimer("segmentation");
        Segmentation::pointer segmentation = getStaticOutputData<Segmentation>(0);
        segmentation->createFromImage(input);

        OpenCLDevice::pointer device = getMainDevice();

        // Copy contents
        OpenCLImageAccess::pointer writeAccess = segmentation->getOpenCLImageAccess(ACCESS_READ_WRITE, device);
        cl::Image2D* outputData = writeAccess->get2DImage();
        // Create all zero data
        boost::shared_array<uchar> zeroData(new uchar[input->getWidth()*input->getHeight()]());
        device->getCommandQueue().enqueueWriteImage(
                *outputData,
                CL_TRUE,
                createOrigoRegion(),
                createRegion(input->getWidth(), input->getHeight(), 1),
                0, 0,
                zeroData.get()
                );
        cl::Kernel kernel(program, "createSegmentation");

        for(VesselCrossSection::pointer crossSection : acceptedVessels) {
            VesselCrossSectionAccess::pointer access = crossSection->getAccess(ACCESS_READ);
            Vector2f imageCenter = access->getImageCenterPosition();
            kernel.setArg(0, *outputData);
            kernel.setArg(1, imageCenter.x());
            kernel.setArg(2, imageCenter.y());
            kernel.setArg(3, access->getMajorRadius());
            kernel.setArg(4, access->getMinorRadius());

            device->getCommandQueue().enqueueNDRangeKernel(
                    kernel,
                    cl::NullRange,
                    cl::NDRange(input->getWidth(), input->getHeight()),
                    cl::NullRange
            );
        }
		mRuntimeManager->stopRegularTimer("segmentation");
    }
}

std::vector<VesselCrossSection::pointer> UltrasoundVesselDetection::getCrossSections() {
	return mCrossSections;
}

} // end namespace fast

<|endoftext|>


<commit_before>//
//  main.cpp
//  parsetool
//
//  Created by Andrew Hunter on 24/09/2011.
//
//  Copyright (c) 2011-2012 Andrew Hunter
//
//  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 "TameParse/TameParse.h"
#include "boost_console.h"

#include <iostream>
#include <memory>

using namespace std;
using namespace dfa;
using namespace contextfree;
using namespace lr;
using namespace tameparse;
using namespace language;
using namespace compiler;

int main (int argc, const char * argv[])
{
    // Create the console
    boost_console       console(argc, argv);
    console_container   cons(&console, false);

    try {
        // Give up if the console is set not to start
        if (!console.can_start()) {
            return 1;
        }

        // Startup message
        console.message_stream() << L"TameParse " << version::major_version << "." << version::minor_version << "." << version::revision << endl;
        console.verbose_stream() << endl;

        // Parse the input file
        parser_stage parserStage(cons, console.input_file());
        parserStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // The definition file should exist
        if (!parserStage.definition_file().item()) {
            console.report_error(error(error::sev_bug, console.input_file(), L"BUG_NO_FILE_DATA", L"File did not produce any data", position(-1, -1, -1)));
            return error::sev_bug;
        }

        // Parse any imported files
        import_stage importStage(cons, console.input_file(), parserStage.definition_file());
        importStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // Run any tests that were specified
        if (!console.get_option(L"run-tests").empty()) {
            test_stage tests(cons, console.input_file(), parserStage.definition_file(), &importStage);
            tests.compile();

            // Stop if we have an error
            if (console.exit_code()) {
                return console.exit_code();
            }

            // If --run-tests is specified and no explicit options for generating an output file is supplied then stop here
            if (console.get_option(L"output-file").empty()
                && console.get_option(L"start-symbol").empty()
                && console.get_option(L"output-language").empty()
                && console.get_option(L"test").empty()
                && console.get_option(L"show-parser").empty()) {
                return console.exit_code();
            }
        }

        // Convert to grammars & NDFAs
        language_builder_stage builderStage(cons, console.input_file(), &importStage);
        builderStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // Work out the name of the language to build and the start symbols
        wstring         buildLanguageName   = console.get_option(L"compile-language");
        wstring         buildClassName      = console.get_option(L"class-name");
        vector<wstring> startSymbols        = console.get_option_list(L"start-symbol");
        wstring         targetLanguage      = console.get_option(L"target-language");
        wstring         buildNamespaceName  = console.get_option(L"namespace-name");
        position        parseBlockPosition  = position(-1, -1, -1);

        // Use the options by default
        if (console.get_option(L"compile-language").empty()) {
            // TODO: get information from the parser block
            // TODO: the class-name option overrides the name specified in the parser block (but gives a warning)
            // TODO: use the position of the parser block to report
            // TODO: deal with multiple parser blocks somehow (error? generate multiple classes?)
        }

        // If there is only one language in the original file and none specified, then we will generate that
        if (buildLanguageName.empty()) {
            int languageCount = 0;

            // Find all of the language blocks
            for (definition_file::iterator defnBlock = parserStage.definition_file()->begin(); defnBlock != parserStage.definition_file()->end(); ++defnBlock) {
                if ((*defnBlock)->language()) {
                    ++languageCount;
                    if (languageCount > 1) {
                        // Multiple languages: can't infer one
                        buildLanguageName.clear();
                        break;
                    } else {
                        // This is the first language: use its identifier as the language to build
                        buildLanguageName = (*defnBlock)->language()->identifier();
                    }
                }
            }

            // Tell the user about this
            if (!buildLanguageName.empty()) {
                wstringstream msg;
                msg << L"Language name not explicitly specified: will use '" << buildLanguageName << L"'";
                console.report_error(error(error::sev_info, console.input_file(), L"INFERRED_LANGUAGE", msg.str(), parseBlockPosition));
            }
        }

        // Error if there is no language specified
        if (buildLanguageName.empty()) {
            console.report_error(error(error::sev_error, console.input_file(), L"NO_LANGUAGE_SPECIFIED", L"Could not determine which language block to compile", parseBlockPosition));
            return error::sev_error;
        }

        // Infer the class name to use if none is specified (same as the language name)
        if (buildClassName.empty()) {
            buildClassName = buildLanguageName;
        }

        // Get the language that we're going to compile
        const language_block*   compileLanguage       = importStage.language_with_name(buildLanguageName);
        language_stage*         compileLanguageStage  = builderStage.language_with_name(buildLanguageName);
        if (!compileLanguage || !compileLanguageStage) {
            // The language could not be found
            wstringstream msg;
            msg << L"Could not find the target language '" << buildLanguageName << L"'";
            console.report_error(error(error::sev_error, console.input_file(), L"MISSING_TARGET_LANGUAGE", msg.str(), parseBlockPosition));
            return error::sev_error;
        }

        // Report any unused symbols in the language
        compileLanguageStage->report_unused_symbols();

        // Infer the start symbols if there are none
        if (startSymbols.empty()) {
            // TODO: Use the first nonterminal defined in the language block
            // TODO: warn if we establish a start symbol this way
        }

        if (startSymbols.empty()) {
            // Error if we can't find any start symbols at all
            console.report_error(error(error::sev_error, console.input_file(), L"NO_START_SYMBOLS", L"Could not determine a start symbol for the language (use the start-symbol option to specify one manually)", parseBlockPosition));
            return error::sev_error;
        }

        // Generate the lexer for the target language
        lexer_stage lexerStage(cons, importStage.file_with_language(buildLanguageName), compileLanguageStage);
        lexerStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // Generate the parser
        lr_parser_stage lrParserStage(cons, importStage.file_with_language(buildLanguageName), compileLanguageStage, &lexerStage, startSymbols);
        lrParserStage.compile();

        // Write the parser out if requested
        if (!console.get_option(L"show-parser").empty() || !console.get_option(L"show-parser-closure").empty()) {
            wcout << endl << L"== Parser tables:" << endl << formatter::to_string(*lrParserStage.get_parser(), *compileLanguageStage->grammar(), *compileLanguageStage->terminals(), !console.get_option(L"show-parser-closure").empty()) << endl;
        }

        // Display the propagation tables if requested
        if (!console.get_option(L"show-propagation").empty()) {
            // Get the parser builder
            lalr_builder* builder = lrParserStage.get_parser();
            typedef lalr_builder::lr_item_id lr_item_id;

            if (builder) {
                // Write out a header
                wcout << endl << L"== Symbol propagation:" << endl;

                // Iterate through the states
                for (int stateId = 0; stateId < builder->machine().count_states(); stateId++) {
                    const lalr_state& state = *builder->machine().state_with_id(stateId);

                    // Write out the state ID
                    wcout << L"State #" << stateId << endl;

                    // Go through the items
                    for (int itemId = 0; itemId < state.count_items(); itemId++) {
                        // Get the spontaneous lookahead generation for this item
                        const set<lr_item_id>& spontaneous  = builder->spontaneous_for_item(stateId, itemId);
                        const set<lr_item_id>& propagate    = builder->propagations_for_item(stateId, itemId);

                        // Ignore any items that have no items in them
                        if (spontaneous.empty() && propagate.empty()) continue;

                        wcout   << L"  "
                                << formatter::to_string(*state[itemId], *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                << L" " << formatter::to_string(state.lookahead_for(itemId), *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                << endl;

                        // Write out which items generate spontaneous lookaheads
                        for (set<lr_item_id>::const_iterator spont = spontaneous.begin(); spont != spontaneous.end(); spont++) {
                            const item_set& lookahead = builder->lookahead_for_spontaneous(stateId, itemId, spont->state_id, spont->item_id);

                            wcout   << L"    Spontaneous -> state #" << spont->state_id << ": "
                                    << formatter::to_string(*(*builder->machine().state_with_id(spont->state_id))[spont->item_id], *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                    << L" " << formatter::to_string(lookahead, *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                    << endl;
                        }

                        // Write out which items propagate lookaheads
                        for (set<lr_item_id>::const_iterator prop = propagate.begin(); prop != propagate.end(); prop++) {
                            wcout   << L"    Propagate -> state #" << prop->state_id << ": "
                                    << formatter::to_string(*(*builder->machine().state_with_id(prop->state_id))[prop->item_id], *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                    << endl;
                        }
                    }
                }
            }
        }

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // The --test option sets the target language to 'test'
        if (!console.get_option(L"test").empty()) {
            targetLanguage = L"test";
        }

        // Target language is C++ if no language is specified
        if (targetLanguage.empty()) {
            targetLanguage = L"cplusplus";
        }

        // Work out the prefix filename
        wstring prefixFilename = console.get_option(L"output-language");
        if (prefixFilename.empty()) {
            // Derive from the input file
            // This works provided the target language
            prefixFilename = console.input_file();
        }

        // Create the output stage
        auto_ptr<output_stage> outputStage(NULL);

        if (targetLanguage == L"cplusplus") {
            // Use the C++ language generator
            outputStage = auto_ptr<output_stage>(new output_cplusplus(cons, importStage.file_with_language(buildLanguageName), &lexerStage, compileLanguageStage, &lrParserStage, prefixFilename, buildClassName, buildNamespaceName));
        } else if (targetLanguage == L"test") {
            // Special case: read from stdin, and try to parse the source language
            ast_parser parser(*lrParserStage.get_tables());

            // Create the parser
            lexeme_stream* stdinStream      = lexerStage.get_lexer()->create_stream_from(wcin);
            ast_parser::state* stdInParser  = parser.create_parser(new ast_parser_actions(stdinStream));

            // Parse stdin
            if (stdInParser->parse()) {
                console.verbose_stream() << formatter::to_string(*stdInParser->get_item(), *compileLanguageStage->grammar(), *compileLanguageStage->terminals()) << endl;
            } else {
                position failPos(-1, -1, -1);
                if (stdInParser->look().item()) {
                    failPos = stdInParser->look()->pos();
                }

                console.report_error(error(error::sev_error, L"stdin", L"TEST_PARSER_ERROR", L"Syntax error", failPos));
            }
        } else {
            // Unknown target language
            wstringstream msg;
            msg << L"Output language '" << targetLanguage << L"' is not known";
            console.report_error(error(error::sev_error, console.input_file(), L"UNKNOWN_OUTPUT_LANGUAGE_TYPE", msg.str(), position(-1, -1, -1)));
            return error::sev_error;
        }

        // Compile the final output
        if (outputStage.get()) {
            outputStage->compile();
        }

        // Done
        return console.exit_code();
    } catch (...) {
        console.report_error(error(error::sev_bug, L"", L"BUG_UNCAUGHT_EXCEPTION", L"Uncaught exception", position(-1, -1, -1)));
        throw;
    }
}

<commit_msg>Fixed an issue with the way the target language is parsed. Added a new 'fake' language which runs tests using the parser in diagnostic mode.<commit_after>//
//  main.cpp
//  parsetool
//
//  Created by Andrew Hunter on 24/09/2011.
//
//  Copyright (c) 2011-2012 Andrew Hunter
//
//  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 "TameParse/TameParse.h"
#include "boost_console.h"

#include <iostream>
#include <memory>

using namespace std;
using namespace util;
using namespace dfa;
using namespace contextfree;
using namespace lr;
using namespace tameparse;
using namespace language;
using namespace compiler;

int main (int argc, const char * argv[])
{
    // Create the console
    boost_console       console(argc, argv);
    console_container   cons(&console, false);

    try {
        // Give up if the console is set not to start
        if (!console.can_start()) {
            return 1;
        }

        // Startup message
        console.message_stream() << L"TameParse " << version::major_version << "." << version::minor_version << "." << version::revision << endl;
        console.verbose_stream() << endl;

        // Parse the input file
        parser_stage parserStage(cons, console.input_file());
        parserStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // The definition file should exist
        if (!parserStage.definition_file().item()) {
            console.report_error(error(error::sev_bug, console.input_file(), L"BUG_NO_FILE_DATA", L"File did not produce any data", position(-1, -1, -1)));
            return error::sev_bug;
        }

        // Parse any imported files
        import_stage importStage(cons, console.input_file(), parserStage.definition_file());
        importStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // Run any tests that were specified
        if (!console.get_option(L"run-tests").empty()) {
            test_stage tests(cons, console.input_file(), parserStage.definition_file(), &importStage);
            tests.compile();

            // Stop if we have an error
            if (console.exit_code()) {
                return console.exit_code();
            }

            // If --run-tests is specified and no explicit options for generating an output file is supplied then stop here
            if (console.get_option(L"output-file").empty()
                && console.get_option(L"start-symbol").empty()
                && console.get_option(L"output-language").empty()
                && console.get_option(L"test").empty()
                && console.get_option(L"show-parser").empty()) {
                return console.exit_code();
            }
        }

        // Convert to grammars & NDFAs
        language_builder_stage builderStage(cons, console.input_file(), &importStage);
        builderStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // Work out the name of the language to build and the start symbols
        wstring         buildLanguageName   = console.get_option(L"compile-language");
        wstring         buildClassName      = console.get_option(L"class-name");
        vector<wstring> startSymbols        = console.get_option_list(L"start-symbol");
        wstring         targetLanguage      = console.get_option(L"output-language");
        wstring         buildNamespaceName  = console.get_option(L"namespace-name");
        position        parseBlockPosition  = position(-1, -1, -1);

        // Use the options by default
        if (console.get_option(L"compile-language").empty()) {
            // TODO: get information from the parser block
            // TODO: the class-name option overrides the name specified in the parser block (but gives a warning)
            // TODO: use the position of the parser block to report
            // TODO: deal with multiple parser blocks somehow (error? generate multiple classes?)
        }

        // If there is only one language in the original file and none specified, then we will generate that
        if (buildLanguageName.empty()) {
            int languageCount = 0;

            // Find all of the language blocks
            for (definition_file::iterator defnBlock = parserStage.definition_file()->begin(); defnBlock != parserStage.definition_file()->end(); ++defnBlock) {
                if ((*defnBlock)->language()) {
                    ++languageCount;
                    if (languageCount > 1) {
                        // Multiple languages: can't infer one
                        buildLanguageName.clear();
                        break;
                    } else {
                        // This is the first language: use its identifier as the language to build
                        buildLanguageName = (*defnBlock)->language()->identifier();
                    }
                }
            }

            // Tell the user about this
            if (!buildLanguageName.empty()) {
                wstringstream msg;
                msg << L"Language name not explicitly specified: will use '" << buildLanguageName << L"'";
                console.report_error(error(error::sev_info, console.input_file(), L"INFERRED_LANGUAGE", msg.str(), parseBlockPosition));
            }
        }

        // Error if there is no language specified
        if (buildLanguageName.empty()) {
            console.report_error(error(error::sev_error, console.input_file(), L"NO_LANGUAGE_SPECIFIED", L"Could not determine which language block to compile", parseBlockPosition));
            return error::sev_error;
        }

        // Infer the class name to use if none is specified (same as the language name)
        if (buildClassName.empty()) {
            buildClassName = buildLanguageName;
        }

        // Get the language that we're going to compile
        const language_block*   compileLanguage       = importStage.language_with_name(buildLanguageName);
        language_stage*         compileLanguageStage  = builderStage.language_with_name(buildLanguageName);
        if (!compileLanguage || !compileLanguageStage) {
            // The language could not be found
            wstringstream msg;
            msg << L"Could not find the target language '" << buildLanguageName << L"'";
            console.report_error(error(error::sev_error, console.input_file(), L"MISSING_TARGET_LANGUAGE", msg.str(), parseBlockPosition));
            return error::sev_error;
        }

        // Report any unused symbols in the language
        compileLanguageStage->report_unused_symbols();

        // Infer the start symbols if there are none
        if (startSymbols.empty()) {
            // TODO: Use the first nonterminal defined in the language block
            // TODO: warn if we establish a start symbol this way
        }

        if (startSymbols.empty()) {
            // Error if we can't find any start symbols at all
            console.report_error(error(error::sev_error, console.input_file(), L"NO_START_SYMBOLS", L"Could not determine a start symbol for the language (use the start-symbol option to specify one manually)", parseBlockPosition));
            return error::sev_error;
        }

        // Generate the lexer for the target language
        lexer_stage lexerStage(cons, importStage.file_with_language(buildLanguageName), compileLanguageStage);
        lexerStage.compile();

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // Generate the parser
        lr_parser_stage lrParserStage(cons, importStage.file_with_language(buildLanguageName), compileLanguageStage, &lexerStage, startSymbols);
        lrParserStage.compile();

        // Write the parser out if requested
        if (!console.get_option(L"show-parser").empty() || !console.get_option(L"show-parser-closure").empty()) {
            wcout << endl << L"== Parser tables:" << endl << formatter::to_string(*lrParserStage.get_parser(), *compileLanguageStage->grammar(), *compileLanguageStage->terminals(), !console.get_option(L"show-parser-closure").empty()) << endl;
        }

        // Display the propagation tables if requested
        if (!console.get_option(L"show-propagation").empty()) {
            // Get the parser builder
            lalr_builder* builder = lrParserStage.get_parser();
            typedef lalr_builder::lr_item_id lr_item_id;

            if (builder) {
                // Write out a header
                wcout << endl << L"== Symbol propagation:" << endl;

                // Iterate through the states
                for (int stateId = 0; stateId < builder->machine().count_states(); stateId++) {
                    const lalr_state& state = *builder->machine().state_with_id(stateId);

                    // Write out the state ID
                    wcout << L"State #" << stateId << endl;

                    // Go through the items
                    for (int itemId = 0; itemId < state.count_items(); itemId++) {
                        // Get the spontaneous lookahead generation for this item
                        const set<lr_item_id>& spontaneous  = builder->spontaneous_for_item(stateId, itemId);
                        const set<lr_item_id>& propagate    = builder->propagations_for_item(stateId, itemId);

                        // Ignore any items that have no items in them
                        if (spontaneous.empty() && propagate.empty()) continue;

                        wcout   << L"  "
                                << formatter::to_string(*state[itemId], *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                << L" " << formatter::to_string(state.lookahead_for(itemId), *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                << endl;

                        // Write out which items generate spontaneous lookaheads
                        for (set<lr_item_id>::const_iterator spont = spontaneous.begin(); spont != spontaneous.end(); spont++) {
                            const item_set& lookahead = builder->lookahead_for_spontaneous(stateId, itemId, spont->state_id, spont->item_id);

                            wcout   << L"    Spontaneous -> state #" << spont->state_id << ": "
                                    << formatter::to_string(*(*builder->machine().state_with_id(spont->state_id))[spont->item_id], *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                    << L" " << formatter::to_string(lookahead, *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                    << endl;
                        }

                        // Write out which items propagate lookaheads
                        for (set<lr_item_id>::const_iterator prop = propagate.begin(); prop != propagate.end(); prop++) {
                            wcout   << L"    Propagate -> state #" << prop->state_id << ": "
                                    << formatter::to_string(*(*builder->machine().state_with_id(prop->state_id))[prop->item_id], *compileLanguageStage->grammar(), *compileLanguageStage->terminals())
                                    << endl;
                        }
                    }
                }
            }
        }

        // Stop if we have an error
        if (console.exit_code()) {
            return console.exit_code();
        }

        // The --test option sets the target language to 'test'
        if (!console.get_option(L"test").empty()) {
            targetLanguage = L"test";
        }

        // Target language is C++ if no language is specified
        if (targetLanguage.empty()) {
            targetLanguage = L"cplusplus";
        }

        // Work out the prefix filename
        wstring prefixFilename = console.get_option(L"output-language");
        if (prefixFilename.empty()) {
            // Derive from the input file
            // This works provided the target language
            prefixFilename = console.input_file();
        }

        // Create the output stage
        auto_ptr<output_stage> outputStage(NULL);

        if (targetLanguage == L"cplusplus") {
            // Use the C++ language generator
            outputStage = auto_ptr<output_stage>(new output_cplusplus(cons, importStage.file_with_language(buildLanguageName), &lexerStage, compileLanguageStage, &lrParserStage, prefixFilename, buildClassName, buildNamespaceName));
        } else if (targetLanguage == L"test") {
            // Special case: read from stdin, and try to parse the source language
            ast_parser parser(*lrParserStage.get_tables());

            // Create the parser
            lexeme_stream* stdinStream      = lexerStage.get_lexer()->create_stream_from(wcin);
            ast_parser::state* stdInParser  = parser.create_parser(new ast_parser_actions(stdinStream));

            // Parse stdin
            if (stdInParser->parse()) {
                console.verbose_stream() << formatter::to_string(*stdInParser->get_item(), *compileLanguageStage->grammar(), *compileLanguageStage->terminals()) << endl;
            } else {
                position failPos(-1, -1, -1);
                if (stdInParser->look().item()) {
                    failPos = stdInParser->look()->pos();
                }

                console.report_error(error(error::sev_error, L"stdin", L"TEST_PARSER_ERROR", L"Syntax error", failPos));
            }
        } else if (targetLanguage == L"test-trace") {
            // Special case: same as for test, but use the debug version of the parser
            typedef parser<astnode_container, ast_parser_actions, debug_parser_trace<1> > trace_parser;
            trace_parser parser(*lrParserStage.get_tables());

            // Create the parser
            lexeme_stream* stdinStream          = lexerStage.get_lexer()->create_stream_from(wcin);
            trace_parser::state* stdInParser    = parser.create_parser(new ast_parser_actions(stdinStream));

            // Parse stdin
            if (stdInParser->parse()) {
                console.verbose_stream() << formatter::to_string(*stdInParser->get_item(), *compileLanguageStage->grammar(), *compileLanguageStage->terminals()) << endl;
            } else {
                position failPos(-1, -1, -1);
                if (stdInParser->look().item()) {
                    failPos = stdInParser->look()->pos();
                }

                console.report_error(error(error::sev_error, L"stdin", L"TEST_PARSER_ERROR", L"Syntax error", failPos));

                // Report the stack at the point of failure
                trace_parser::stack stack = stdInParser->get_stack();
                console.verbose_stream() << endl << L"Stack:" << endl;
                do {
                    console.verbose_stream() << formatter::to_string(*stack->item, *compileLanguageStage->grammar(), *compileLanguageStage->terminals()) << endl;
                } while (stack.pop());
            }
        } else {
            // Unknown target language
            wstringstream msg;
            msg << L"Output language '" << targetLanguage << L"' is not known";
            console.report_error(error(error::sev_error, console.input_file(), L"UNKNOWN_OUTPUT_LANGUAGE_TYPE", msg.str(), position(-1, -1, -1)));
            return error::sev_error;
        }

        // Compile the final output
        if (outputStage.get()) {
            outputStage->compile();
        }

        // Done
        return console.exit_code();
    } catch (...) {
        console.report_error(error(error::sev_bug, L"", L"BUG_UNCAUGHT_EXCEPTION", L"Uncaught exception", position(-1, -1, -1)));
        throw;
    }
}
<|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.
 *
 */

// [[CITE]] Tarjan's strongly connected components algorithm
// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010
// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SccWorker
{
	RTLIL::Design *design;
	RTLIL::Module *module;
	SigMap sigmap;
	CellTypes ct;

	std::set<RTLIL::Cell*> workQueue;
	std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
	std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;

	std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
	std::map<RTLIL::Cell*, int> cellDepth;
	std::set<RTLIL::Cell*> cellsOnStack;
	std::vector<RTLIL::Cell*> cellStack;
	int labelCounter;

	std::map<RTLIL::Cell*, int> cell2scc;
	std::vector<std::set<RTLIL::Cell*>> sccList;

	void run(RTLIL::Cell *cell, int depth, int maxDepth)
	{
		log_assert(workQueue.count(cell) > 0);

		workQueue.erase(cell);
		cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
		labelCounter++;

		cellsOnStack.insert(cell);
		cellStack.push_back(cell);

		if (maxDepth >= 0)
			cellDepth[cell] = depth;

		for (auto nextCell : cellToNextCell[cell])
			if (cellLabels.count(nextCell) == 0) {
				run(nextCell, depth+1, maxDepth);
				cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			} else
			if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
					cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			}

		if (cellLabels[cell].first == cellLabels[cell].second)
		{
			if (cellStack.back() == cell)
			{
				cellStack.pop_back();
				cellsOnStack.erase(cell);
			}
			else
			{
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				while (cellsOnStack.count(cell) > 0) {
					RTLIL::Cell *c = cellStack.back();
					cellStack.pop_back();
					cellsOnStack.erase(c);
					log(" %s", RTLIL::id2cstr(c->name));
					cell2scc[c] = sccList.size();
					scc.insert(c);
				}
				sccList.push_back(scc);
				log("\n");
			}
		}
	}

	SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
			design(design), module(module), sigmap(module)
	{
		if (module->processes.size() > 0) {
			log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
			return;
		}

		if (allCellTypes) {
			ct.setup(design);
		} else {
			ct.setup_internals();
			ct.setup_stdcells();
		}

		SigPool selectedSignals;
		SigSet<RTLIL::Cell*> sigToNextCells;

		for (auto &it : module->wires_)
			if (design->selected(module, it.second))
				selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));

		for (auto &it : module->cells_)
		{
			RTLIL::Cell *cell = it.second;

			if (!design->selected(module, cell))
				continue;

			if (!allCellTypes && !ct.cell_known(cell->type))
				continue;

			workQueue.insert(cell);

			RTLIL::SigSpec inputSignals, outputSignals;

			for (auto &conn : cell->connections())
			{
				bool isInput = true, isOutput = true;

				if (ct.cell_known(cell->type)) {
					isInput = ct.cell_input(cell->type, conn.first);
					isOutput = ct.cell_output(cell->type, conn.first);
				}

				RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
				sig.sort_and_unify();

				if (isInput)
					inputSignals.append(sig);
				if (isOutput)
					outputSignals.append(sig);
			}

			inputSignals.sort_and_unify();
			outputSignals.sort_and_unify();

			cellToPrevSig[cell] = inputSignals;
			cellToNextSig[cell] = outputSignals;
			sigToNextCells.insert(inputSignals, cell);
		}

		for (auto cell : workQueue)
		{
			cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);

			if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				log(" %s", RTLIL::id2cstr(cell->name));
				cell2scc[cell] = sccList.size();
				scc.insert(cell);
				sccList.push_back(scc);
				log("\n");
			}
		}

		labelCounter = 0;
		cellLabels.clear();

		while (!workQueue.empty())
		{
			RTLIL::Cell *cell = *workQueue.begin();
			log_assert(cellStack.size() == 0);
			cellDepth.clear();

			run(cell, 0, maxDepth);
		}

		log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
	}

	void select(RTLIL::Selection &sel)
	{
		for (int i = 0; i < int(sccList.size()); i++)
		{
			std::set<RTLIL::Cell*> &cells = sccList[i];
			RTLIL::SigSpec prevsig, nextsig, sig;

			for (auto cell : cells) {
				sel.selected_members[module->name].insert(cell->name);
				prevsig.append(cellToPrevSig[cell]);
				nextsig.append(cellToNextSig[cell]);
			}

			prevsig.sort_and_unify();
			nextsig.sort_and_unify();
			sig = prevsig.extract(nextsig);

			for (auto &chunk : sig.chunks())
				if (chunk.wire != NULL)
					sel.selected_members[module->name].insert(chunk.wire->name);
		}
	}
};

struct SccPass : public Pass {
	SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    scc [options] [selection]\n");
		log("\n");
		log("This command identifies strongly connected components (aka logic loops) in the\n");
		log("design.\n");
		log("\n");
		log("    -expect <num>\n");
		log("        expect to find exactly <num> SSCs. A different number of SSCs will\n");
		log("        produce an error.\n");
		log("\n");
		log("    -max_depth <num>\n");
		log("        limit to loops not longer than the specified number of cells. This\n");
		log("        can e.g. be useful in identifying small local loops in a module that\n");
		log("        implements one large SCC.\n");
		log("\n");
		log("    -nofeedback\n");
		log("        do not count cells that have their output fed back into one of their\n");
		log("        inputs as single-cell scc.\n");
		log("\n");
		log("    -all_cell_types\n");
		log("        Usually this command only considers internal non-memory cells. With\n");
		log("        this option set, all cells are considered. For unknown cells all ports\n");
		log("        are assumed to be bidirectional 'inout' ports.\n");
		log("\n");
		log("    -set_attr <name> <value>\n");
		log("        set the specified attribute on all cells that are part of a logic\n");
		log("        loop. the special token {} in the value is replaced with a unique\n");
		log("        identifier for the logic loop.\n");
		log("\n");
		log("    -select\n");
		log("        replace the current selection with a selection of all cells and wires\n");
		log("        that are part of a found logic loop\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::map<std::string, std::string> setAttr;
		bool allCellTypes = false;
		bool selectMode = false;
		bool nofeedbackMode = false;
		int maxDepth = -1;
		int expect = -1;

		log_header(design, "Executing SCC pass (detecting logic loops).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
				maxDepth = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-expect" && argidx+1 < args.size()) {
				expect = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-nofeedback") {
				nofeedbackMode = true;
				continue;
			}
			if (args[argidx] == "-all_cell_types") {
				allCellTypes = true;
				continue;
			}
			if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
				setAttr[args[argidx+1]] = args[argidx+2];
				argidx += 2;
				continue;
			}
			if (args[argidx] == "-select") {
				selectMode = true;
				continue;
			}
			break;
		}
		int origSelectPos = design->selection_stack.size() - 1;
		extra_args(args, argidx, design);

		RTLIL::Selection newSelection(false);
		int scc_counter = 0;

		for (auto &mod_it : design->modules_)
			if (design->selected(mod_it.second))
			{
				SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);

				if (!setAttr.empty())
				{
					for (const auto &cells : worker.sccList)
					{
						for (auto attr : setAttr)
						{
							IdString attr_name(RTLIL::escape_id(attr.first));
							string attr_valstr = attr.second;
							string index = stringf("%d", scc_counter);

							for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
								attr_valstr.replace(pos, 2, index);

							Const attr_value(attr_valstr);

							for (auto cell : cells)
								cell->attributes[attr_name] = attr_value;
						}

						scc_counter++;
					}
				}
				else
				{
					scc_counter += GetSize(worker.sccList);
				}

				if (selectMode)
					worker.select(newSelection);
			}

		if (expect >= 0) {
			if (scc_counter == expect)
				log("Found and expected %d SCCs.\n", scc_counter);
			else
				log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
		} else
			log("Found %d SCCs.\n", scc_counter);

		if (selectMode) {
			log_assert(origSelectPos >= 0);
			design->selection_stack[origSelectPos] = newSelection;
			design->selection_stack[origSelectPos].optimize(design);
		}
	}
} SccPass;

PRIVATE_NAMESPACE_END
<commit_msg>scc to use design->selected_modules() which avoids black/white-boxes<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.
 *
 */

// [[CITE]] Tarjan's strongly connected components algorithm
// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010
// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SccWorker
{
	RTLIL::Design *design;
	RTLIL::Module *module;
	SigMap sigmap;
	CellTypes ct;

	std::set<RTLIL::Cell*> workQueue;
	std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
	std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;

	std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
	std::map<RTLIL::Cell*, int> cellDepth;
	std::set<RTLIL::Cell*> cellsOnStack;
	std::vector<RTLIL::Cell*> cellStack;
	int labelCounter;

	std::map<RTLIL::Cell*, int> cell2scc;
	std::vector<std::set<RTLIL::Cell*>> sccList;

	void run(RTLIL::Cell *cell, int depth, int maxDepth)
	{
		log_assert(workQueue.count(cell) > 0);

		workQueue.erase(cell);
		cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
		labelCounter++;

		cellsOnStack.insert(cell);
		cellStack.push_back(cell);

		if (maxDepth >= 0)
			cellDepth[cell] = depth;

		for (auto nextCell : cellToNextCell[cell])
			if (cellLabels.count(nextCell) == 0) {
				run(nextCell, depth+1, maxDepth);
				cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			} else
			if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
					cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			}

		if (cellLabels[cell].first == cellLabels[cell].second)
		{
			if (cellStack.back() == cell)
			{
				cellStack.pop_back();
				cellsOnStack.erase(cell);
			}
			else
			{
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				while (cellsOnStack.count(cell) > 0) {
					RTLIL::Cell *c = cellStack.back();
					cellStack.pop_back();
					cellsOnStack.erase(c);
					log(" %s", RTLIL::id2cstr(c->name));
					cell2scc[c] = sccList.size();
					scc.insert(c);
				}
				sccList.push_back(scc);
				log("\n");
			}
		}
	}

	SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
			design(design), module(module), sigmap(module)
	{
		if (module->processes.size() > 0) {
			log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
			return;
		}

		if (allCellTypes) {
			ct.setup(design);
		} else {
			ct.setup_internals();
			ct.setup_stdcells();
		}

		SigPool selectedSignals;
		SigSet<RTLIL::Cell*> sigToNextCells;

		for (auto &it : module->wires_)
			if (design->selected(module, it.second))
				selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));

		for (auto &it : module->cells_)
		{
			RTLIL::Cell *cell = it.second;

			if (!design->selected(module, cell))
				continue;

			if (!allCellTypes && !ct.cell_known(cell->type))
				continue;

			workQueue.insert(cell);

			RTLIL::SigSpec inputSignals, outputSignals;

			for (auto &conn : cell->connections())
			{
				bool isInput = true, isOutput = true;

				if (ct.cell_known(cell->type)) {
					isInput = ct.cell_input(cell->type, conn.first);
					isOutput = ct.cell_output(cell->type, conn.first);
				}

				RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
				sig.sort_and_unify();

				if (isInput)
					inputSignals.append(sig);
				if (isOutput)
					outputSignals.append(sig);
			}

			inputSignals.sort_and_unify();
			outputSignals.sort_and_unify();

			cellToPrevSig[cell] = inputSignals;
			cellToNextSig[cell] = outputSignals;
			sigToNextCells.insert(inputSignals, cell);
		}

		for (auto cell : workQueue)
		{
			cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);

			if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				log(" %s", RTLIL::id2cstr(cell->name));
				cell2scc[cell] = sccList.size();
				scc.insert(cell);
				sccList.push_back(scc);
				log("\n");
			}
		}

		labelCounter = 0;
		cellLabels.clear();

		while (!workQueue.empty())
		{
			RTLIL::Cell *cell = *workQueue.begin();
			log_assert(cellStack.size() == 0);
			cellDepth.clear();

			run(cell, 0, maxDepth);
		}

		log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
	}

	void select(RTLIL::Selection &sel)
	{
		for (int i = 0; i < int(sccList.size()); i++)
		{
			std::set<RTLIL::Cell*> &cells = sccList[i];
			RTLIL::SigSpec prevsig, nextsig, sig;

			for (auto cell : cells) {
				sel.selected_members[module->name].insert(cell->name);
				prevsig.append(cellToPrevSig[cell]);
				nextsig.append(cellToNextSig[cell]);
			}

			prevsig.sort_and_unify();
			nextsig.sort_and_unify();
			sig = prevsig.extract(nextsig);

			for (auto &chunk : sig.chunks())
				if (chunk.wire != NULL)
					sel.selected_members[module->name].insert(chunk.wire->name);
		}
	}
};

struct SccPass : public Pass {
	SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    scc [options] [selection]\n");
		log("\n");
		log("This command identifies strongly connected components (aka logic loops) in the\n");
		log("design.\n");
		log("\n");
		log("    -expect <num>\n");
		log("        expect to find exactly <num> SSCs. A different number of SSCs will\n");
		log("        produce an error.\n");
		log("\n");
		log("    -max_depth <num>\n");
		log("        limit to loops not longer than the specified number of cells. This\n");
		log("        can e.g. be useful in identifying small local loops in a module that\n");
		log("        implements one large SCC.\n");
		log("\n");
		log("    -nofeedback\n");
		log("        do not count cells that have their output fed back into one of their\n");
		log("        inputs as single-cell scc.\n");
		log("\n");
		log("    -all_cell_types\n");
		log("        Usually this command only considers internal non-memory cells. With\n");
		log("        this option set, all cells are considered. For unknown cells all ports\n");
		log("        are assumed to be bidirectional 'inout' ports.\n");
		log("\n");
		log("    -set_attr <name> <value>\n");
		log("        set the specified attribute on all cells that are part of a logic\n");
		log("        loop. the special token {} in the value is replaced with a unique\n");
		log("        identifier for the logic loop.\n");
		log("\n");
		log("    -select\n");
		log("        replace the current selection with a selection of all cells and wires\n");
		log("        that are part of a found logic loop\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::map<std::string, std::string> setAttr;
		bool allCellTypes = false;
		bool selectMode = false;
		bool nofeedbackMode = false;
		int maxDepth = -1;
		int expect = -1;

		log_header(design, "Executing SCC pass (detecting logic loops).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
				maxDepth = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-expect" && argidx+1 < args.size()) {
				expect = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-nofeedback") {
				nofeedbackMode = true;
				continue;
			}
			if (args[argidx] == "-all_cell_types") {
				allCellTypes = true;
				continue;
			}
			if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
				setAttr[args[argidx+1]] = args[argidx+2];
				argidx += 2;
				continue;
			}
			if (args[argidx] == "-select") {
				selectMode = true;
				continue;
			}
			break;
		}
		int origSelectPos = design->selection_stack.size() - 1;
		extra_args(args, argidx, design);

		RTLIL::Selection newSelection(false);
		int scc_counter = 0;

		for (auto mod : design->selected_modules())
		{
			SccWorker worker(design, mod, nofeedbackMode, allCellTypes, maxDepth);

			if (!setAttr.empty())
			{
				for (const auto &cells : worker.sccList)
				{
					for (auto attr : setAttr)
					{
						IdString attr_name(RTLIL::escape_id(attr.first));
						string attr_valstr = attr.second;
						string index = stringf("%d", scc_counter);

						for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
							attr_valstr.replace(pos, 2, index);

						Const attr_value(attr_valstr);

						for (auto cell : cells)
							cell->attributes[attr_name] = attr_value;
					}

					scc_counter++;
				}
			}
			else
			{
				scc_counter += GetSize(worker.sccList);
			}

			if (selectMode)
				worker.select(newSelection);
		}

		if (expect >= 0) {
			if (scc_counter == expect)
				log("Found and expected %d SCCs.\n", scc_counter);
			else
				log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
		} else
			log("Found %d SCCs.\n", scc_counter);

		if (selectMode) {
			log_assert(origSelectPos >= 0);
			design->selection_stack[origSelectPos] = newSelection;
			design->selection_stack[origSelectPos].optimize(design);
		}
	}
} SccPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/adr32s_workarounds.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file workarounds/adr32s_workarounds.C
/// @brief Workarounds for the ADR32s logic blocks
/// Workarounds are very deivce specific, so there is no attempt to generalize
/// this code in any way.
///
// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>
#include <lib/mss_attribute_accessors.H>

#include <generic/memory/lib/utils/scom.H>
#include <generic/memory/lib/utils/pos.H>
#include <lib/utils/conversions.H>
#include <lib/fir/fir.H>
#include <lib/workarounds/adr32s_workarounds.H>
#include <lib/phy/ddr_phy.H>
#include <lib/phy/dcd.H>
#include <generic/memory/lib/utils/find.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_SYSTEM;
using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{

namespace workarounds
{

namespace adr32s
{

///
/// @brief Clears the FIRs mistakenly set by the DCD calibration
/// @param[in] i_target MCBIST target on which to operate
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
/// @note Always needs to be run for DD1.* parts.  unsure for DD2
///
fapi2::ReturnCode clear_dcd_firs( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target )
{
    FAPI_INF("%s clearing DCD FIRs!", mss::c_str(i_target));

    // Run the fir clear to reset bits that are caused by the DCD calibration
    for( const auto& l_mca : mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target))
    {
        fir::reg<MCA_IOM_PHY0_DDRPHY_FIR_REG> l_mca_fir_reg(l_mca, fapi2::current_err);
        FAPI_TRY(fapi2::current_err, "unable to create fir::reg for %d", MCA_IOM_PHY0_DDRPHY_FIR_REG);

        // Per Steve Wyatt:
        // Bit 55 gets set during the DCD cal in the ADR
        // Bit 56/58 get set during the DCD cal in the DP's
        // Bit 59 is set due to parity errors and must be cleared, per Tim Buccholtz
        // Clearing them all here, as the DCD cal is run on the ADR/DP's in the same code in lib/adr32s.C
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_1>()); // bit 55
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_2>()); // bit 56
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_4>()); // bit 58
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_5>()); // bit 59
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform ADR DCD calibration - Nimbus Only
/// @param[in] i_target the MCBIST (controler) to perform calibration on
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode duty_cycle_distortion_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target )
{
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    const auto l_mca = mss::find_targets<TARGET_TYPE_MCA>(i_target);

    // Skips DCD calibration if we're a DD2 part
    if (!mss::chip_ec_feature_dcd_workaround(i_target))
    {
        FAPI_INF("%s Skipping DCD calibration algorithm due to part revision", mss::c_str(i_target));
        return FAPI2_RC_SUCCESS;
    }

    // Clears the FIRs created by DCD calibration, if needed
    FAPI_TRY(mss::workarounds::adr32s::clear_dcd_firs(i_target));

    // We must calibrate each of our ports. Each has 2 ADR units and each unit needs it's A-side and B-side calibrated.
    for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
    {
        uint64_t l_seed = TT::DD1_DCD_ADJUST_DEFAULT;

        // Sets up the DLL control regs for DCD cal for this port
        FAPI_TRY(mss::dcd::setup_dll_control_regs( p ));

        for (const auto& r : TT::DUTY_CYCLE_DISTORTION_REG)
        {
            FAPI_TRY(mss::dcd::sw_cal_per_register(p, r, l_seed));
        }

        // Restores the DLL control regs for DCD cal for this port
        FAPI_TRY(mss::dcd::restore_dll_control_regs( p ));
    }

    // Clears the FIRs created by DCD calibration, if needed
    FAPI_TRY(mss::workarounds::adr32s::clear_dcd_firs(i_target));

    FAPI_INF("%s Cleared DCD firs", mss::c_str(i_target));

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Retries to clear the cal update bit, as it has been seen that the bit can be "sticky" in hardware
/// @param[in] i_target MCA target on which to operate
/// @param[in] i_reg the register on which to operate
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
fapi2::ReturnCode setup_dll_control_regs( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, const uint64_t i_reg )
{
    // Traits definition
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    // Poll limit declaration - this is an engineering judgement value from the lab's experimentation
    // The bit thus far has always unstuck after 3 loops, so 10 is more than safe
    constexpr uint64_t POLL_LIMIT = 10;
    bool l_done = false;
    fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;

    for(uint64_t i = 0; i < POLL_LIMIT; ++i)
    {
        fapi2::buffer<uint64_t> l_data;

        FAPI_TRY(mss::getScom(i_target, i_reg, l_data), "%s failed to getScom from register 0x%016lx", mss::c_str(i_target),
                 i_reg);

        // If our bit is a 0, then we're done
        l_done = !l_data.getBit<TT::DLL_CAL_UPDATE>();

        // Break out
        if(l_done)
        {
            FAPI_INF("%s DLL control register 0x%016lx is setup correctly after %lu attempts", mss::c_str(i_target), i_reg, i);
            break;
        }

        // Stops cal from updating and disables cal good to keep parity good (these regs have parity issues on bits 60-63)
        l_data.clearBit<TT::DLL_CAL_UPDATE>();
        l_data.clearBit<TT::DLL_CAL_GOOD>();

        FAPI_TRY(mss::putScom(i_target, i_reg, l_data), "%s failed to putScom from register 0x%016lx", mss::c_str(i_target),
                 i_reg);
    }

    // do the error check
    FAPI_ASSERT( l_done,
                 fapi2::MSS_DLL_UPDATE_BIT_STUCK()
                 .set_TARGET(i_target)
                 .set_REGISTER(i_reg),
                 "Failed to setup DLL control reg for %s 0x%016lx", mss::c_str(i_target), i_reg );

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace adr32s
} // close namespace workarounds
} // close namespace mss
<commit_msg>L3 support for ddr_phy_reset, termination_control<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/adr32s_workarounds.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file workarounds/adr32s_workarounds.C
/// @brief Workarounds for the ADR32s logic blocks
/// Workarounds are very deivce specific, so there is no attempt to generalize
/// this code in any way.
///
// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>
#include <lib/mss_attribute_accessors.H>

#include <generic/memory/lib/utils/scom.H>
#include <generic/memory/lib/utils/pos.H>
#include <lib/utils/conversions.H>
#include <lib/fir/fir.H>
#include <lib/workarounds/adr32s_workarounds.H>
#include <lib/phy/ddr_phy.H>
#include <lib/phy/dcd.H>
#include <generic/memory/lib/utils/find.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_SYSTEM;
using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{

namespace workarounds
{

namespace adr32s
{

///
/// @brief Clears the FIRs mistakenly set by the DCD calibration
/// @param[in] i_target MCBIST target on which to operate
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
/// @note Always needs to be run for DD1.* parts.  unsure for DD2
///
fapi2::ReturnCode clear_dcd_firs( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target )
{
    FAPI_INF("%s clearing DCD FIRs!", mss::c_str(i_target));

    // Run the fir clear to reset bits that are caused by the DCD calibration
    for( const auto& l_mca : mss::find_targets<fapi2::TARGET_TYPE_MCA>(i_target))
    {
        fir::reg<MCA_IOM_PHY0_DDRPHY_FIR_REG> l_mca_fir_reg(l_mca, fapi2::current_err);
        FAPI_TRY(fapi2::current_err, "unable to create fir::reg for %d", MCA_IOM_PHY0_DDRPHY_FIR_REG);

        // Per Steve Wyatt:
        // Bit 55 gets set during the DCD cal in the ADR
        // Bit 56/58 get set during the DCD cal in the DP's
        // Bit 59 is set due to parity errors and must be cleared, per Tim Buccholtz
        // Clearing them all here, as the DCD cal is run on the ADR/DP's in the same code in lib/adr32s.C
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_1>()); // bit 55
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_2>()); // bit 56
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_4>()); // bit 58
        FAPI_TRY(l_mca_fir_reg.clear<MCA_IOM_PHY0_DDRPHY_FIR_REG_ERROR_5>()); // bit 59
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform ADR DCD calibration - Nimbus Only
/// @param[in] i_target the MCBIST (controler) to perform calibration on
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode duty_cycle_distortion_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target )
{
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    const auto l_mca = mss::find_targets<TARGET_TYPE_MCA>(i_target);

    // Skips DCD calibration if we're a DD2 part
    if (!mss::chip_ec_feature_dcd_workaround(i_target))
    {
        FAPI_INF("%s Skipping DCD calibration algorithm due to part revision", mss::c_str(i_target));
        return FAPI2_RC_SUCCESS;
    }

    // Clears the FIRs created by DCD calibration, if needed
    FAPI_TRY(mss::workarounds::adr32s::clear_dcd_firs(i_target));

    // We must calibrate each of our ports. Each has 2 ADR units and each unit needs it's A-side and B-side calibrated.
    for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
    {
        uint64_t l_seed = TT::DD1_DCD_ADJUST_DEFAULT;

        // Sets up the DLL control regs for DCD cal for this port
        FAPI_TRY(mss::dcd::setup_dll_control_regs( p ));

        for (const auto& r : TT::DUTY_CYCLE_DISTORTION_REG)
        {
            FAPI_TRY(mss::dcd::sw_cal_per_register(p, r, l_seed));
        }

        // Restores the DLL control regs for DCD cal for this port
        FAPI_TRY(mss::dcd::restore_dll_control_regs( p ));
    }

    // Clears the FIRs created by DCD calibration, if needed
    FAPI_TRY(mss::workarounds::adr32s::clear_dcd_firs(i_target));

    FAPI_INF("%s Cleared DCD firs", mss::c_str(i_target));

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Retries to clear the cal update bit, as it has been seen that the bit can be "sticky" in hardware
/// @param[in] i_target MCA target on which to operate
/// @param[in] i_reg the register on which to operate
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
fapi2::ReturnCode setup_dll_control_regs( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target, const uint64_t i_reg )
{
    // Traits definition
    typedef dutyCycleDistortionTraits<TARGET_TYPE_MCA> TT;

    // Poll limit declaration - this is an engineering judgement value from the lab's experimentation
    // The bit thus far has always unstuck after 3 loops, so 10 is more than safe
    constexpr uint64_t POLL_LIMIT = 10;
    bool l_done = false;
    fapi2::current_err = fapi2::FAPI2_RC_SUCCESS;

    for(uint64_t i = 0; i < POLL_LIMIT; ++i)
    {
        fapi2::buffer<uint64_t> l_data;

        FAPI_TRY(mss::getScom(i_target, i_reg, l_data), "%s failed to getScom from register 0x%016lx", mss::c_str(i_target),
                 i_reg);

        // If our bit is a 0, then we're done
        l_done = !l_data.getBit<TT::DLL_CAL_UPDATE>();

        // Break out
        if(l_done)
        {
            FAPI_INF("%s DLL control register 0x%016lx is setup correctly after %lu attempts", mss::c_str(i_target), i_reg, i);
            break;
        }

        // Stops cal from updating and disables cal good to keep parity good (these regs have parity issues on bits 60-63)
        l_data.clearBit<TT::DLL_CAL_UPDATE>();
        l_data.clearBit<TT::DLL_CAL_GOOD>();

        FAPI_TRY(mss::putScom(i_target, i_reg, l_data), "%s failed to putScom from register 0x%016lx", mss::c_str(i_target),
                 i_reg);
    }

    // do the error check
    FAPI_ASSERT( l_done,
                 fapi2::MSS_DLL_UPDATE_BIT_STUCK()
                 .set_MCA_TARGET(i_target)
                 .set_REGISTER(i_reg),
                 "Failed to setup DLL control reg for %s 0x%016lx", mss::c_str(i_target), i_reg );

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace adr32s
} // close namespace workarounds
} // close namespace mss
<|endoftext|>