3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-22 08:35:32 +00:00
yosys/kernel/bitpattern.h
2024-07-18 15:48:52 +02:00

207 lines
5.3 KiB
C++

/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef BITPATTERN_H
#define BITPATTERN_H
#include "kernel/log.h"
#include "kernel/rtlil.h"
YOSYS_NAMESPACE_BEGIN
/**
* This file implements BitPatternPool for efficiently storing
* sets of fixed-width 2-valued logic constants compressed as "bit patterns"
* represented as bits_t. A bit pattern is a signal in 3-valued logic:
* 0, 1, a ("any" or "don't care").
*
* BitPatternPool does not permit adding new patterns, only removing.
* Its intended use case is in analysing cases in case/match constructs in HDL.
*/
struct BitPatternPool
{
int width;
struct bits_t {
std::vector<RTLIL::State> bitdata;
mutable unsigned int cached_hash;
bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
RTLIL::State &operator[](int index) {
return bitdata[index];
}
const RTLIL::State &operator[](int index) const {
return bitdata[index];
}
bool operator==(const bits_t &other) const {
if (hash() != other.hash())
return false;
return bitdata == other.bitdata;
}
unsigned int hash() const {
if (!cached_hash)
cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
return cached_hash;
}
};
pool<bits_t> database;
BitPatternPool(RTLIL::SigSpec sig)
{
width = sig.size();
if (width > 0) {
bits_t pattern(width);
for (int i = 0; i < width; i++) {
if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1)
pattern[i] = sig[i].data;
else
pattern[i] = RTLIL::State::Sa;
}
database.insert(pattern);
}
}
/**
* Constructs a pool of all possible patterns (all don't-care bits)
*/
BitPatternPool(int width)
{
this->width = width;
if (width > 0) {
bits_t pattern(width);
for (int i = 0; i < width; i++)
pattern[i] = RTLIL::State::Sa;
database.insert(pattern);
}
}
/**
* Convert a constant SigSpec to a pattern. Normalize Yosys many-valued
* to three-valued logic.
*/
bits_t sig2bits(RTLIL::SigSpec sig)
{
bits_t bits;
bits.bitdata = sig.as_const().bits;
for (auto &b : bits.bitdata)
if (b > RTLIL::State::S1)
b = RTLIL::State::Sa;
return bits;
}
/**
* Do two patterns match?
* A pattern matches another when all their bits match.
* A bit matches another if their values are equal.
* A bit also matches another if either of their values is "any"
*/
bool match(bits_t a, bits_t b)
{
log_assert(int(a.bitdata.size()) == width);
log_assert(int(b.bitdata.size()) == width);
for (int i = 0; i < width; i++)
if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])
return false;
return true;
}
/**
* Does sig match any pattern in the pool?
* For example:
* pool({aaa}).has_any(01a) == true
* pool({011}).has_any(01a) == true
* pool({111}).has_any(01a) == false
*/
bool has_any(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
for (auto &it : database)
if (match(it, bits))
return true;
return false;
}
/**
* Does sig match a pattern in the pool such that
* all non-"any" bits in sig are not "any" in the pattern?
* For example:
* pool({aaa}).has_all(01a) == false
* pool({011}).has_all(01a) == true
* pool({111}).has_any(01a) == false
*/
bool has_all(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
for (auto &it : database)
if (match(it, bits)) {
for (int i = 0; i < width; i++)
if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)
goto next_database_entry;
return true;
next_database_entry:;
}
return false;
}
/**
* Remove a pattern from the pool, splitting what's left. True if success.
* For example:
* Taking 011 out of pool({01a}) -> pool({010}), returns true.
* Taking 011 out of pool({010}) does nothing, returns false.
*/
bool take(RTLIL::SigSpec sig)
{
bool status = false;
bits_t bits = sig2bits(sig);
for (auto it = database.begin(); it != database.end();)
if (match(*it, bits)) {
for (int i = 0; i < width; i++) {
if ((*it)[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
continue;
bits_t new_pattern;
new_pattern.bitdata = it->bitdata;
new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
database.insert(new_pattern);
}
it = database.erase(it);
status = true;
continue;
} else
++it;
return status;
}
/**
* Remove all patterns. Returns false if already empty.
*/
bool take_all()
{
if (database.empty())
return false;
database.clear();
return true;
}
bool empty()
{
return database.empty();
}
};
YOSYS_NAMESPACE_END
#endif