blob: 669dd09b6ba438a335b14bbd9d9e65d27e0dec8d [file] [log] [blame]
/* Authors: Aaron Graham (aaron.graham@unb.ca, aarongraham9@gmail.com),
* Jean-Philippe Legault (jlegault@unb.ca, jeanphilippe.legault@gmail.com),
* Alexandrea Demmings (alexandrea.demmings@unb.ca, lxdemmings@gmail.com) and
* Dr. Kenneth B. Kent (ken@unb.ca)
* for the Reconfigurable Computing Research Lab at the
* Univerity of New Brunswick in Fredericton, New Brunswick, Canada
*/
#ifndef INTERNAL_BITS_HPP
#define INTERNAL_BITS_HPP
#include <cstdint>
#include <string>
#include <algorithm>
#include <vector>
#include <bitset>
#include "rtl_utils.hpp"
typedef uint16_t veri_internal_bits_t;
// typedef VNumber<64> veri_64_t;
// typedef VNumber<32> veri_32_t;
template <typename T>
uint8_t get_veri_integer_limit()
{
return (sizeof(T)*8);
}
#define _static_unused(x) namespace { constexpr auto _##x = x; }
#define unroll_1d(lut) { lut[_0], lut[_1], lut[_x], lut[_z] }
#define unroll_2d(lut) { unroll_1d(lut[_0]), unroll_1d(lut[_1]), unroll_1d(lut[_x]), unroll_1d(lut[_z]) }
#define unroll_1d_invert(lut) { l_not[lut[_0]], l_not[lut[_1]], l_not[lut[_x]], l_not[lut[_z]] }
#define unroll_2d_invert(lut) { unroll_1d_invert(lut[_0]), unroll_1d_invert(lut[_1]), unroll_1d_invert(lut[_x]), unroll_1d_invert(lut[_z]) }
namespace BitSpace {
typedef uint8_t bit_value_t;
constexpr veri_internal_bits_t _All_0 = static_cast<veri_internal_bits_t>(0x0000000000000000UL);
constexpr veri_internal_bits_t _All_1 = static_cast<veri_internal_bits_t>(0x5555555555555555UL);
constexpr veri_internal_bits_t _All_x = static_cast<veri_internal_bits_t>(0xAAAAAAAAAAAAAAAAUL);
constexpr veri_internal_bits_t _All_z = static_cast<veri_internal_bits_t>(0xFFFFFFFFFFFFFFFFUL);
constexpr bit_value_t _0 = 0x0;
constexpr bit_value_t _1 = 0x1;
constexpr bit_value_t _x = 0x2;
constexpr bit_value_t _z = 0x3;
/***
* these are taken from the raw verilog truth tables so that the evaluation are correct.
* only use this to evaluate any expression for the number_t binary digits.
* reference: http://staff.ustc.edu.cn/~songch/download/IEEE.1364-2005.pdf
*
*******************************************************/
constexpr bit_value_t l_buf[4] = {
/* 0 1 x z <- a*/
_0,_1,_x,_x
};
_static_unused(l_buf)
constexpr bit_value_t l_not[4] = {
/* 0 1 x z <- a */
_1,_0,_x,_x
};
_static_unused(l_not)
constexpr bit_value_t is_unk[4] = {
/* 0 1 x z <- a*/
_0,_0,_1,_1
};
_static_unused(is_unk)
constexpr bit_value_t is_x_bit[4] = {
/* 0 1 x z <- a*/
_0,_0,_1,_0
};
_static_unused(is_x_bit)
constexpr bit_value_t is_z_bit[4] = {
/* 0 1 x z <- a*/
_0,_0,_0,_1
};
_static_unused(is_z_bit)
constexpr bit_value_t is_one_bit[4] = {
/* 0 1 x z <- a*/
_0,_1,_0,_0
};
_static_unused(is_one_bit)
constexpr bit_value_t is_zero_bit[4] = {
/* 0 1 x z <- a*/
_1,_0,_0,_0
};
_static_unused(is_zero_bit)
constexpr bit_value_t l_and[4][4] = {
/* a / 0 1 x z <-b */
/* 0 */ {_0,_0,_0,_0},
/* 1 */ {_0,_1,_x,_x},
/* x */ {_0,_x,_x,_x},
/* z */ {_0,_x,_x,_x}
};
_static_unused(l_and)
constexpr bit_value_t l_nand[4][4] = unroll_2d_invert(l_and);
_static_unused(l_nand)
constexpr bit_value_t l_or[4][4] = {
/* a / 0 1 x z <-b */
/* 0 */ {_0,_1,_x,_x},
/* 1 */ {_1,_1,_1,_1},
/* x */ {_x,_1,_x,_x},
/* z */ {_x,_1,_x,_x}
};
_static_unused(l_or)
constexpr bit_value_t l_nor[4][4] = unroll_2d_invert(l_or);
_static_unused(l_nor)
constexpr bit_value_t l_xor[4][4] = {
/* a / 0 1 x z <-b */
/* 0 */ {_0,_1,_x,_x},
/* 1 */ {_1,_0,_x,_x},
/* x */ {_x,_x,_x,_x},
/* z */ {_x,_x,_x,_x}
};
_static_unused(l_xor)
constexpr bit_value_t l_xnor[4][4] = unroll_2d_invert(l_xor);
_static_unused(l_xnor)
/*****************************************************
* Tran NO SUPPORT FOR THESE YET
*/
constexpr bit_value_t l_notif1[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_z,_1,_x,_x},
/* 1 */ {_z,_0,_x,_x},
/* x */ {_z,_x,_x,_x},
/* z */ {_z,_x,_x,_x}
};
_static_unused(l_notif1)
constexpr bit_value_t l_notif0[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_1,_z,_x,_x},
/* 1 */ {_0,_z,_x,_x},
/* x */ {_x,_z,_x,_x},
/* z */ {_x,_z,_x,_x}
};
_static_unused(l_notif0)
constexpr bit_value_t l_bufif1[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_z,_0,_x,_x},
/* 1 */ {_z,_1,_x,_x},
/* x */ {_z,_x,_x,_x},
/* z */ {_z,_x,_x,_x}
};
_static_unused(l_bufif1)
constexpr bit_value_t l_bufif0[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_0,_z,_x,_x},
/* 1 */ {_1,_z,_x,_x},
/* x */ {_x,_z,_x,_x},
/* z */ {_x,_z,_x,_x}
};
_static_unused(l_bufif0)
/* cmos gates */
constexpr bit_value_t l_rpmos[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_0,_z,_x,_x},
/* 1 */ {_1,_z,_x,_x},
/* x */ {_x,_z,_x,_x},
/* z */ {_z,_z,_z,_z}
};
_static_unused(l_rpmos)
constexpr bit_value_t l_rnmos[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_z,_0,_x,_x},
/* 1 */ {_z,_1,_x,_x},
/* x */ {_z,_x,_x,_x},
/* z */ {_z,_z,_z,_z}
};
_static_unused(l_rnmos)
constexpr bit_value_t l_nmos[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_z,_0,_x,_x},
/* 1 */ {_z,_1,_x,_x},
/* x */ {_z,_x,_x,_x},
/* z */ {_z,_z,_z,_z}
};
_static_unused(l_nmos)
// see table 5-21 p:54 IEEE 1364-2005
constexpr bit_value_t l_ternary[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_0,_x,_x,_x},
/* 1 */ {_x,_1,_x,_x},
/* x */ {_x,_x,_x,_x},
/* z */ {_x,_x,_x,_x}
};
_static_unused(l_ternary)
/*****
* these extend the library and simplify the process
*/
/* helper */
constexpr bit_value_t l_unk[4][4] = {
/* in / 0 1 x z <-control */
/* 0 */ {_x,_x,_x,_x},
/* 1 */ {_x,_x,_x,_x},
/* x */ {_x,_x,_x,_x},
/* z */ {_x,_x,_x,_x}
};
_static_unused(l_unk)
constexpr bit_value_t l_case_eq[4][4] = {
/* a / 0 1 x z <-b */
/* 0 */ {_1,_0,_0,_0},
/* 1 */ {_0,_1,_0,_0},
/* x */ {_0,_0,_1,_0},
/* z */ {_0,_0,_0,_1}
};
_static_unused(l_case_eq)
constexpr bit_value_t l_lt[4][4] = {
/* a / 0 1 x z <-b */
/* 0 */ {_0,_1,_x,_x},
/* 1 */ {_0,_0,_x,_x},
/* x */ {_x,_x,_x,_x},
/* z */ {_x,_x,_x,_x}
};
_static_unused(l_lt)
constexpr bit_value_t l_gt[4][4] = {
/* a / 0 1 x z <-b */
/* 0 */ {_0,_0,_x,_x},
/* 1 */ {_1,_0,_x,_x},
/* x */ {_x,_x,_x,_x},
/* z */ {_x,_x,_x,_x}
};
_static_unused(l_gt)
constexpr bit_value_t l_eq[4][4] = unroll_2d(l_xnor);
_static_unused(l_eq)
constexpr bit_value_t l_sum[4][4][4] = {
/* c_in */
/* 0 */ unroll_2d(l_xor),
/* 1 */ unroll_2d(l_xnor),
/* x */ unroll_2d(l_unk),
/* z */ unroll_2d(l_unk)
};
_static_unused(l_sum)
constexpr bit_value_t l_carry[4][4][4] = {
/* c_in */
/* 0 */ unroll_2d(l_and),
/* 1 */ unroll_2d(l_or),
/* x */ unroll_2d(l_ternary),
/* z */ unroll_2d(l_ternary)
};
_static_unused(l_carry)
constexpr bit_value_t l_half_carry[4][4] = unroll_2d(l_carry[_0]);
_static_unused(l_half_carry)
constexpr bit_value_t l_half_sum[4][4] = unroll_2d(l_sum[_0]);
_static_unused(l_half_sum)
static char bit_to_c(bit_value_t bit)
{
switch(bit)
{
case _0: return '0';
case _1: return '1';
case _z: return 'z';
default: return 'x';
}
}
static bit_value_t c_to_bit(char c)
{
switch(tolower(c))
{
case '0': return _0;
case '1': return _1;
case 'z': return _z;
default: return _x;
}
}
template<typename T>
class BitFields
{
private :
T bits = static_cast<T>(_All_x);
template<typename Addr_t>
size_t get_bit_location(Addr_t address)
{
size_t current_address = static_cast<size_t>(address);
current_address %= this->size();
current_address <<= 1;
return current_address;
}
public :
BitFields(bit_value_t init_v)
{
this->bits = static_cast<T>(
(_0 == init_v)? _All_0:
(_1 == init_v)? _All_1:
(_z == init_v)? _All_z:
_All_x
);
}
template<typename Addr_t>
bit_value_t get_bit(Addr_t address)
{
auto result = this->bits >> this->get_bit_location(address);
result &= 0x3;
return static_cast<bit_value_t>(result);
}
template<typename Addr_t>
void set_bit(Addr_t address, bit_value_t value)
{
size_t real_address = this->get_bit_location(address);
T set_value = static_cast<T>(value);
set_value = static_cast<T>(set_value << real_address);
T mask = static_cast<T>(0x3);
mask = static_cast<T>(mask << real_address);
mask = static_cast<T>(~(mask));
this->bits = static_cast<T>(this->bits & mask);
this->bits = static_cast<T>(this->bits | set_value);
}
/**
* get 16 real bit (8 verilog bits) as 8 bit (char)
*/
template<typename Addr_t>
char get_as_char(Addr_t address)
{
size_t start = (8*(address));
size_t end = (8*(address+1))-1;
char value = 0;
for(size_t i = start; i <= end; i++)
{
value += (((this->get_bit(i))? 1: 0) << i);
}
return value;
}
static size_t size()
{
return (sizeof(T)<<2); // 8 bit in a byte, 2 bits for a verilog bits = 4 bits in a byte, << 2 = sizeof x 4
}
};
// #define DEBUG_V_BITS
/*****
* we use large array since we process the bits in chunks
*/
class VerilogBits
{
private:
std::vector<BitFields<veri_internal_bits_t>> bits;
size_t bit_size = 0;
size_t to_index(size_t address)
{
return ( address / BitFields<veri_internal_bits_t>::size() );
}
size_t list_size()
{
return this->bits.size();
}
public:
VerilogBits()
{
this->bit_size = 0;
this->bits = std::vector<BitSpace::BitFields<veri_internal_bits_t>>();
}
VerilogBits(size_t data_size, bit_value_t value_in)
{
this->bit_size = data_size;
this->bits = std::vector<BitSpace::BitFields<veri_internal_bits_t>>();
size_t bitfield_count = (this->bit_size / BitFields<veri_internal_bits_t>::size()) +1;
for(size_t i=0; i<bitfield_count; i++)
{
this->bits.push_back(BitSpace::BitFields<veri_internal_bits_t>(value_in));
}
}
VerilogBits(VerilogBits *other)
{
this->bit_size = other->size();
this->bits = other->get_internal_bitvector();
}
size_t size()
{
return this->bit_size;
}
std::vector<BitFields<veri_internal_bits_t>> get_internal_bitvector()
{
return this->bits;
}
BitFields<veri_internal_bits_t> *get_bitfield(size_t index)
{
#ifdef DEBUG_V_BITS
if (index >= this->bits.size() )
{
std::cerr << "Bit array indexing out of bounds " << index << " but size is " << this->bit_size << std::endl;
std::abort();
}
#endif
return (&this->bits[index]);
}
bit_value_t get_bit(size_t address)
{
#ifdef DEBUG_V_BITS
if (address >= this->bit_size )
{
std::cerr << "Bit index array out of bounds " << address << " but size is " << this->bit_size << std::endl;
std::abort();
}
#endif
return (this->get_bitfield(to_index(address))->get_bit(address));
}
void set_bit(size_t address, bit_value_t value)
{
#ifdef DEBUG_V_BITS
if (address >= this->bit_size )
{
std::cerr << "Bit index array out of bounds " << address << " but size is " << this->bit_size << std::endl;
std::abort();
}
#endif
(this->get_bitfield(to_index(address))->set_bit(address, value));
}
std::string to_string(bool big_endian)
{
// make a big endian string
std::string to_return = "";
for(size_t address=0x0; address < this->size(); address++)
{
char value = BitSpace::bit_to_c(this->get_bit(address));
if(big_endian)
{
to_return.push_back(value);
}
else
{
to_return.insert(0,1,value);
}
}
return to_return;
}
std::string to_printable()
{
std::string to_return = "";
for(size_t i=0; i< this->size(); i += 8)
{
to_return.insert(0,1,this->get_bitfield(to_index(i))->get_as_char(i));
}
return to_return;
}
bool has_unknowns()
{
for(size_t address=0x0; address < this->size(); address++)
{
if(is_unk[this->get_bit(address)])
return true;
}
return false;
}
bool is_only_z()
{
for(size_t address=0x0; address < this->size(); address++)
{
if(! is_z_bit[this->get_bit(address)])
return false;
}
return true;
}
bool is_only_x()
{
for(size_t address=0x0; address < this->size(); address++)
{
if(! is_x_bit[this->get_bit(address)])
return false;
}
return true;
}
bool is_true()
{
for(size_t address=0x0; address < this->size(); address++)
{
if(is_one_bit[this->get_bit(address)])
return true;
}
return false;
}
bool is_false()
{
for(size_t address=0x0; address < this->size(); address++)
{
if(! is_zero_bit[this->get_bit(address)])
return false;
}
return true;
}
/**
* Unary Reduction operations
* This is Msb to Lsb on purpose, as per specs
*/
VerilogBits bitwise_reduce(const bit_value_t lut[4][4])
{
bit_value_t result = this->get_bit(this->size()-1);
for(size_t i=this->size()-2; i < this->size(); i--)
{
result = lut[result][this->get_bit(i)];
}
return VerilogBits(1, result);
}
VerilogBits invert()
{
VerilogBits other(this->bit_size, _0);
for(size_t i=0; i<this->size(); i++)
other.set_bit(i, BitSpace::l_not[this->get_bit(i)]);
return other;
}
VerilogBits twos_complement()
{
BitSpace::bit_value_t previous_carry = BitSpace::_1;
VerilogBits other(this->bit_size, _0);
for(size_t i=0; i<this->size(); i++)
{
BitSpace::bit_value_t not_bit_i = BitSpace::l_not[this->get_bit(i)];
other.set_bit(i,BitSpace::l_half_sum[previous_carry][not_bit_i]);
previous_carry = BitSpace::l_half_carry[previous_carry][not_bit_i];
}
return other;
}
/**
* size of zero compact to the least amount of bits
*/
VerilogBits resize(BitSpace::bit_value_t pad, size_t new_size)
{
/**
* find the new size
*/
if(new_size == 0)
{
size_t last_bit_id = this->size() - 1;
size_t next_bit_id = last_bit_id -1;
while(next_bit_id < this->size()-1)
{
BitSpace::bit_value_t current = this->get_bit(last_bit_id);
BitSpace::bit_value_t next = this->get_bit(next_bit_id);
if(current == next && current == pad)
{
last_bit_id--;
next_bit_id--;
}
else
{
break; /* it down. oh. oh! */
}
}
new_size = last_bit_id+1;
}
VerilogBits other(new_size, BitSpace::_0);
size_t i = 0;
while(i < this->size() && i < new_size)
{
other.set_bit(i, this->get_bit(i));
i++;
}
while(i < new_size)
{
other.set_bit(i, pad);/* <- ask Eve about it */
i++;
}
return other;
}
/**
* replicates the bitset n times
*/
VerilogBits replicate(size_t n_times)
{
size_t old_size = this->size();
size_t new_size = old_size * n_times;
VerilogBits other(new_size, BitSpace::_0);
for(size_t i = 0; i < new_size; i += 1)
{
other.set_bit(i, this->get_bit( i%old_size ));
}
return other;
}
};
}
//template<size_t bit_size>
class VNumber
{
private:
bool sign = false;
bool defined_size = false;
BitSpace::VerilogBits bitstring = BitSpace::VerilogBits(1, BitSpace::_x);
VNumber(BitSpace::VerilogBits other_bitstring, bool other_defined_size, bool other_sign)
{
bitstring = BitSpace::VerilogBits(other_bitstring);
sign = other_sign;
defined_size = other_defined_size;
}
VNumber insert(VNumber &other, size_t index_to_insert_at, size_t insertion_size)
{
assert_Werr(other.is_defined_size() && this->is_defined_size()
,"Size must be defined on both operand for insertion");
VNumber new_bitstring(this->size() + insertion_size, BitSpace::_0, this->is_signed() && other.is_signed(), true);
size_t index = 0;
for(size_t i=0; i < this->size() && i < index_to_insert_at; i += 1, index +=1)
new_bitstring.set_bit_from_lsb(index, this->get_bit_from_lsb( i ));
for(size_t i=0; i < insertion_size; i += 1, index +=1)
new_bitstring.set_bit_from_lsb(index, other.get_bit_from_lsb( i ));
for(size_t i=index_to_insert_at; i < this->size(); i += 1, index +=1)
new_bitstring.set_bit_from_lsb(index, this->get_bit_from_lsb( i ));
return new_bitstring;
}
public:
VNumber()
{
this->sign = false;
this->bitstring = BitSpace::VerilogBits(1, BitSpace::_x);
this->defined_size = false;
}
VNumber(VNumber&&) = default;
VNumber& operator=(VNumber&&) = default;
VNumber& operator=(const VNumber& other) = default;
VNumber(const VNumber& other)
{
this->sign = other.sign;
this->bitstring = other.bitstring;
this->defined_size = other.defined_size;
}
VNumber(VNumber other, size_t length)
{
this->sign = other.sign;
this->bitstring = other.bitstring.resize(other.get_padding_bit(),length);
// TODO this->defined_size = true?????;
}
VNumber(const std::string& verilog_string)
{
set_value(verilog_string);
}
VNumber(int64_t numeric_value)
{
set_value(numeric_value);
}
VNumber(size_t len, BitSpace::bit_value_t initial_bits, bool input_sign, bool this_defined_size)
{
this->bitstring = BitSpace::VerilogBits(len, initial_bits);
this->sign = input_sign;
this->defined_size = this_defined_size;
}
/***
* getters to 64 bit int
*/
int64_t get_value()
{
using integer_t = int64_t;
size_t bit_size = 8*sizeof(integer_t);
assert_Werr( (! this->bitstring.has_unknowns() ) ,
"Invalid Number contains dont care values. number: " + this->bitstring.to_string(false)
);
size_t end = this->size();
if(end > bit_size)
{
printf(" === Warning: Returning a 64 bit integer from a larger bitstring (%zu). The bitstring will be truncated\n", bit_size);
end = bit_size;
}
integer_t result = 0;
BitSpace::bit_value_t pad = this->get_padding_bit(); // = this->is_negative();
for(size_t bit_index = 0; bit_index < end; bit_index++)
{
integer_t current_bit = static_cast<integer_t>(pad);
if(bit_index < this->size())
current_bit = this->bitstring.get_bit(bit_index);
result |= (current_bit << bit_index);
}
return result;
}
// convert lsb_msb bitstring to verilog
std::string to_full_string()
{
std::string out = this->to_bit_string();
size_t len = this->bitstring.size();
return std::to_string(len) + ((this->is_signed())? "\'sb": "\'b") + out;
}
std::string to_bit_string()
{
std::string out = this->bitstring.to_string(false);
return out;
}
std::string to_printable()
{
std::string out = this->bitstring.to_printable();
return out;
}
/***
* setters
*/
void set_value(const std::string& input)
{
if(!input.size())
{
return;
}
std::string verilog_string(input);
/**
* set defaults
*/
size_t bitsize = 32; // 32 bit is the fall back
this->defined_size = false; // the size is undefined unless otherwise specified
size_t radix = 0; // the radix is unknown to start with
this->sign = false; // we treat everything as unsigned unless specified
// if this is a string
if(verilog_string[0] == '\"')
{
assert_Werr(verilog_string.size() >= 2,
"Malformed input String for VNumber, only open quote" + verilog_string);
assert_Werr(verilog_string.back() == '\"',
"Malformed input String for VNumber, expected closing quotes" + verilog_string);
verilog_string.erase(0,1);
verilog_string.pop_back();
size_t string_size = verilog_string.size();
if(string_size == 0)
string_size = 1;
bitsize = string_size * 8;
this->defined_size = true;
radix = 256;
}
else
{
size_t loc = verilog_string.find("\'");
if(loc == std::string::npos)
{
verilog_string.insert(0, "\'sd");
loc = 0;
}
if(loc != 0)
{
std::string bit_length_char = verilog_string.substr(0, loc);
bitsize = strtoul(bit_length_char.c_str(), nullptr, 10);
this->defined_size = true;
}
if(std::tolower(verilog_string[loc+1]) == 's')
{
this->sign = true;
}
char base = static_cast<char>(std::tolower(verilog_string[loc+1+sign]));
switch(base)
{
case 'b': radix = 2; break; // binary
case 'o': radix = 8; break; // octal
case 'd': radix = 10; break; // decimal
case 'h': radix = 16; break; // hexadecimal
default:
assert_Werr( false,
"Invalid radix base for number: " + std::string(1,base)
);
break;
}
//remove underscores
verilog_string = verilog_string.substr(loc+2+sign);
verilog_string.erase(std::remove(verilog_string.begin(), verilog_string.end(), '_'), verilog_string.end());
//little endian bitstring string
}
std::string temp_bitstring = string_of_radix_to_bitstring(verilog_string, radix);
char pad = temp_bitstring[0];
if(!this->sign && pad == '1')
{
pad = '0';
}
// convert the bits to the internal data struct (bit at index 0 in string is msb since string go from msb to lsb)
BitSpace::VerilogBits new_bitstring(temp_bitstring.size(), BitSpace::_0);
size_t counter = temp_bitstring.size()-1;
for(char in: temp_bitstring)
{
new_bitstring.set_bit(counter--,BitSpace::c_to_bit(in));
}
this->bitstring = new_bitstring.resize(BitSpace::c_to_bit(pad), bitsize);
}
void set_value(int64_t in)
{
this->set_value(std::to_string(in));
}
size_t msb_index()
{
return this->bitstring.size()-1;
}
/****
* bit twiddling functions
*/
BitSpace::bit_value_t get_bit_from_msb(size_t index)
{
return this->bitstring.get_bit(msb_index()-index);
}
BitSpace::bit_value_t get_bit_from_lsb(size_t index)
{
if (index < this->size())
return this->bitstring.get_bit(index);
else
return this->get_padding_bit();
}
void set_bit_from_msb(size_t index, BitSpace::bit_value_t val)
{
this->bitstring.set_bit(msb_index()-index, val);
}
void set_bit_from_lsb(size_t index, BitSpace::bit_value_t val)
{
this->bitstring.set_bit(index, val);
}
/***
* other
*/
size_t size()
{
return this->bitstring.size();
}
BitSpace::bit_value_t get_padding_bit()
{
return this->is_negative()? BitSpace::_1:BitSpace::_0;
}
bool is_signed() const
{
return this->sign;
}
bool is_defined_size()
{
return this->defined_size;
}
bool is_negative()
{
return ( this->get_bit_from_msb(0) == BitSpace::_1 && this->sign );
}
bool is_dont_care_string()
{
return this->bitstring.has_unknowns();
}
bool is_z()
{
return this->bitstring.is_only_z();
}
bool is_x()
{
return this->bitstring.is_only_x();
}
bool is_true()
{
return this->bitstring.is_true();
}
bool is_false()
{
return this->bitstring.is_false();
}
VNumber twos_complement()
{
return VNumber(this->bitstring.twos_complement(),this->defined_size,this->sign);
}
VNumber to_signed()
{
return VNumber(this->bitstring,this->defined_size,true);
}
VNumber to_unsigned()
{
return VNumber(this->bitstring,this->defined_size,false);
}
VNumber invert()
{
return VNumber(this->bitstring.invert(),this->defined_size,this->sign);
}
VNumber bitwise_reduce(const BitSpace::bit_value_t lut[4][4])
{
return VNumber(this->bitstring.bitwise_reduce(lut),this->defined_size,false);
}
/**
* Binary Reduction operations
*/
VNumber bitwise(VNumber& b, const BitSpace::bit_value_t lut[4][4])
{
size_t std_length = std::max(this->size(), b.size());
const BitSpace::bit_value_t pad_a = this->get_padding_bit();
const BitSpace::bit_value_t pad_b = b.get_padding_bit();
VNumber result(std_length, BitSpace::_x, false, this->is_defined_size() && b.is_defined_size() );
for(size_t i=0; i < result.size(); i++)
{
BitSpace::bit_value_t bit_a = pad_a;
if(i < this->size())
bit_a = this->get_bit_from_lsb(i);
BitSpace::bit_value_t bit_b = pad_b;
if(i < b.size())
bit_b = b.get_bit_from_lsb(i);
result.set_bit_from_lsb(i, lut[bit_a][bit_b]);
}
return result;
}
VNumber replicate(int64_t n_times_replicate)
{
assert_Werr(n_times_replicate > 0,
"Cannot replicate bitstring less than 1 times");
size_t n_times_unsigned = static_cast<size_t>(n_times_replicate);
return VNumber(this->bitstring.replicate(n_times_unsigned),true,this->sign);
}
VNumber insert_at_lsb(VNumber &other)
{
return this->insert(other, 0, other.size());
}
VNumber insert_at_msb(VNumber &other)
{
return this->insert(other, this->size(), other.size());
}
};
#endif