<commit_before>#include "Variant.h"
#include "split.h"
#include "cdflib.hpp"
#include "pdflib.hpp"

#include <string>
#include <iostream>
#include <math.h>
#include <cmath>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <getopt.h>

using namespace std;
using namespace vcf;

struct pop{

  double nalt ;
  double nref ;
  double af   ;
  double nhomr;
  double nhoma;
  double nhet ;
  double ngeno;
  double fis  ;

  vector<int>    geno_index ;
  vector< vector< double > > unphred_p;

};

double unphred(string phred){

  double unphred = atof(phred.c_str());
  unphred = unphred / -10;
  return unphred;

}

void initPop(pop & population){
  population.nalt  = 0;
  population.nref  = 0;
  population.af    = 0;
  population.nhomr = 0;
  population.nhoma = 0;
  population.nhet  = 0;
  population.ngeno = 0;
  population.fis   = 0;

}

void loadPop( vector< map< string, vector<string> > >& group, pop & population){

  vector< map< string, vector<string> > >::iterator targ_it = group.begin();

  for(; targ_it != group.end(); targ_it++){

    population.ngeno += 1;

    string genotype = (*targ_it)["GT"].front();

    vector<double> phreds;

	phreds.push_back( unphred((*targ_it)["PL"][0]));
	phreds.push_back( unphred((*targ_it)["PL"][1]));
	phreds.push_back( unphred((*targ_it)["PL"][2]));

	population.unphred_p.push_back(phreds);

	while(1){
	  if(genotype == "0/0"){
	    population.nhomr += 1;
	    population.nref  += 2;
	    population.geno_index.push_back(0);
	    break;
	  }
	  if(genotype == "0/1"){
	    population.nhet  += 1;
	    population.nref  += 1;
	    population.nalt  += 1;
	    population.geno_index.push_back(1);
	    break;
	  }
	  if(genotype == "1/1"){
	    population.nhoma += 1;
	    population.nalt  += 2;
	    population.geno_index.push_back(2);
	    break;
	  }
	  if(genotype == "0|0"){
	    population.nhomr += 1;
	    population.nref  += 2;
	    population.geno_index.push_back(0);
	    break;
	  }
	  if(genotype == "0|1"){
	    population.nhet  += 1;
	    population.nref  += 1;
	    population.nalt  += 1;
	    population.geno_index.push_back(1);
	    break;
	  }
	  if(genotype == "1|1"){
	    population.nhoma += 1;
	    population.nalt  += 2;
	    population.geno_index.push_back(2);
	    break;
	  }
	  cerr << "FATAL: unknown genotype" << endl;
	  exit(1);
	}
  }

  if(population.nalt == 0 && population.nref == 0){
    population.af = -1;
  }
  else{

    population.af  = (population.nalt / (population.nref + population.nalt));

    if(population.nhet > 0){
      population.fis = ( 1 - ((population.nhet/population.ngeno) / (2*population.af*(1 - population.af))));
    }
    else{
      population.fis = 1;
    }
    if(population.fis < 0){
      population.fis = 0.00001;
    }
  }
}

double bound(double v){
  if(v <= 0.00001){
    return  0.00001;
  }
  if(v >= 0.99999){
    return 0.99999;
  }
  return v;
}

void loadIndices(map<int, int> & index, string set){

  vector<string>  indviduals = split(set, ",");

  vector<string>::iterator it = indviduals.begin();

  for(; it != indviduals.end(); it++){
    index[ atoi( (*it).c_str() ) ] = 1;
  }
}

void getPosterior(pop & population, double *alpha, double *beta){

  int ng = population.geno_index.size();

  for(int i = 0 ; i < ng; i++){

    double aa = population.unphred_p[i][0] ;
    double ab = population.unphred_p[i][1] ;
    double bb = population.unphred_p[i][2] ;

    double norm = log(exp(aa) + exp(ab) + exp(bb));

    int gi = population.geno_index[i];

    (*alpha) += exp(ab - norm);
    (*beta ) += exp(ab - norm);

    (*alpha) += 2 * exp(aa - norm);
    (*beta ) += 2 * exp(bb - norm);

  }
}

int main(int argc, char** argv) {

  // set the random seed for MCMC

  srand((unsigned)time(NULL));

  // the filename

  string filename = "NA";

  // set region to scaffold

  string region = "NA";

  // using vcflib; thanks to Erik Garrison

  VariantCallFile variantFile;

  // zero based index for the target and background indivudals

  map<int, int> it, ib;

  // deltaaf is the difference of allele frequency we bother to look at

  string deltaaf ;
  double daf  = 0;

  //

  int counts = 0;

    const struct option longopts[] =
      {
	{"version"   , 0, 0, 'v'},
	{"help"      , 0, 0, 'h'},
	{"counts"    , 0, 0, 'c'},
        {"file"      , 1, 0, 'f'},
	{"target"    , 1, 0, 't'},
	{"background", 1, 0, 'b'},
	{"deltaaf"   , 1, 0, 'd'},
	{"region"    , 1, 0, 'r'},
	{0,0,0,0}
      };

    int index;
    int iarg=0;

    while(iarg != -1)
      {
	iarg = getopt_long(argc, argv, "r:d:t:b:f:chv", longopts, &index);

	switch (iarg)
	  {
	  case 'h':
	    cerr << endl << endl;
	    cerr << "INFO: help" << endl;
	    cerr << "INFO: description:" << endl;
            cerr << "     pFst is a probabilistic approach for detecting differences in allele frequencies between      " << endl;
	    cerr << "     a target and background.  pFst uses the conjugated form of the beta-binomial distributions to estimate         " << endl;
	    cerr << "     the posterior distribution for the background's allele frequency.  pFst calculates the probability of observing	" << endl;
	    cerr << "     the target's allele frequency given the posterior distribution of the background. By default	" << endl;
	    cerr << "     pFst uses the genotype likelihoods to estimate alpha, beta and the allele frequency of the target group.  If you would like to assume	" << endl;
	    cerr << "     all genotypes are correct set the count flag equal to one.                                    " << endl << endl;

	    cerr << "Output : 3 columns :     "    << endl;
	    cerr << "     1. seqid            "    << endl;
	    cerr << "     2. position         "    << endl;
	    cerr << "     3. pFst probability "    << endl  << endl;

	    cerr << "INFO: usage:  pFst --target 0,1,2,3,4,5,6,7 --background 11,12,13,16,17,19,22 --file my.vcf --deltaaf 0.1" << endl;
	    cerr << endl;
	    cerr << "INFO: required: t,target     -- a zero bases comma seperated list of target individuals corrisponding to VCF columns" << endl;
	    cerr << "INFO: required: b,background -- a zero bases comma seperated list of target individuals corrisponding to VCF columns" << endl;
	    cerr << "INFO: required: f,file a     -- proper formatted VCF.  the FORMAT field MUST contain \"PL\"" << endl;
	    cerr << "INFO: optional: d,deltaaf    -- skip sites were the difference in allele frequency is less than deltaaf, default is zero"      << endl;
	    cerr << "INFO: optional: c,counts     -- use genotype counts rather than genotype likelihoods to estimate parameters, default false"  << endl;
	    cerr << endl;
	    cerr << "INFO: version 1.0.0 ; date: April 2014 ; author: Zev Kronenberg; email : zev.kronenberg@utah.edu " << endl;
	    cerr << endl << endl;
	    return 0;
	  case 'v':
	    cerr << endl << endl;
	    cerr << "INFO: version 1.0.0 ; date: April 2014 ; author: Zev Kronenberg; email : zev.kronenberg@utah.edu "  << endl;
	    return 0;
	  case 'c':
	    cerr << "INFO: using genotype counts rather than gentoype likelihoods" << endl;
	    counts = 1;
	    break;
	  case 't':
	    loadIndices(ib, optarg);
	    cerr << "INFO: There are " << ib.size() << " individuals in the target" << endl;
	    cerr << "INFO: target ids: " << optarg << endl;
	    break;
	  case 'b':
	    loadIndices(it, optarg);
	    cerr << "INFO: There are " << it.size() << " individuals in the background" << endl;
	    cerr << "INFO: background ids: " << optarg << endl;
	    break;
	  case 'f':
	    cerr << "INFO: File: " << optarg  <<  endl;
	    filename = optarg;
	    break;
	  case 'd':
	    cerr << "INFO: only scoring sites where the allele frequency difference is greater than: " << optarg << endl;
	    deltaaf = optarg;
	    daf = atof(deltaaf.c_str());
	    break;
	  case 'r':
            cerr << "INFO: set seqid region to : " << optarg << endl;
	    region = optarg;
	    break;
	  default:
	    break;
	  }

      }

    variantFile.open(filename);

    if(region != "NA"){
      variantFile.setRegion(region);
    }

    if (!variantFile.is_open()) {
        return 1;
    }

    Variant var(variantFile);

    while (variantFile.getNextVariant(var)) {
        map<string, map<string, vector<string> > >::iterator s     = var.samples.begin();
        map<string, map<string, vector<string> > >::iterator sEnd  = var.samples.end();

	// biallelic sites naturally

	if(var.alt.size() > 1){
	  continue;
	}

	vector < map< string, vector<string> > > target, background, total;

	int index = 0;

        for (; s != sEnd; ++s) {

            map<string, vector<string> >& sample = s->second;

	    if(sample["GT"].front() != "./."){
	      if(it.find(index) != it.end() ){
		target.push_back(sample);
		total.push_back(sample);

	      }
	      if(ib.find(index) != ib.end()){
		background.push_back(sample);
		total.push_back(sample);
	      }
	    }

	index += 1;
	}

	if(target.size() < 5 || background.size() < 5 ){
	  continue;
	}

	pop popt, popb, popTotal;

	initPop(popt);
	initPop(popb);
	initPop(popTotal);

	loadPop(target,     popt);
	loadPop(background, popb);
	loadPop(total,  popTotal);

	if(popt.af == -1 || popb.af == -1){
	  continue;
	}
	if(popt.af == 1  && popb.af == 1){
	  continue;
	}
	if(popt.af == 0 && popb.af  == 0){
	  continue;
	}

	double afdiff = abs(popt.af - popb.af);

	if(afdiff < daf){
	  continue;
	}

	double alphaT = 0.01;
	double alphaB = 0.01;
	double betaT  = 0.01;
	double betaB  = 0.01;

	if(counts == 1){
	  alphaT += popt.nref ;
	  alphaB += popb.nref ;
	  betaT  += popt.nalt ;
	  betaB  += popb.nalt ;
	}
	else{
	  getPosterior(popt, &alphaT, &betaT);
	  getPosterior(popb, &alphaB, &betaB);
	}

	double targm = alphaT / ( alphaT + betaT );
        double backm = alphaB / ( alphaB + betaB );

	double xa = targm - 0.001;
	double xb = targm + 0.001;
	if(xa <= 0){
	  xa = 0;
	  xb = 0.002;
	}
	if(xb >= 1){
	  xa = 0.998;
	  xb = 1;
	}

	double dph = r8_beta_pdf(alphaB, betaB, xa);
	double dpl = r8_beta_pdf(alphaB, betaB, xb);

	double p   = ((dph + dpl)/2) *  0.01;

	cout << var.sequenceName << "\t"  << var.position << "\t" << p << endl ;

    }
    return 0;
}
<commit_msg>docs docs docs<commit_after>#include "Variant.h"
#include "split.h"
#include "cdflib.hpp"
#include "pdflib.hpp"

#include <string>
#include <iostream>
#include <math.h>
#include <cmath>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <getopt.h>

using namespace std;
using namespace vcf;

struct pop{

  double nalt ;
  double nref ;
  double af   ;
  double nhomr;
  double nhoma;
  double nhet ;
  double ngeno;
  double fis  ;

  vector<int>    geno_index ;
  vector< vector< double > > unphred_p;

};

double unphred(string phred){

  double unphred = atof(phred.c_str());
  unphred = unphred / -10;
  return unphred;

}

void initPop(pop & population){
  population.nalt  = 0;
  population.nref  = 0;
  population.af    = 0;
  population.nhomr = 0;
  population.nhoma = 0;
  population.nhet  = 0;
  population.ngeno = 0;
  population.fis   = 0;

}

void loadPop( vector< map< string, vector<string> > >& group, pop & population){

  vector< map< string, vector<string> > >::iterator targ_it = group.begin();

  for(; targ_it != group.end(); targ_it++){

    population.ngeno += 1;

    string genotype = (*targ_it)["GT"].front();

    vector<double> phreds;

	phreds.push_back( unphred((*targ_it)["PL"][0]));
	phreds.push_back( unphred((*targ_it)["PL"][1]));
	phreds.push_back( unphred((*targ_it)["PL"][2]));

	population.unphred_p.push_back(phreds);

	while(1){
	  if(genotype == "0/0"){
	    population.nhomr += 1;
	    population.nref  += 2;
	    population.geno_index.push_back(0);
	    break;
	  }
	  if(genotype == "0/1"){
	    population.nhet  += 1;
	    population.nref  += 1;
	    population.nalt  += 1;
	    population.geno_index.push_back(1);
	    break;
	  }
	  if(genotype == "1/1"){
	    population.nhoma += 1;
	    population.nalt  += 2;
	    population.geno_index.push_back(2);
	    break;
	  }
	  if(genotype == "0|0"){
	    population.nhomr += 1;
	    population.nref  += 2;
	    population.geno_index.push_back(0);
	    break;
	  }
	  if(genotype == "0|1"){
	    population.nhet  += 1;
	    population.nref  += 1;
	    population.nalt  += 1;
	    population.geno_index.push_back(1);
	    break;
	  }
	  if(genotype == "1|1"){
	    population.nhoma += 1;
	    population.nalt  += 2;
	    population.geno_index.push_back(2);
	    break;
	  }
	  cerr << "FATAL: unknown genotype" << endl;
	  exit(1);
	}
  }

  if(population.nalt == 0 && population.nref == 0){
    population.af = -1;
  }
  else{

    population.af  = (population.nalt / (population.nref + population.nalt));

    if(population.nhet > 0){
      population.fis = ( 1 - ((population.nhet/population.ngeno) / (2*population.af*(1 - population.af))));
    }
    else{
      population.fis = 1;
    }
    if(population.fis < 0){
      population.fis = 0.00001;
    }
  }
}

double bound(double v){
  if(v <= 0.00001){
    return  0.00001;
  }
  if(v >= 0.99999){
    return 0.99999;
  }
  return v;
}

void loadIndices(map<int, int> & index, string set){

  vector<string>  indviduals = split(set, ",");

  vector<string>::iterator it = indviduals.begin();

  for(; it != indviduals.end(); it++){
    index[ atoi( (*it).c_str() ) ] = 1;
  }
}

void getPosterior(pop & population, double *alpha, double *beta){

  int ng = population.geno_index.size();

  for(int i = 0 ; i < ng; i++){

    double aa = population.unphred_p[i][0] ;
    double ab = population.unphred_p[i][1] ;
    double bb = population.unphred_p[i][2] ;

    double norm = log(exp(aa) + exp(ab) + exp(bb));

    int gi = population.geno_index[i];

    (*alpha) += exp(ab - norm);
    (*beta ) += exp(ab - norm);

    (*alpha) += 2 * exp(aa - norm);
    (*beta ) += 2 * exp(bb - norm);

  }
}

int main(int argc, char** argv) {

  // set the random seed for MCMC

  srand((unsigned)time(NULL));

  // the filename

  string filename = "NA";

  // set region to scaffold

  string region = "NA";

  // using vcflib; thanks to Erik Garrison

  VariantCallFile variantFile;

  // zero based index for the target and background indivudals

  map<int, int> it, ib;

  // deltaaf is the difference of allele frequency we bother to look at

  string deltaaf ;
  double daf  = 0;

  //

  int counts = 0;

    const struct option longopts[] =
      {
	{"version"   , 0, 0, 'v'},
	{"help"      , 0, 0, 'h'},
	{"counts"    , 0, 0, 'c'},
        {"file"      , 1, 0, 'f'},
	{"target"    , 1, 0, 't'},
	{"background", 1, 0, 'b'},
	{"deltaaf"   , 1, 0, 'd'},
	{"region"    , 1, 0, 'r'},
	{0,0,0,0}
      };

    int index;
    int iarg=0;

    while(iarg != -1)
      {
	iarg = getopt_long(argc, argv, "r:d:t:b:f:chv", longopts, &index);

	switch (iarg)
	  {
	  case 'h':
	    cerr << endl << endl;
	    cerr << "INFO: help" << endl;
	    cerr << "INFO: description:" << endl;
            cerr << "     pFst is a probabilistic approach for detecting differences in allele frequencies between two populations,           " << endl;
	    cerr << "     a target and background.  pFst uses the conjugated form of the beta-binomial distributions to estimate              " << endl;
	    cerr << "     the posterior distribution for the background's allele frequency.  pFst calculates the probability of observing     " << endl;
	    cerr << "     the target's allele frequency given the posterior distribution of the background. By default	" << endl;
	    cerr << "     pFst uses the genotype likelihoods to estimate alpha, beta and the allele frequency of the target group.  If you would like to assume	" << endl;
	    cerr << "     all genotypes are correct set the count flag equal to one.                                    " << endl << endl;

	    cerr << "Output : 3 columns :     "    << endl;
	    cerr << "     1. seqid            "    << endl;
	    cerr << "     2. position         "    << endl;
	    cerr << "     3. pFst probability "    << endl  << endl;

	    cerr << "INFO: usage:  pFst --target 0,1,2,3,4,5,6,7 --background 11,12,13,16,17,19,22 --file my.vcf --deltaaf 0.1" << endl;
	    cerr << endl;
	    cerr << "INFO: required: t,target     -- a zero bases comma seperated list of target individuals corrisponding to VCF columns" << endl;
	    cerr << "INFO: required: b,background -- a zero bases comma seperated list of background individuals corrisponding to VCF columns" << endl;
	    cerr << "INFO: required: f,file a     -- proper formatted VCF.  the FORMAT field MUST contain \"PL\"" << endl;
	    cerr << "INFO: optional: d,deltaaf    -- skip sites where the difference in allele frequencies is less than deltaaf, default is zero"      << endl;
	    cerr << "INFO: optional: c,counts     -- use genotype counts rather than genotype likelihoods to estimate parameters, default false"  << endl;
	    cerr << endl;
	    cerr << "INFO: version 1.0.0 ; date: April 2014 ; author: Zev Kronenberg; email : zev.kronenberg@utah.edu " << endl;
	    cerr << endl << endl;
	    return 0;
	  case 'v':
	    cerr << endl << endl;
	    cerr << "INFO: version 1.0.0 ; date: April 2014 ; author: Zev Kronenberg; email : zev.kronenberg@utah.edu "  << endl;
	    return 0;
	  case 'c':
	    cerr << "INFO: using genotype counts rather than gentoype likelihoods" << endl;
	    counts = 1;
	    break;
	  case 't':
	    loadIndices(ib, optarg);
	    cerr << "INFO: There are " << ib.size() << " individuals in the target" << endl;
	    cerr << "INFO: target ids: " << optarg << endl;
	    break;
	  case 'b':
	    loadIndices(it, optarg);
	    cerr << "INFO: There are " << it.size() << " individuals in the background" << endl;
	    cerr << "INFO: background ids: " << optarg << endl;
	    break;
	  case 'f':
	    cerr << "INFO: File: " << optarg  <<  endl;
	    filename = optarg;
	    break;
	  case 'd':
	    cerr << "INFO: only scoring sites where the allele frequency difference is greater than: " << optarg << endl;
	    deltaaf = optarg;
	    daf = atof(deltaaf.c_str());
	    break;
	  case 'r':
            cerr << "INFO: set seqid region to : " << optarg << endl;
	    region = optarg;
	    break;
	  default:
	    break;
	  }

      }

    variantFile.open(filename);

    if(region != "NA"){
      variantFile.setRegion(region);
    }

    if (!variantFile.is_open()) {
        return 1;
    }

    Variant var(variantFile);

    while (variantFile.getNextVariant(var)) {
        map<string, map<string, vector<string> > >::iterator s     = var.samples.begin();
        map<string, map<string, vector<string> > >::iterator sEnd  = var.samples.end();

	// biallelic sites naturally

	if(var.alt.size() > 1){
	  continue;
	}

	vector < map< string, vector<string> > > target, background, total;

	int index = 0;

        for (; s != sEnd; ++s) {

            map<string, vector<string> >& sample = s->second;

	    if(sample["GT"].front() != "./."){
	      if(it.find(index) != it.end() ){
		target.push_back(sample);
		total.push_back(sample);

	      }
	      if(ib.find(index) != ib.end()){
		background.push_back(sample);
		total.push_back(sample);
	      }
	    }

	index += 1;
	}

	if(target.size() < 5 || background.size() < 5 ){
	  continue;
	}

	pop popt, popb, popTotal;

	initPop(popt);
	initPop(popb);
	initPop(popTotal);

	loadPop(target,     popt);
	loadPop(background, popb);
	loadPop(total,  popTotal);

	if(popt.af == -1 || popb.af == -1){
	  continue;
	}
	if(popt.af == 1  && popb.af == 1){
	  continue;
	}
	if(popt.af == 0 && popb.af  == 0){
	  continue;
	}

	double afdiff = abs(popt.af - popb.af);

	if(afdiff < daf){
	  continue;
	}

	double alphaT = 0.01;
	double alphaB = 0.01;
	double betaT  = 0.01;
	double betaB  = 0.01;

	if(counts == 1){
	  alphaT += popt.nref ;
	  alphaB += popb.nref ;
	  betaT  += popt.nalt ;
	  betaB  += popb.nalt ;
	}
	else{
	  getPosterior(popt, &alphaT, &betaT);
	  getPosterior(popb, &alphaB, &betaB);
	}

	double targm = alphaT / ( alphaT + betaT );
        double backm = alphaB / ( alphaB + betaB );

	double xa = targm - 0.001;
	double xb = targm + 0.001;
	if(xa <= 0){
	  xa = 0;
	  xb = 0.002;
	}
	if(xb >= 1){
	  xa = 0.998;
	  xb = 1;
	}

	double dph = r8_beta_pdf(alphaB, betaB, xa);
	double dpl = r8_beta_pdf(alphaB, betaB, xb);

	double p   = ((dph + dpl)/2) *  0.01;

	cout << var.sequenceName << "\t"  << var.position << "\t" << p << endl ;

    }
    return 0;
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.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 sync.C
/// @brief Synchronous function implementations
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP
#include  <vector>
#include <map>

#include <fapi2.H>
#include <mss.H>
#include <freq/sync.H>
#include <lib/utils/find.H>

using fapi2::TARGET_TYPE_DIMM;
using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_SYSTEM;

namespace mss
{

///
/// @brief Retrieves a mapping of MSS frequency values per mcbist target
/// @param[in] i_targets vector of controller targets
/// @param[out] o_freq_map dimm speed map <key, value> = (mcbist target, frequency)
/// @param[out] o_is_speed_equal true if all map dimm speeds are the same
/// @return FAPI2_RC_SUCCESS iff successful
///
fapi2::ReturnCode dimm_speed_map(const std::vector< fapi2::Target<TARGET_TYPE_MCBIST> >& i_targets,
                                 std::map< fapi2::Target<TARGET_TYPE_MCBIST>, uint64_t >& o_freq_map,
                                 speed_equality& o_is_speed_equal)
{
    FAPI_INF("---- In dimm_speed_pairs ----");

    if(i_targets.empty())
    {
        FAPI_ERR("Empty target vector found when constructing dimm speed mapping!");
        return fapi2::FAPI2_RC_INVALID_PARAMETER;
    }

    // Getting a sample freq value from an arbitrary target (first one)
    // to compare against all other target freq values
    uint64_t l_comparator = 0;
    FAPI_TRY( mss::freq(i_targets[0], l_comparator), "Failed accessor to mss_freq" );

    o_is_speed_equal = speed_equality::EQUAL_DIMM_SPEEDS;

    // Loop through all MCSBISTs and store dimm speeds
    for (const auto& l_mcbist : i_targets)
    {
        uint64_t l_dimm_speed = 0;
        FAPI_TRY( mss::freq(l_mcbist, l_dimm_speed), "Failed accessor to mss_freq" );

        if(l_comparator != l_dimm_speed)
        {
            o_is_speed_equal = speed_equality::NOT_EQUAL_DIMM_SPEEDS;
        }

        FAPI_INF("%s: Dimm speed %d MT/s", c_str(l_mcbist), l_dimm_speed);
        o_freq_map.emplace( std::make_pair(l_mcbist, l_dimm_speed) );
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Deconfigures MCS targets connected to MCBIST
/// @param[in] i_target the controller target
/// @param[in] i_dimm_speed dimm speed in MT/s
/// @param[in] i_nest_freq nest freq in MHz
/// @return true if hardware was deconfigured
///
bool deconfigure(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
                 const uint64_t i_dimm_speed,
                 const uint32_t i_nest_freq)
{
    FAPI_INF("---- In deconfigure ----");
    bool l_is_hw_deconfigured = false;

    // TODO - RTC 155347 fix dimm speed & nest comparison if needed
    if(i_dimm_speed != i_nest_freq)
    {
        // Deconfigure MCSes
        for( const auto& l_mcs : mss::find_targets<TARGET_TYPE_MCS>(i_target) )
        {
            l_is_hw_deconfigured = true;

            PLAT_FAPI_ASSERT_NOEXIT(false,
                                    fapi2::MSS_FREQ_NOT_EQUAL_NEST_FREQ()
                                    .set_MSS_FREQ(i_dimm_speed)
                                    .set_NEST_FREQ(i_nest_freq)
                                    .set_MCS_TARGET(l_mcs),
                                    "Deconfiguring %s",
                                    mss::c_str(l_mcs) );
        }// end for
    }// end if

    return l_is_hw_deconfigured;
}

///
/// @brief Selects synchronous mode and performs requirements enforced by ATTR_REQUIRED_SYNCH_MODE
/// @param[in] i_freq_map dimm speed mapping
/// @param[in] i_equal_dimm_speed tracks whether map has equal dimm speeds
/// @param[in] i_nest_freq nest frequency
/// @param[in] i_required_sync_mode system policy to enforce synchronous mode
/// @param[out] o_selected_sync_mode final synchronous mode
/// @return FAPI2_RC_SUCCESS iff successful
///
fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target<TARGET_TYPE_MCBIST>, uint64_t >& i_freq_map,
                                   const speed_equality i_equal_dimm_speed,
                                   const uint32_t i_nest_freq,
                                   const uint8_t i_required_sync_mode,
                                   sync_mode& o_selected_sync_mode)
{
    FAPI_INF("---- In select_sync_mode ----");

    // Implementing frequency handling discussion:
    // https://w3-connections.ibm.com/forums/html/topic?id=1222318f-5992-4342-a858-b75594df1be3&ps=
    // Summary: We will always use async mode if we don't see a perfect match of dimm frequencies that match the nest
    switch(i_equal_dimm_speed)
    {
        case speed_equality::EQUAL_DIMM_SPEEDS:

            // Do not run synchronously, even if the frequencies match
            if (i_required_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_NEVER)
            {
                o_selected_sync_mode = sync_mode::MC_NOT_IN_SYNC;
                break;
            }

            // Run synchronously if the dimm and nest freq matches
            // Implicitly covers case when ATTR_REQUIRED_SYNCH_MODE is
            // ALWAYS and UNDETERMINED
            if( i_freq_map.begin()->second  == i_nest_freq)
            {
                o_selected_sync_mode = sync_mode::MC_IN_SYNC;
            }
            else
            {
                o_selected_sync_mode =  sync_mode::MC_NOT_IN_SYNC;
            }

            break;

        case speed_equality::NOT_EQUAL_DIMM_SPEEDS:

            // Require matching frequencies and deconfigure memory that does not match the nest
            if( i_required_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS )
            {
                for(const auto& l_it : i_freq_map)
                {
                    // This can be refactored to return info people might
                    // need.  Until then this returns true if hw was deconfigured
                    // FFDC prints out location
                    deconfigure(l_it.first, l_it.second, i_nest_freq);

                }// end for
            }// end if

            // Implicitly covers case when ATTR_REQUIRED_SYNCH_MODE is
            // NEVER, ALWAYS, and UNDETERMINED
            o_selected_sync_mode = sync_mode::MC_NOT_IN_SYNC;

            break;

        default:
            FAPI_ERR("Invalid speed_equality parameter!");
            return fapi2::FAPI2_RC_INVALID_PARAMETER;
            break;
    }// end switch

    return fapi2::FAPI2_RC_SUCCESS;
}

}// mss
<commit_msg>Change mss build to account for double free in wrappers<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/freq/sync.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 sync.C
/// @brief Synchronous function implementations
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP
#include  <vector>
#include <map>

#include <fapi2.H>
#include <mss.H>
#include <lib/freq/sync.H>
#include <lib/utils/find.H>

using fapi2::TARGET_TYPE_DIMM;
using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_SYSTEM;

namespace mss
{

///
/// @brief Retrieves a mapping of MSS frequency values per mcbist target
/// @param[in] i_targets vector of controller targets
/// @param[out] o_freq_map dimm speed map <key, value> = (mcbist target, frequency)
/// @param[out] o_is_speed_equal true if all map dimm speeds are the same
/// @return FAPI2_RC_SUCCESS iff successful
///
fapi2::ReturnCode dimm_speed_map(const std::vector< fapi2::Target<TARGET_TYPE_MCBIST> >& i_targets,
                                 std::map< fapi2::Target<TARGET_TYPE_MCBIST>, uint64_t >& o_freq_map,
                                 speed_equality& o_is_speed_equal)
{
    FAPI_INF("---- In dimm_speed_pairs ----");

    if(i_targets.empty())
    {
        FAPI_ERR("Empty target vector found when constructing dimm speed mapping!");
        return fapi2::FAPI2_RC_INVALID_PARAMETER;
    }

    // Getting a sample freq value from an arbitrary target (first one)
    // to compare against all other target freq values
    uint64_t l_comparator = 0;
    FAPI_TRY( mss::freq(i_targets[0], l_comparator), "Failed accessor to mss_freq" );

    o_is_speed_equal = speed_equality::EQUAL_DIMM_SPEEDS;

    // Loop through all MCSBISTs and store dimm speeds
    for (const auto& l_mcbist : i_targets)
    {
        uint64_t l_dimm_speed = 0;
        FAPI_TRY( mss::freq(l_mcbist, l_dimm_speed), "Failed accessor to mss_freq" );

        if(l_comparator != l_dimm_speed)
        {
            o_is_speed_equal = speed_equality::NOT_EQUAL_DIMM_SPEEDS;
        }

        FAPI_INF("%s: Dimm speed %d MT/s", c_str(l_mcbist), l_dimm_speed);
        o_freq_map.emplace( std::make_pair(l_mcbist, l_dimm_speed) );
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Deconfigures MCS targets connected to MCBIST
/// @param[in] i_target the controller target
/// @param[in] i_dimm_speed dimm speed in MT/s
/// @param[in] i_nest_freq nest freq in MHz
/// @return true if hardware was deconfigured
///
bool deconfigure(const fapi2::Target<TARGET_TYPE_MCBIST>& i_target,
                 const uint64_t i_dimm_speed,
                 const uint32_t i_nest_freq)
{
    FAPI_INF("---- In deconfigure ----");
    bool l_is_hw_deconfigured = false;

    // TODO - RTC 155347 fix dimm speed & nest comparison if needed
    if(i_dimm_speed != i_nest_freq)
    {
        // Deconfigure MCSes
        for( const auto& l_mcs : mss::find_targets<TARGET_TYPE_MCS>(i_target) )
        {
            l_is_hw_deconfigured = true;

            PLAT_FAPI_ASSERT_NOEXIT(false,
                                    fapi2::MSS_FREQ_NOT_EQUAL_NEST_FREQ()
                                    .set_MSS_FREQ(i_dimm_speed)
                                    .set_NEST_FREQ(i_nest_freq)
                                    .set_MCS_TARGET(l_mcs),
                                    "Deconfiguring %s",
                                    mss::c_str(l_mcs) );
        }// end for
    }// end if

    return l_is_hw_deconfigured;
}

///
/// @brief Selects synchronous mode and performs requirements enforced by ATTR_REQUIRED_SYNCH_MODE
/// @param[in] i_freq_map dimm speed mapping
/// @param[in] i_equal_dimm_speed tracks whether map has equal dimm speeds
/// @param[in] i_nest_freq nest frequency
/// @param[in] i_required_sync_mode system policy to enforce synchronous mode
/// @param[out] o_selected_sync_mode final synchronous mode
/// @return FAPI2_RC_SUCCESS iff successful
///
fapi2::ReturnCode select_sync_mode(const std::map< fapi2::Target<TARGET_TYPE_MCBIST>, uint64_t >& i_freq_map,
                                   const speed_equality i_equal_dimm_speed,
                                   const uint32_t i_nest_freq,
                                   const uint8_t i_required_sync_mode,
                                   sync_mode& o_selected_sync_mode)
{
    FAPI_INF("---- In select_sync_mode ----");

    // Implementing frequency handling discussion:
    // https://w3-connections.ibm.com/forums/html/topic?id=1222318f-5992-4342-a858-b75594df1be3&ps=
    // Summary: We will always use async mode if we don't see a perfect match of dimm frequencies that match the nest
    switch(i_equal_dimm_speed)
    {
        case speed_equality::EQUAL_DIMM_SPEEDS:

            // Do not run synchronously, even if the frequencies match
            if (i_required_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_NEVER)
            {
                o_selected_sync_mode = sync_mode::MC_NOT_IN_SYNC;
                break;
            }

            // Run synchronously if the dimm and nest freq matches
            // Implicitly covers case when ATTR_REQUIRED_SYNCH_MODE is
            // ALWAYS and UNDETERMINED
            if( i_freq_map.begin()->second  == i_nest_freq)
            {
                o_selected_sync_mode = sync_mode::MC_IN_SYNC;
            }
            else
            {
                o_selected_sync_mode =  sync_mode::MC_NOT_IN_SYNC;
            }

            break;

        case speed_equality::NOT_EQUAL_DIMM_SPEEDS:

            // Require matching frequencies and deconfigure memory that does not match the nest
            if( i_required_sync_mode == fapi2::ENUM_ATTR_REQUIRED_SYNCH_MODE_ALWAYS )
            {
                for(const auto& l_it : i_freq_map)
                {
                    // This can be refactored to return info people might
                    // need.  Until then this returns true if hw was deconfigured
                    // FFDC prints out location
                    deconfigure(l_it.first, l_it.second, i_nest_freq);

                }// end for
            }// end if

            // Implicitly covers case when ATTR_REQUIRED_SYNCH_MODE is
            // NEVER, ALWAYS, and UNDETERMINED
            o_selected_sync_mode = sync_mode::MC_NOT_IN_SYNC;

            break;

        default:
            FAPI_ERR("Invalid speed_equality parameter!");
            return fapi2::FAPI2_RC_INVALID_PARAMETER;
            break;
    }// end switch

    return fapi2::FAPI2_RC_SUCCESS;
}

}// mss
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: PagePropertySetContext.cxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 15:29:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _XMLOFF_PAGEPROPERTYSETCONTEXT_HXX
#include "PagePropertySetContext.hxx"
#endif
#ifndef _XMLBACKGROUNDIMAGECONTEXT_HXX
#include "XMLBackgroundImageContext.hxx"
#endif
#ifndef _XMLTEXTCOLUMNSCONTEXT_HXX
#include "XMLTextColumnsContext.hxx"
#endif
#ifndef _XMLOFF_PAGEMASTERSTYLEMAP_HXX
#include <xmloff/PageMasterStyleMap.hxx>
#endif
#ifndef _XMLOFF_XMLFOOTNOTESEPARATORIMPORT_HXX
#include "XMLFootnoteSeparatorImport.hxx"
#endif

using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;

PagePropertySetContext::PagePropertySetContext(
                 SvXMLImport& rImport, sal_uInt16 nPrfx,
                 const OUString& rLName,
                 const Reference< xml::sax::XAttributeList > & xAttrList,
                 sal_uInt32 nFam,
                 ::std::vector< XMLPropertyState > &rProps,
                 const UniReference < SvXMLImportPropertyMapper > &rMap,
                 sal_Int32 nStartIndex, sal_Int32 nEndIndex,
                 const PageContextType aTempType ) :
    SvXMLPropertySetContext( rImport, nPrfx, rLName, xAttrList, nFam,
                             rProps, rMap, nStartIndex, nEndIndex )
{
    aType = aTempType;
}

PagePropertySetContext::~PagePropertySetContext()
{
}

SvXMLImportContext *PagePropertySetContext::CreateChildContext(
                   sal_uInt16 nPrefix,
                   const OUString& rLocalName,
                   const Reference< xml::sax::XAttributeList > & xAttrList,
                   ::std::vector< XMLPropertyState > &rProperties,
                   const XMLPropertyState& rProp )
{
    sal_Int32 nPos = CTF_PM_GRAPHICPOSITION;
    sal_Int32 nFil = CTF_PM_GRAPHICFILTER;
    switch ( aType )
    {
        case Header:
        {
            nPos = CTF_PM_HEADERGRAPHICPOSITION;
            nFil = CTF_PM_HEADERGRAPHICFILTER;
        }
        break;
        case Footer:
        {
            nPos = CTF_PM_FOOTERGRAPHICPOSITION;
            nFil = CTF_PM_FOOTERGRAPHICFILTER;
        }
        break;
        default:
            break;
    }
    SvXMLImportContext *pContext = 0;

    switch( mxMapper->getPropertySetMapper()
                    ->GetEntryContextId( rProp.mnIndex ) )
    {
    case CTF_PM_GRAPHICURL:
    case CTF_PM_HEADERGRAPHICURL:
    case CTF_PM_FOOTERGRAPHICURL:
        DBG_ASSERT( rProp.mnIndex >= 2 &&
                    nPos  == mxMapper->getPropertySetMapper()
                        ->GetEntryContextId( rProp.mnIndex-2 ) &&
                    nFil  == mxMapper->getPropertySetMapper()
                        ->GetEntryContextId( rProp.mnIndex-1 ),
                    "invalid property map!");
        pContext =
            new XMLBackgroundImageContext( GetImport(), nPrefix,
                                           rLocalName, xAttrList,
                                           rProp,
                                           rProp.mnIndex-2,
                                           rProp.mnIndex-1,
                                           -1,
                                           rProperties );
        break;

    case CTF_PM_TEXTCOLUMNS:
#ifndef SVX_LIGHT
        pContext = new XMLTextColumnsContext( GetImport(), nPrefix,
                                              rLocalName, xAttrList, rProp,
                                              rProperties );
#else
        // create default context to skip content
        pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
#endif // #ifndef SVX_LIGHT
        break;

    case CTF_PM_FTN_LINE_WEIGTH:
#ifndef SVX_LIGHT
        pContext = new XMLFootnoteSeparatorImport(
            GetImport(), nPrefix, rLocalName, rProperties,
            mxMapper->getPropertySetMapper(), rProp.mnIndex);
#else
        // create default context to skip content
        pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName);
#endif // #ifndef SVX_LIGHT
        break;
    }

    if( !pContext )
        pContext = SvXMLPropertySetContext::CreateChildContext( nPrefix, rLocalName,
                                                            xAttrList,
                                                            rProperties, rProp );

    return pContext;
}

<commit_msg>INTEGRATION: CWS impresstables2 (1.12.80); FILE MERGED 2007/08/01 14:26:12 cl 1.12.80.2: RESYNC: (1.12-1.13); FILE MERGED 2007/07/27 09:09:53 cl 1.12.80.1: fixed build issues due to pch and namespace ::rtl<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: PagePropertySetContext.cxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: rt $ $Date: 2008-03-12 10:44:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _XMLOFF_PAGEPROPERTYSETCONTEXT_HXX
#include "PagePropertySetContext.hxx"
#endif
#ifndef _XMLBACKGROUNDIMAGECONTEXT_HXX
#include "XMLBackgroundImageContext.hxx"
#endif
#ifndef _XMLTEXTCOLUMNSCONTEXT_HXX
#include "XMLTextColumnsContext.hxx"
#endif
#ifndef _XMLOFF_PAGEMASTERSTYLEMAP_HXX
#include <xmloff/PageMasterStyleMap.hxx>
#endif
#ifndef _XMLOFF_XMLFOOTNOTESEPARATORIMPORT_HXX
#include "XMLFootnoteSeparatorImport.hxx"
#endif

using ::rtl::OUString;

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;

PagePropertySetContext::PagePropertySetContext(
                 SvXMLImport& rImport, sal_uInt16 nPrfx,
                 const OUString& rLName,
                 const Reference< xml::sax::XAttributeList > & xAttrList,
                 sal_uInt32 nFam,
                 ::std::vector< XMLPropertyState > &rProps,
                 const UniReference < SvXMLImportPropertyMapper > &rMap,
                 sal_Int32 nStartIndex, sal_Int32 nEndIndex,
                 const PageContextType aTempType ) :
    SvXMLPropertySetContext( rImport, nPrfx, rLName, xAttrList, nFam,
                             rProps, rMap, nStartIndex, nEndIndex )
{
    aType = aTempType;
}

PagePropertySetContext::~PagePropertySetContext()
{
}

SvXMLImportContext *PagePropertySetContext::CreateChildContext(
                   sal_uInt16 nPrefix,
                   const OUString& rLocalName,
                   const Reference< xml::sax::XAttributeList > & xAttrList,
                   ::std::vector< XMLPropertyState > &rProperties,
                   const XMLPropertyState& rProp )
{
    sal_Int32 nPos = CTF_PM_GRAPHICPOSITION;
    sal_Int32 nFil = CTF_PM_GRAPHICFILTER;
    switch ( aType )
    {
        case Header:
        {
            nPos = CTF_PM_HEADERGRAPHICPOSITION;
            nFil = CTF_PM_HEADERGRAPHICFILTER;
        }
        break;
        case Footer:
        {
            nPos = CTF_PM_FOOTERGRAPHICPOSITION;
            nFil = CTF_PM_FOOTERGRAPHICFILTER;
        }
        break;
        default:
            break;
    }
    SvXMLImportContext *pContext = 0;

    switch( mxMapper->getPropertySetMapper()
                    ->GetEntryContextId( rProp.mnIndex ) )
    {
    case CTF_PM_GRAPHICURL:
    case CTF_PM_HEADERGRAPHICURL:
    case CTF_PM_FOOTERGRAPHICURL:
        DBG_ASSERT( rProp.mnIndex >= 2 &&
                    nPos  == mxMapper->getPropertySetMapper()
                        ->GetEntryContextId( rProp.mnIndex-2 ) &&
                    nFil  == mxMapper->getPropertySetMapper()
                        ->GetEntryContextId( rProp.mnIndex-1 ),
                    "invalid property map!");
        pContext =
            new XMLBackgroundImageContext( GetImport(), nPrefix,
                                           rLocalName, xAttrList,
                                           rProp,
                                           rProp.mnIndex-2,
                                           rProp.mnIndex-1,
                                           -1,
                                           rProperties );
        break;

    case CTF_PM_TEXTCOLUMNS:
#ifndef SVX_LIGHT
        pContext = new XMLTextColumnsContext( GetImport(), nPrefix,
                                              rLocalName, xAttrList, rProp,
                                              rProperties );
#else
        // create default context to skip content
        pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
#endif // #ifndef SVX_LIGHT
        break;

    case CTF_PM_FTN_LINE_WEIGTH:
#ifndef SVX_LIGHT
        pContext = new XMLFootnoteSeparatorImport(
            GetImport(), nPrefix, rLocalName, rProperties,
            mxMapper->getPropertySetMapper(), rProp.mnIndex);
#else
        // create default context to skip content
        pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName);
#endif // #ifndef SVX_LIGHT
        break;
    }

    if( !pContext )
        pContext = SvXMLPropertySetContext::CreateChildContext( nPrefix, rLocalName,
                                                            xAttrList,
                                                            rProperties, rProp );

    return pContext;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ChartOASISTContext.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-13 08:43:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_CHARTOASISTCONTEXT_HXX
#include "ChartOASISTContext.hxx"
#endif
#ifndef _XMLOFF_MUTABLEATTRLIST_HXX
#include "MutableAttrList.hxx"
#endif
#ifndef _XMLOFF_XMLNMSPE_HXX
#include "xmlnmspe.hxx"
#endif
#ifndef _XMLOFF_ACTIONMAPTYPESOASIS_HXX
#include "ActionMapTypesOASIS.hxx"
#endif
#ifndef _XMLOFF_ATTRTRANSFORMERACTION_HXX
#include "AttrTransformerAction.hxx"
#endif
#ifndef _XMLOFF_TRANSFORMERACTIONS_HXX
#include "TransformerActions.hxx"
#endif
#ifndef _XMLOFF_TRANSFORMERBASE_HXX
#include "TransformerBase.hxx"
#endif

using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;

// -----------------------------------------------------------------------------

TYPEINIT1( XMLChartOASISTransformerContext, XMLTransformerContext );

XMLChartOASISTransformerContext::XMLChartOASISTransformerContext(
        XMLTransformerBase& rImp,
        const OUString& rQName ) :
    XMLTransformerContext( rImp, rQName )
{
}

XMLChartOASISTransformerContext::~XMLChartOASISTransformerContext()
{
}

void XMLChartOASISTransformerContext::StartElement(
    const Reference< XAttributeList >& rAttrList )
{
    XMLTransformerActions *pActions =
        GetTransformer().GetUserDefinedActions( OASIS_CHART_ACTIONS );
    OSL_ENSURE( pActions, "go no actions" );

    OUString aAddInName;
    Reference< XAttributeList > xAttrList( rAttrList );
    XMLMutableAttributeList *pMutableAttrList = 0;
    sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
    for( sal_Int16 i=0; i < nAttrCount; i++ )
    {
        const OUString& rAttrName = xAttrList->getNameByIndex( i );
        OUString aLocalName;
        sal_uInt16 nPrefix =
            GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName,
                                                                 &aLocalName );
        XMLTransformerActions::key_type aKey( nPrefix, aLocalName );
        XMLTransformerActions::const_iterator aIter =
            pActions->find( aKey );
        if( !(aIter == pActions->end() ) )
        {
            if( !pMutableAttrList )
            {
                pMutableAttrList =
                        new XMLMutableAttributeList( xAttrList );
                xAttrList = pMutableAttrList;
            }
            const OUString& rAttrValue = xAttrList->getValueByIndex( i );
            switch( (*aIter).second.m_nActionType )
            {
            case XML_ATACTION_IN2INCH:
                {
                    OUString aAttrValue( rAttrValue );
                    if( XMLTransformerBase::ReplaceSingleInWithInch(
                                aAttrValue ) )
                        pMutableAttrList->SetValueByIndex( i, aAttrValue );
                }
                break;
            case XML_ATACTION_DECODE_STYLE_NAME_REF:
                {
                    OUString aAttrValue( rAttrValue );
                    if( GetTransformer().DecodeStyleName(aAttrValue) )
                        pMutableAttrList->SetValueByIndex( i, aAttrValue );
                }
                break;
            case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX:
                OSL_ENSURE( IsXMLToken( aLocalName, XML_CLASS ),
                               "unexpected class token" );
                {
                    OUString aChartClass;
                    sal_uInt16 nPrefix =
                        GetTransformer().GetNamespaceMap().GetKeyByAttrName(
                                                            rAttrValue,
                                                            &aChartClass );
                    if( XML_NAMESPACE_CHART == nPrefix )
                    {
                        pMutableAttrList->SetValueByIndex( i, aChartClass );
                    }
                    else if ( XML_NAMESPACE_OOO == nPrefix )
                    {
                        pMutableAttrList->SetValueByIndex( i,
                                                GetXMLToken(XML_ADD_IN ) );
                        aAddInName = aChartClass;
                    }
                }
                break;
            default:
                OSL_ENSURE( !this, "unknown action" );
                break;
            }
        }
    }

    if( aAddInName.getLength() > 0 )
    {
        OUString aAttrQName( GetTransformer().GetNamespaceMap().GetQNameByKey(
                                XML_NAMESPACE_CHART,
                                GetXMLToken( XML_ADD_IN_NAME ) ) );
        pMutableAttrList->AddAttribute( aAttrQName, aAddInName );
    }

    XMLTransformerContext::StartElement( xAttrList );
}
<commit_msg>INTEGRATION: CWS schoasis01 (1.2.78); FILE MERGED 2004/10/14 15:10:08 bm 1.2.78.1: warning removed<commit_after>/*************************************************************************
 *
 *  $RCSfile: ChartOASISTContext.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2004-11-09 18:29:41 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_CHARTOASISTCONTEXT_HXX
#include "ChartOASISTContext.hxx"
#endif
#ifndef _XMLOFF_MUTABLEATTRLIST_HXX
#include "MutableAttrList.hxx"
#endif
#ifndef _XMLOFF_XMLNMSPE_HXX
#include "xmlnmspe.hxx"
#endif
#ifndef _XMLOFF_ACTIONMAPTYPESOASIS_HXX
#include "ActionMapTypesOASIS.hxx"
#endif
#ifndef _XMLOFF_ATTRTRANSFORMERACTION_HXX
#include "AttrTransformerAction.hxx"
#endif
#ifndef _XMLOFF_TRANSFORMERACTIONS_HXX
#include "TransformerActions.hxx"
#endif
#ifndef _XMLOFF_TRANSFORMERBASE_HXX
#include "TransformerBase.hxx"
#endif

using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;

// -----------------------------------------------------------------------------

TYPEINIT1( XMLChartOASISTransformerContext, XMLTransformerContext );

XMLChartOASISTransformerContext::XMLChartOASISTransformerContext(
        XMLTransformerBase& rImp,
        const OUString& rQName ) :
    XMLTransformerContext( rImp, rQName )
{
}

XMLChartOASISTransformerContext::~XMLChartOASISTransformerContext()
{
}

void XMLChartOASISTransformerContext::StartElement(
    const Reference< XAttributeList >& rAttrList )
{
    XMLTransformerActions *pActions =
        GetTransformer().GetUserDefinedActions( OASIS_CHART_ACTIONS );
    OSL_ENSURE( pActions, "go no actions" );

    OUString aAddInName;
    Reference< XAttributeList > xAttrList( rAttrList );
    XMLMutableAttributeList *pMutableAttrList = 0;
    sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
    for( sal_Int16 i=0; i < nAttrCount; i++ )
    {
        const OUString& rAttrName = xAttrList->getNameByIndex( i );
        OUString aLocalName;
        sal_uInt16 nPrefix =
            GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName,
                                                                 &aLocalName );
        XMLTransformerActions::key_type aKey( nPrefix, aLocalName );
        XMLTransformerActions::const_iterator aIter =
            pActions->find( aKey );
        if( !(aIter == pActions->end() ) )
        {
            if( !pMutableAttrList )
            {
                pMutableAttrList =
                        new XMLMutableAttributeList( xAttrList );
                xAttrList = pMutableAttrList;
            }
            const OUString& rAttrValue = xAttrList->getValueByIndex( i );
            switch( (*aIter).second.m_nActionType )
            {
            case XML_ATACTION_IN2INCH:
                {
                    OUString aAttrValue( rAttrValue );
                    if( XMLTransformerBase::ReplaceSingleInWithInch(
                                aAttrValue ) )
                        pMutableAttrList->SetValueByIndex( i, aAttrValue );
                }
                break;
            case XML_ATACTION_DECODE_STYLE_NAME_REF:
                {
                    OUString aAttrValue( rAttrValue );
                    if( GetTransformer().DecodeStyleName(aAttrValue) )
                        pMutableAttrList->SetValueByIndex( i, aAttrValue );
                }
                break;
            case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX:
                OSL_ENSURE( IsXMLToken( aLocalName, XML_CLASS ),
                               "unexpected class token" );
                {
                    if( XML_NAMESPACE_CHART == nPrefix )
                    {
                        pMutableAttrList->SetValueByIndex( i, aLocalName );
                    }
                    else if ( XML_NAMESPACE_OOO == nPrefix )
                    {
                        pMutableAttrList->SetValueByIndex( i,
                                                GetXMLToken(XML_ADD_IN ) );
                        aAddInName = aLocalName;
                    }
                }
                break;
            default:
                OSL_ENSURE( !this, "unknown action" );
                break;
            }
        }
    }

    if( aAddInName.getLength() > 0 )
    {
        OUString aAttrQName( GetTransformer().GetNamespaceMap().GetQNameByKey(
                                XML_NAMESPACE_CHART,
                                GetXMLToken( XML_ADD_IN_NAME ) ) );
        pMutableAttrList->AddAttribute( aAttrQName, aAddInName );
    }

    XMLTransformerContext::StartElement( xAttrList );
}
<|endoftext|>


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

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

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct setunset_t
{
	RTLIL::IdString name;
	RTLIL::Const value;
	bool unset;

	setunset_t(std::string unset_name) : name(RTLIL::escape_id(unset_name)), value(), unset(true) { }

	setunset_t(std::string set_name, std::vector<std::string> args, size_t &argidx) : name(RTLIL::escape_id(set_name)), value(), unset(false)
	{
		if (!args[argidx].empty() && args[argidx][0] == '"') {
			std::string str = args[argidx++].substr(1);
			while (str.size() != 0 && str[str.size()-1] != '"' && argidx < args.size())
				str += args[argidx++];
			if (str.size() != 0 && str[str.size()-1] == '"')
				str = str.substr(0, str.size()-1);
			value = RTLIL::Const(str);
		} else {
			RTLIL::SigSpec sig_value;
			if (!RTLIL::SigSpec::parse(sig_value, NULL, args[argidx++]))
				log_cmd_error("Can't decode value '%s'!\n", args[argidx-1].c_str());
			value = sig_value.as_const();
		}
	}
};

static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, std::vector<setunset_t> &list)
{
	for (auto &item : list)
		if (item.unset)
			attrs.erase(item.name);
		else
			attrs[item.name] = item.value;
}

struct SetattrPass : public Pass {
	SetattrPass() : Pass("setattr", "set/unset attributes on objects") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    setattr [ -mod ] [ -set name value | -unset name ]... [selection]\n");
		log("\n");
		log("Set/unset the given attributes on the selected objects. String values must be\n");
		log("passed in double quotes (\").\n");
		log("\n");
		log("When called with -mod, this command will set and unset attributes on modules\n");
		log("instead of objects within modules.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::vector<setunset_t> setunset_list;
		bool flag_mod = false;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			std::string arg = args[argidx];
			if (arg == "-set" && argidx+2 < args.size()) {
				argidx += 2;
				setunset_list.push_back(setunset_t(args[argidx-1], args, argidx));
				argidx--;
				continue;
			}
			if (arg == "-unset" && argidx+1 < args.size()) {
				setunset_list.push_back(setunset_t(args[++argidx]));
				continue;
			}
			if (arg == "-mod") {
				flag_mod = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod : design->modules_)
		{
			RTLIL::Module *module = mod.second;

			if (flag_mod) {
				if (design->selected_whole_module(module->name))
					do_setunset(module->attributes, setunset_list);
				continue;
			}

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

			for (auto &it : module->wires_)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);

			for (auto &it : module->memories)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);

			for (auto &it : module->cells_)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);

			for (auto &it : module->processes)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);
		}
	}
} SetattrPass;

struct SetparamPass : public Pass {
	SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    setparam [ -set name value | -unset name ]... [selection]\n");
		log("\n");
		log("Set/unset the given parameters on the selected cells. String values must be\n");
		log("passed in double quotes (\").\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::vector<setunset_t> setunset_list;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			std::string arg = args[argidx];
			if (arg == "-set" && argidx+2 < args.size()) {
				argidx += 2;
				setunset_list.push_back(setunset_t(args[argidx-1], args, argidx));
				argidx--;
				continue;
			}
			if (arg == "-unset" && argidx+1 < args.size()) {
				setunset_list.push_back(setunset_t(args[++argidx]));
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod : design->modules_)
		{
			RTLIL::Module *module = mod.second;

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

			for (auto &it : module->cells_)
				if (design->selected(module, it.second))
					do_setunset(it.second->parameters, setunset_list);
		}
	}
} SetparamPass;

struct ChparamPass : public Pass {
	ChparamPass() : Pass("chparam", "re-evaluate modules with new parameters") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    chparam [ -set name value ]... [selection]\n");
		log("\n");
		log("Re-evaluate the selected modules with new parameters. String values must be\n");
		log("passed in double quotes (\").\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::vector<setunset_t> setunset_list;
		dict<RTLIL::IdString, RTLIL::Const> new_parameters;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			std::string arg = args[argidx];
			if (arg == "-set" && argidx+2 < args.size()) {
				argidx += 2;
				setunset_t new_param(args[argidx-1], args, argidx);
				new_parameters[new_param.name] = new_param.value;
				argidx--;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		pool<IdString> modnames, old_modnames;
		for (auto module : design->selected_modules()) {
			if (design->selected_whole_module(module))
				modnames.insert(module->name);
			else
				log_warning("Ignoring partially selecedted module %s.\n", log_id(module));
			old_modnames.insert(module->name);
		}
		modnames.sort();

		for (auto modname : modnames) {
			Module *module = design->module(modname);
			Module *new_module = design->module(module->derive(design, new_parameters));
			if (module != new_module) {
				Module *m = new_module->clone();
				m->name = module->name;
				design->remove(module);
				design->add(m);
			}
			if (old_modnames.count(new_module->name) == 0)
				design->remove(new_module);
		}
	}
} ChparamPass;

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

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

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct setunset_t
{
	RTLIL::IdString name;
	RTLIL::Const value;
	bool unset;

	setunset_t(std::string unset_name) : name(RTLIL::escape_id(unset_name)), value(), unset(true) { }

	setunset_t(std::string set_name, std::vector<std::string> args, size_t &argidx) : name(RTLIL::escape_id(set_name)), value(), unset(false)
	{
		if (!args[argidx].empty() && args[argidx][0] == '"') {
			std::string str = args[argidx++].substr(1);
			while (str.size() != 0 && str[str.size()-1] != '"' && argidx < args.size())
				str += args[argidx++];
			if (str.size() != 0 && str[str.size()-1] == '"')
				str = str.substr(0, str.size()-1);
			value = RTLIL::Const(str);
		} else {
			RTLIL::SigSpec sig_value;
			if (!RTLIL::SigSpec::parse(sig_value, NULL, args[argidx++]))
				log_cmd_error("Can't decode value '%s'!\n", args[argidx-1].c_str());
			value = sig_value.as_const();
		}
	}
};

static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, std::vector<setunset_t> &list)
{
	for (auto &item : list)
		if (item.unset)
			attrs.erase(item.name);
		else
			attrs[item.name] = item.value;
}

struct SetattrPass : public Pass {
	SetattrPass() : Pass("setattr", "set/unset attributes on objects") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    setattr [ -mod ] [ -set name value | -unset name ]... [selection]\n");
		log("\n");
		log("Set/unset the given attributes on the selected objects. String values must be\n");
		log("passed in double quotes (\").\n");
		log("\n");
		log("When called with -mod, this command will set and unset attributes on modules\n");
		log("instead of objects within modules.\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::vector<setunset_t> setunset_list;
		bool flag_mod = false;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			std::string arg = args[argidx];
			if (arg == "-set" && argidx+2 < args.size()) {
				argidx += 2;
				setunset_list.push_back(setunset_t(args[argidx-1], args, argidx));
				argidx--;
				continue;
			}
			if (arg == "-unset" && argidx+1 < args.size()) {
				setunset_list.push_back(setunset_t(args[++argidx]));
				continue;
			}
			if (arg == "-mod") {
				flag_mod = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod : design->modules_)
		{
			RTLIL::Module *module = mod.second;

			if (flag_mod) {
				if (design->selected_whole_module(module->name))
					do_setunset(module->attributes, setunset_list);
				continue;
			}

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

			for (auto &it : module->wires_)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);

			for (auto &it : module->memories)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);

			for (auto &it : module->cells_)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);

			for (auto &it : module->processes)
				if (design->selected(module, it.second))
					do_setunset(it.second->attributes, setunset_list);
		}
	}
} SetattrPass;

struct SetparamPass : public Pass {
	SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    setparam [ -set name value | -unset name ]... [selection]\n");
		log("\n");
		log("Set/unset the given parameters on the selected cells. String values must be\n");
		log("passed in double quotes (\").\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::vector<setunset_t> setunset_list;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			std::string arg = args[argidx];
			if (arg == "-set" && argidx+2 < args.size()) {
				argidx += 2;
				setunset_list.push_back(setunset_t(args[argidx-1], args, argidx));
				argidx--;
				continue;
			}
			if (arg == "-unset" && argidx+1 < args.size()) {
				setunset_list.push_back(setunset_t(args[++argidx]));
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto &mod : design->modules_)
		{
			RTLIL::Module *module = mod.second;

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

			for (auto &it : module->cells_)
				if (design->selected(module, it.second))
					do_setunset(it.second->parameters, setunset_list);
		}
	}
} SetparamPass;

struct ChparamPass : public Pass {
	ChparamPass() : Pass("chparam", "re-evaluate modules with new parameters") { }
	virtual void help()
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    chparam [ -set name value ]... [selection]\n");
		log("\n");
		log("Re-evaluate the selected modules with new parameters. String values must be\n");
		log("passed in double quotes (\").\n");
		log("\n");
	}
	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
	{
		std::vector<setunset_t> setunset_list;
		dict<RTLIL::IdString, RTLIL::Const> new_parameters;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			std::string arg = args[argidx];
			if (arg == "-set" && argidx+2 < args.size()) {
				argidx += 2;
				setunset_t new_param(args[argidx-1], args, argidx);
				new_parameters[new_param.name] = new_param.value;
				argidx--;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		pool<IdString> modnames, old_modnames;
		for (auto module : design->selected_modules()) {
			if (design->selected_whole_module(module))
				modnames.insert(module->name);
			else
				log_warning("Ignoring partially selected module %s.\n", log_id(module));
			old_modnames.insert(module->name);
		}
		modnames.sort();

		for (auto modname : modnames) {
			Module *module = design->module(modname);
			Module *new_module = design->module(module->derive(design, new_parameters));
			if (module != new_module) {
				Module *m = new_module->clone();
				m->name = module->name;
				design->remove(module);
				design->add(m);
			}
			if (old_modnames.count(new_module->name) == 0)
				design->remove(new_module);
		}
	}
} ChparamPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


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

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/modtools.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct OptLutWorker
{
	RTLIL::Module *module;
	ModIndex index;
	SigMap sigmap;

	pool<RTLIL::Cell*> luts;
	dict<RTLIL::Cell*, int> luts_arity;

	int combined_count = 0;

	bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs)
	{
		SigSpec lut_input = sigmap(lut->getPort("\\A"));
		int lut_width = lut->getParam("\\WIDTH").as_int();
		Const lut_table = lut->getParam("\\LUT");
		int lut_index = 0;

		for (int i = 0; i < lut_width; i++)
		{
			SigBit input = sigmap(lut_input[i]);
			if (inputs.count(input))
			{
				lut_index |= inputs[input] << i;
			}
			else
			{
				lut_index |= SigSpec(lut_input[i]).as_bool() << i;
			}
		}

		return lut_table.extract(lut_index).as_int();
	}

	void show_stats_by_arity()
	{
		dict<int, int> arity_counts;
		int max_arity = 0;
		for (auto lut_arity : luts_arity)
		{
			max_arity = max(max_arity, lut_arity.second);
			arity_counts[lut_arity.second]++;
		}

		log("Number of LUTs: %6zu\n", luts.size());
		for (int arity = 1; arity <= max_arity; arity++)
		{
			if (arity_counts[arity])
				log("  %d-LUT: %13d\n", arity, arity_counts[arity]);
		}
	}

	OptLutWorker(RTLIL::Module *module) :
		module(module), index(module), sigmap(module)
	{
		log("Discovering LUTs.\n");
		for (auto cell : module->selected_cells())
		{
			if (cell->type == "$lut")
			{
				int lut_width = cell->getParam("\\WIDTH").as_int();
				SigSpec lut_input = cell->getPort("\\A");
				int lut_arity = 0;

				for (auto &bit : lut_input)
				{
					if (bit.wire)
						lut_arity++;
				}

				log("Found $lut cell %s.%s with WIDTH=%d implementing %d-LUT.\n", log_id(module), log_id(cell), lut_width, lut_arity);
				luts.insert(cell);
				luts_arity[cell] = lut_arity;
			}
		}
		show_stats_by_arity();

		log("\n");
		log("Combining LUTs.\n");
		pool<RTLIL::Cell*> worklist = luts;
		while (worklist.size())
		{
			auto lutA = worklist.pop();
			SigSpec lutA_input = sigmap(lutA->getPort("\\A"));
			SigSpec lutA_output = sigmap(lutA->getPort("\\Y")[0]);
			int lutA_width = lutA->getParam("\\WIDTH").as_int();
			int lutA_arity = luts_arity[lutA];

			auto lutA_output_ports = index.query_ports(lutA->getPort("\\Y"));
			if (lutA_output_ports.size() != 2)
				continue;

			for (auto port : lutA_output_ports)
			{
				if (port.cell == lutA)
					continue;

				if (luts.count(port.cell))
				{
					auto lutB = port.cell;
					SigSpec lutB_input = sigmap(lutB->getPort("\\A"));
					SigSpec lutB_output = sigmap(lutB->getPort("\\Y")[0]);
					int lutB_width = lutB->getParam("\\WIDTH").as_int();
					int lutB_arity = luts_arity[lutB];

					log("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));

					pool<SigBit> lutA_inputs;
					pool<SigBit> lutB_inputs;
					for (auto &bit : lutA_input)
					{
						if (bit.wire)
							lutA_inputs.insert(sigmap(bit));
					}
					for (auto &bit : lutB_input)
					{
						if(bit.wire)
							lutB_inputs.insert(sigmap(bit));
					}

					pool<SigBit> common_inputs;
					for (auto &bit : lutA_inputs)
					{
						if (lutB_inputs.count(bit))
							common_inputs.insert(bit);
					}

					int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size();
					log("  Cell A is a %d-LUT. Cell B is a %d-LUT. Cells share %zu input(s) and can be merged into one %d-LUT.\n", lutA_arity, lutB_arity, common_inputs.size(), lutM_arity);

					int combine = -1;
					if (combine == -1)
					{
						if (lutM_arity > lutA_width)
						{
							log("  Not combining LUTs into cell A (combined LUT too wide).\n");
						}
						else if (lutB->get_bool_attribute("\\lut_keep"))
						{
							log("  Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n");
						}
						else combine = 0;
					}
					if (combine == -1)
					{
						if (lutM_arity > lutB_width)
						{
							log("  Not combining LUTs into cell B (combined LUT too wide).\n");
						}
						else if (lutA->get_bool_attribute("\\lut_keep"))
						{
							log("  Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n");
						}
						else combine = 1;
					}

					RTLIL::Cell *lutM, *lutR;
					pool<SigBit> lutM_inputs, lutR_inputs;
					if (combine == 0)
					{
						log("  Combining LUTs into cell A.\n");
						lutM = lutA;
						lutM_inputs = lutA_inputs;
						lutR = lutB;
						lutR_inputs = lutB_inputs;
					}
					else if (combine == 1)
					{
						log("  Combining LUTs into cell B.\n");
						lutM = lutB;
						lutM_inputs = lutB_inputs;
						lutR = lutA;
						lutR_inputs = lutA_inputs;
					}
					else
					{
						log("  Cannot combine LUTs.\n");
						continue;
					}

					pool<SigBit> lutR_unique;
					for (auto &bit : lutR_inputs)
					{
						if (!common_inputs.count(bit) && bit != lutA_output)
							lutR_unique.insert(bit);
					}

					int lutM_width = lutM->getParam("\\WIDTH").as_int();
					SigSpec lutM_input = sigmap(lutM->getPort("\\A"));
					std::vector<SigBit> lutM_new_inputs;
					for (int i = 0; i < lutM_width; i++)
					{
						if ((!lutM_input[i].wire || sigmap(lutM_input[i]) == lutA_output) && lutR_unique.size())
						{
							SigBit new_input = lutR_unique.pop();
							log("    Connecting input %d as %s.\n", i, log_signal(new_input));
							lutM_new_inputs.push_back(new_input);
						}
						else if (sigmap(lutM_input[i]) == lutA_output)
						{
							log("    Disconnecting input %d.\n", i);
							lutM_new_inputs.push_back(SigBit());
						}
						else
						{
							log("    Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
							lutM_new_inputs.push_back(lutM_input[i]);
						}
					}
					log_assert(lutR_unique.size() == 0);

					RTLIL::Const lutM_new_table(State::Sx, 1 << lutM_width);
					for (int eval = 0; eval < 1 << lutM_width; eval++)
					{
						dict<SigBit, bool> eval_inputs;
						for (size_t i = 0; i < lutM_new_inputs.size(); i++)
						{
							eval_inputs[lutM_new_inputs[i]] = (eval >> i) & 1;
						}
						eval_inputs[lutA_output] = evaluate_lut(lutA, eval_inputs);
						lutM_new_table[eval] = (RTLIL::State) evaluate_lut(lutB, eval_inputs);
					}

					log("  Old truth table: %s.\n", lutM->getParam("\\LUT").as_string().c_str());
					log("  New truth table: %s.\n", lutM_new_table.as_string().c_str());

					lutM->setParam("\\LUT", lutM_new_table);
					lutM->setPort("\\A", lutM_new_inputs);
					lutM->setPort("\\Y", lutB_output);

					luts_arity[lutM] = lutM_arity;
					luts.erase(lutR);
					luts_arity.erase(lutR);
					lutR->module->remove(lutR);

					worklist.insert(lutM);
					worklist.erase(lutR);

					combined_count++;
				}
			}
		}
		show_stats_by_arity();
	}
};

struct OptLutPass : public Pass {
	OptLutPass() : Pass("opt_lut", "optimize LUT cells") { }
	void help() YS_OVERRIDE
	{
		log("\n");
		log("    opt_lut [options] [selection]\n");
		log("\n");
		log("This pass combines cascaded $lut cells with unused inputs.\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		log_header(design, "Executing OPT_LUT pass (optimize LUTs).\n");

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

		int total_count = 0;
		for (auto module : design->selected_modules())
		{
			OptLutWorker worker(module);
			total_count += worker.combined_count;
		}
		if (total_count)
			design->scratchpad_set_bool("opt.did_something", true);
		log("\n");
		log("Combined %d LUTs.\n", total_count);
	}
} OptLutPass;

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

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/modtools.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct OptLutWorker
{
	RTLIL::Module *module;
	ModIndex index;
	SigMap sigmap;

	pool<RTLIL::Cell*> luts;
	dict<RTLIL::Cell*, int> luts_arity;

	int combined_count = 0;

	bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs)
	{
		SigSpec lut_input = sigmap(lut->getPort("\\A"));
		int lut_width = lut->getParam("\\WIDTH").as_int();
		Const lut_table = lut->getParam("\\LUT");
		int lut_index = 0;

		for (int i = 0; i < lut_width; i++)
		{
			SigBit input = sigmap(lut_input[i]);
			if (inputs.count(input))
			{
				lut_index |= inputs[input] << i;
			}
			else
			{
				lut_index |= SigSpec(lut_input[i]).as_bool() << i;
			}
		}

		return lut_table.extract(lut_index).as_int();
	}

	void show_stats_by_arity()
	{
		dict<int, int> arity_counts;
		int max_arity = 0;
		for (auto lut_arity : luts_arity)
		{
			max_arity = max(max_arity, lut_arity.second);
			arity_counts[lut_arity.second]++;
		}

		log("Number of LUTs: %6zu\n", luts.size());
		for (int arity = 1; arity <= max_arity; arity++)
		{
			if (arity_counts[arity])
				log("  %d-LUT: %13d\n", arity, arity_counts[arity]);
		}
	}

	OptLutWorker(RTLIL::Module *module) :
		module(module), index(module), sigmap(module)
	{
		log("Discovering LUTs.\n");
		for (auto cell : module->selected_cells())
		{
			if (cell->type == "$lut")
			{
				int lut_width = cell->getParam("\\WIDTH").as_int();
				SigSpec lut_input = cell->getPort("\\A");
				int lut_arity = 0;

				for (auto &bit : lut_input)
				{
					if (bit.wire)
						lut_arity++;
				}

				log("Found $lut cell %s.%s with WIDTH=%d implementing %d-LUT.\n", log_id(module), log_id(cell), lut_width, lut_arity);
				luts.insert(cell);
				luts_arity[cell] = lut_arity;
			}
		}
		show_stats_by_arity();

		log("\n");
		log("Combining LUTs.\n");
		pool<RTLIL::Cell*> worklist = luts;
		while (worklist.size())
		{
			auto lutA = worklist.pop();
			SigSpec lutA_input = sigmap(lutA->getPort("\\A"));
			SigSpec lutA_output = sigmap(lutA->getPort("\\Y")[0]);
			int lutA_width = lutA->getParam("\\WIDTH").as_int();
			int lutA_arity = luts_arity[lutA];

			auto lutA_output_ports = index.query_ports(lutA->getPort("\\Y"));
			if (lutA_output_ports.size() != 2)
				continue;

			for (auto port : lutA_output_ports)
			{
				if (port.cell == lutA)
					continue;

				if (luts.count(port.cell))
				{
					auto lutB = port.cell;
					SigSpec lutB_input = sigmap(lutB->getPort("\\A"));
					SigSpec lutB_output = sigmap(lutB->getPort("\\Y")[0]);
					int lutB_width = lutB->getParam("\\WIDTH").as_int();
					int lutB_arity = luts_arity[lutB];

					log("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB));

					pool<SigBit> lutA_inputs;
					pool<SigBit> lutB_inputs;
					for (auto &bit : lutA_input)
					{
						if (bit.wire)
							lutA_inputs.insert(sigmap(bit));
					}
					for (auto &bit : lutB_input)
					{
						if(bit.wire)
							lutB_inputs.insert(sigmap(bit));
					}

					pool<SigBit> common_inputs;
					for (auto &bit : lutA_inputs)
					{
						if (lutB_inputs.count(bit))
							common_inputs.insert(bit);
					}

					int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size();
					log("  Cell A is a %d-LUT. Cell B is a %d-LUT. Cells share %zu input(s) and can be merged into one %d-LUT.\n", lutA_arity, lutB_arity, common_inputs.size(), lutM_arity);

					const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B;
					int combine_mask = 0;
					if (lutM_arity > lutA_width)
					{
						log("  Not combining LUTs into cell A (combined LUT wider than cell A).\n");
					}
					else if (lutB->get_bool_attribute("\\lut_keep"))
					{
						log("  Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n");
					}
					else
					{
						combine_mask |= COMBINE_A;
					}
					if (lutM_arity > lutB_width)
					{
						log("  Not combining LUTs into cell B (combined LUT wider than cell B).\n");
					}
					else if (lutA->get_bool_attribute("\\lut_keep"))
					{
						log("  Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n");
					}
					else
					{
						combine_mask |= COMBINE_B;
					}

					int combine = combine_mask;
					if (combine == COMBINE_EITHER)
					{
						log("  Can combine into either cell.\n");
						if (lutA_arity == 1)
						{
							log("    Cell A is a buffer or inverter, combining into cell B.\n");
							combine = COMBINE_B;
						}
						else if (lutB_arity == 1)
						{
							log("    Cell B is a buffer or inverter, combining into cell A.\n");
							combine = COMBINE_A;
						}
						else
						{
							log("    Arbitrarily combining into cell A.\n");
							combine = COMBINE_A;
						}
					}

					RTLIL::Cell *lutM, *lutR;
					pool<SigBit> lutM_inputs, lutR_inputs;
					if (combine == COMBINE_A)
					{
						log("  Combining LUTs into cell A.\n");
						lutM = lutA;
						lutM_inputs = lutA_inputs;
						lutR = lutB;
						lutR_inputs = lutB_inputs;
					}
					else if (combine == COMBINE_B)
					{
						log("  Combining LUTs into cell B.\n");
						lutM = lutB;
						lutM_inputs = lutB_inputs;
						lutR = lutA;
						lutR_inputs = lutA_inputs;
					}
					else
					{
						log("  Cannot combine LUTs.\n");
						continue;
					}

					pool<SigBit> lutR_unique;
					for (auto &bit : lutR_inputs)
					{
						if (!common_inputs.count(bit) && bit != lutA_output)
							lutR_unique.insert(bit);
					}

					int lutM_width = lutM->getParam("\\WIDTH").as_int();
					SigSpec lutM_input = sigmap(lutM->getPort("\\A"));
					std::vector<SigBit> lutM_new_inputs;
					for (int i = 0; i < lutM_width; i++)
					{
						if ((!lutM_input[i].wire || sigmap(lutM_input[i]) == lutA_output) && lutR_unique.size())
						{
							SigBit new_input = lutR_unique.pop();
							log("    Connecting input %d as %s.\n", i, log_signal(new_input));
							lutM_new_inputs.push_back(new_input);
						}
						else if (sigmap(lutM_input[i]) == lutA_output)
						{
							log("    Disconnecting input %d.\n", i);
							lutM_new_inputs.push_back(SigBit());
						}
						else
						{
							log("    Leaving input %d as %s.\n", i, log_signal(lutM_input[i]));
							lutM_new_inputs.push_back(lutM_input[i]);
						}
					}
					log_assert(lutR_unique.size() == 0);

					RTLIL::Const lutM_new_table(State::Sx, 1 << lutM_width);
					for (int eval = 0; eval < 1 << lutM_width; eval++)
					{
						dict<SigBit, bool> eval_inputs;
						for (size_t i = 0; i < lutM_new_inputs.size(); i++)
						{
							eval_inputs[lutM_new_inputs[i]] = (eval >> i) & 1;
						}
						eval_inputs[lutA_output] = evaluate_lut(lutA, eval_inputs);
						lutM_new_table[eval] = (RTLIL::State) evaluate_lut(lutB, eval_inputs);
					}

					log("  Old truth table: %s.\n", lutM->getParam("\\LUT").as_string().c_str());
					log("  New truth table: %s.\n", lutM_new_table.as_string().c_str());

					lutM->setParam("\\LUT", lutM_new_table);
					lutM->setPort("\\A", lutM_new_inputs);
					lutM->setPort("\\Y", lutB_output);

					luts_arity[lutM] = lutM_arity;
					luts.erase(lutR);
					luts_arity.erase(lutR);
					lutR->module->remove(lutR);

					worklist.insert(lutM);
					worklist.erase(lutR);

					combined_count++;
				}
			}
		}
		show_stats_by_arity();
	}
};

struct OptLutPass : public Pass {
	OptLutPass() : Pass("opt_lut", "optimize LUT cells") { }
	void help() YS_OVERRIDE
	{
		log("\n");
		log("    opt_lut [options] [selection]\n");
		log("\n");
		log("This pass combines cascaded $lut cells with unused inputs.\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		log_header(design, "Executing OPT_LUT pass (optimize LUTs).\n");

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

		int total_count = 0;
		for (auto module : design->selected_modules())
		{
			OptLutWorker worker(module);
			total_count += worker.combined_count;
		}
		if (total_count)
			design->scratchpad_set_bool("opt.did_something", true);
		log("\n");
		log("Combined %d LUTs.\n", total_count);
	}
} OptLutPass;

PRIVATE_NAMESPACE_END
<|endoftext|>