Skip to content

Commit

Permalink
Merge pull request #7 from amiq-consulting/flexible_bin_definitions
Browse files Browse the repository at this point in the history
Flexible bin definitions
  • Loading branch information
AMIQ Consulting authored Nov 2, 2018
2 parents a42742a + 5bf7169 commit 3da19f7
Show file tree
Hide file tree
Showing 12 changed files with 293 additions and 318 deletions.
Binary file modified doc/FC4SC_User_Guide.pdf
Binary file not shown.
7 changes: 7 additions & 0 deletions includes/fc4sc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@
#ifndef FC4SC_HPP
#define FC4SC_HPP

#include <utility> // std::pair

namespace fc4sc {
template<typename T>
using interval_t = std::pair<T, T>;
};

#include "fc4sc_base.hpp"
#include "fc4sc_intervals.hpp"
#include "fc4sc_options.hpp"
Expand Down
16 changes: 5 additions & 11 deletions includes/fc4sc_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ template<typename forbidden, typename first> struct forbid_type<forbidden, first
/*
* Macro used to define and automatically register a coverpoint inside a covergroup.
* The macro accepts 3 or 4 arguments in the following order:
* 1) Type: used for the values of the bins declared in the coveroint
* 1) Type: used for the values of the bins declared in the coverpoint
* 2) Name: the name of the coverpoint
* 3) Sample Expression: the expression that will be used for sampling this coverpoint
* whenever the covergroup is sampled (the type has to be the same as Type argument)
Expand Down Expand Up @@ -120,9 +120,6 @@ template<typename forbidden, typename first> struct forbid_type<forbidden, first
*/
namespace fc4sc
{
template<typename T>
using interval_t = std::pair<T, T>;

using cvp_metadata_t = std::tuple<void*, std::string, std::string>;

typedef enum fc4sc_format {
Expand Down Expand Up @@ -157,16 +154,11 @@ class bin_base
* \param stream Where to print
*/
virtual void to_xml(std::ostream &stream) const = 0;

/*!
* \brief Returns total number of hits
* \returns number of times the sampled value was in the bin
*/
virtual uint64_t get_hitcount() const = 0;
// {
// return hits;
// }

/*! Destructor */
virtual ~bin_base(){}
};
Expand Down Expand Up @@ -234,6 +226,9 @@ class api_base
*/
class cvp_base : public api_base
{
protected:
bool stop_sample_on_first_bin_hit = false;

public:
uint last_bin_index_hit;
uint last_sample_success;
Expand All @@ -244,7 +239,7 @@ class cvp_base : public api_base
/*! Type specific options */
cvp_type_option type_option;

/*! Number of samples not found in any bin */
/*! Number of sample misses (no bin hit)*/
uint64_t misses = 0;

/*! Destructor */
Expand Down Expand Up @@ -324,7 +319,6 @@ class illegal_bin_sample_exception : public std::exception {
update_message();
}


const char * what () const throw () {
return message.c_str();
}
Expand Down
160 changes: 76 additions & 84 deletions includes/fc4sc_bin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ class bin : public bin_base
// the one which receives a name as the first argument. This forces the user
// to give a name for each instantiated bin.

/*! Default Constructor */
bin() = default;
/*!
* \brief Takes a value and wraps it in a pair
* \param value Value associated with the bin
Expand All @@ -95,13 +93,16 @@ class bin : public bin_base
*/
template <typename... Args>
bin(interval_t<T> interval, Args... args) noexcept : bin(args...) {
if (interval.first > interval.second) {
std::swap(interval.first, interval.second);
}
intervals.push_back(interval);
if (intervals.back().first > intervals.back().second) {
std::swap(intervals.back().first, intervals.back().second);
}
}

protected:
/*! Default Constructor */
bin() = default;

void print_xml_header(std::ostream &stream, const std::string &type) const
{
stream << "<ucis:coverpointBin name=\"" << name << "\" \n";
Expand Down Expand Up @@ -234,6 +235,7 @@ class illegal_bin final : public bin<T>
cvp.illegal_bins.push_back(*this);
}

illegal_bin() = delete;
public:
/*!
* \brief Forward to parent constructor
Expand Down Expand Up @@ -299,6 +301,8 @@ class ignore_bin final : public bin<T>
{
cvp.ignore_bins.push_back(*this);
}

ignore_bin() = delete;
public:
/*!
* \brief Forward to parent constructor
Expand All @@ -318,98 +322,86 @@ class bin_array final : public bin<T>
/* Virtual function used to register this bin inside a coverpoint */
virtual void add_to_cvp(coverpoint<T> &cvp) const override
{
cvp.bin_arrays.push_back(*this);
if (this->sparse) {
// bin array was defined by using a vector of intervals or values
// create a new bin for each value/interval and add it to the coverpoint
std::stringstream ss;
for (int i = 0; i < this->intervals.size(); ++i) {
ss << this->name << "[" << i << "]";
cvp.bins.push_back(bin<T>(ss.str(), this->intervals[i]));
ss.str(std::string()); // clear the stringstream
}
}
else {
// bin array was defined by using an interval which needs to be split into
// multiple pieces. The interval is found in the this->intervals[0]
T interval_length = (this->intervals[0].second - this->intervals[0].first) + 1;
if (this->count > interval_length) {
// This bin array interval cannot be split into pieces. Add a single
// bin containing the whole interval to the coverpoint. We can simply
// use this object since it already matches the bin that we need!
cvp.bins.push_back(*this);
}
else {
std::stringstream ss;
// This bin array interval must be split into pieces.
T start = this->intervals[0].first;
T stop = this->intervals[0].second;
T interval_len = (interval_length + 1) / this->count;

for (size_t i = 0; i < this->count; ++i) {
ss << this->name << "[" << i << "]";
// the last interval, will contain all the extra elements
T end = (i == (this->count - 1)) ? stop : start + (interval_len - 1);
cvp.bins.push_back(bin<T>(ss.str(), interval(start, end)));
start = start + interval_len;
ss.str(std::string()); // clear the stringstream
}
}
}
}
public:
std::vector<uint64_t> split_hits;
uint64_t count;

explicit bin_array(const std::string &name, int count, interval_t<T> interval) :
bin<T>(name, interval), count(count)
{
auto intv = this->intervals[0];
uint64_t interval_length = (intv.second - intv.first) + 1;

if (this->count > interval_length)
this->count = 1;

split_hits.resize(this->count);
}
uint64_t count;
bool sparse = false;

virtual ~bin_array() = default;
bin_array() = delete;

uint64_t size() {
return this->count;
}
public:
/*!
* \brief Constructs an bin_array which will split an interval into multiple
* equal parts. The number of sub-intervals is specified via the count argument
*/
explicit bin_array(const std::string &name, uint64_t count, interval_t<T> interval) noexcept :
bin<T>(name, interval), count(count), sparse(false) {}

/*!
* \brief Same as bin::sample(const T& val)
*
* \brief Constructs an bin_array from a vector of intervals where each
* interval will be nested by a bin
*/
uint64_t sample(const T &val)
explicit bin_array(const std::string &name, std::vector<interval_t<T>>&& intvs) noexcept :
count(intvs.size()), sparse(true)
{
for (auto &interval : this->intervals)
if (val >= interval.first && val <= interval.second)
{
uint64_t bin_index = (val - interval.first) * count / (interval.second - interval.first);
if (bin_index == count)
bin_index--;

this->split_hits[bin_index]++;
return bin_index + 1;
}

return 0;
this->name = name;
this->intervals = std::move(intvs);
}



virtual void print_range(std::ostream &stream, T start, T stop, T step, size_t index) const
/*!
* \brief Constructs an bin_array from a vector of values where each
* values will be nested by a bin
*/
explicit bin_array(const std::string &name, const std::vector<T>& intvs) noexcept :
count(intvs.size()), sparse(true)
{

if (index != 0)
start++;

if (index == (count - 1)) {
start = stop - step + 1;
step--;
}

stream << "<ucis:range \n"
<< "from=\"" << start << "\" \n";

stream << "to =\"" << (start + step) << "\"\n"
<< ">\n";
this->name = name;
this->intervals.clear();
this->intervals.reserve(this->count);
// transform each value in the input vector to an interval
std::transform(intvs.begin(), intvs.end(),
std::back_inserter(this->intervals),
[](const T& v) { return fc4sc::interval(v,v); });
}

virtual void to_xml(std::ostream &stream) const
{
T start = this->intervals[0].first;
T stop = this->intervals[0].second;

T step = (stop - start + 1) / count;

for (size_t i = 0; i < count; ++i)
{
stream << "<ucis:coverpointBin name=\"" << this->name << "_" << i+1 << "\" \n";
stream << "type=\"" << "default" << "\" "
<< "alias=\"" << this->split_hits[i] << "\"" << ">\n";

print_range(stream, start, stop, step, i);
// Print hits for each range
stream
<< "<ucis:contents "
<< "coverageCount=\"" << this->split_hits[i] << "\""
<< ">";
stream << "</ucis:contents>\n";

stream << "</ucis:range>\n\n";

stream << "</ucis:coverpointBin>\n";

start = start + step;
}
}
virtual ~bin_array() = default;
};

/*
Expand Down
21 changes: 4 additions & 17 deletions includes/fc4sc_covergroup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class covergroup : public cvg_base
virtual void sample() {
for (auto& cvp : this->cvps) {
try {
cvp->sample();
cvp->sample();
}
catch(illegal_bin_sample_exception &e) {
e.update_cvg_info(this->name);
Expand All @@ -142,20 +142,13 @@ class covergroup : public cvg_base
double res = 0;
double weights = 0;

for (auto &cvp : cvps)
{
for (auto &cvp : cvps) {
res += cvp->get_inst_coverage() * cvp->option.weight;
weights += cvp->option.weight;
}

if (weights == 0 || cvps.size() == 0 || res == 0)
{

if (this->option.weight != 0)
return 0;
else
return 100;
}
return (this->option.weight == 0) ? 100 : 0;

double real = res / weights;
return (real >= this->option.goal) ? 100 : real;
Expand All @@ -169,7 +162,6 @@ class covergroup : public cvg_base
*/
double get_inst_coverage(int &bins_covered, int &total) const
{

double res = 0;
double weights = 0;
int bins_aux = 0;
Expand All @@ -188,14 +180,9 @@ class covergroup : public cvg_base

if (weights == 0 || cvps.size() == 0 || res == 0)
{

total = 0;
bins_covered = 0;

if (this->option.weight != 0)
return 0;
else
return 100;
return (this->option.weight == 0) ? 100 : 0;
}

double real = res / weights;
Expand Down
Loading

0 comments on commit 3da19f7

Please sign in to comment.