Supermodel/Src/Util/BitRegister.cpp

229 lines
5.8 KiB
C++

#include "Util/BitRegister.h"
#include <cstring>
#include <cctype>
namespace Util
{
uint8_t BitRegister::GetLeftMost() const
{
return m_bits.empty() ? m_no_data : m_bits.front();
}
uint8_t BitRegister::GetRightMost() const
{
return m_bits.empty() ? m_no_data : m_bits.back();
}
size_t BitRegister::HexStart(const std::string &value)
{
if (value.length() > 1 && value[0] == '$')
return 1;
if (value.length() > 2 && value[0] == '0' && (value[1] == 'x' || value[1] == 'X'))
return 2;
return std::string::npos;
}
size_t BitRegister::BinStart(const std::string &value)
{
if (value.length() > 1 && value[0] == '%')
return 1;
if (value.length() > 2 && value[0] == '0' && (value[1] == 'b' || value[1] == 'B'))
return 2;
return 0;
}
size_t BitRegister::CountBitsHex(const std::string &value, size_t startPos)
{
return 4 * (value.length() - startPos);
}
size_t BitRegister::CountBitsBin(const std::string &value, size_t startPos)
{
return value.length() - startPos;
}
// Shift a bit into the right side, growing the vector by 1
void BitRegister::ShiftInRight(uint8_t bit)
{
m_bits.push_back(!!bit);
}
// Shift a bit into the left side, growing the vector by 1
void BitRegister::ShiftInLeft(uint8_t bit)
{
m_bits.push_back(0);
ShiftRight(1);
m_bits[0] = !!bit;
}
// Shift left by 1, returning ejected bit (shrinks vector)
uint8_t BitRegister::ShiftOutLeft()
{
uint8_t ejected = GetLeftMost();
ShiftOutLeft(1);
return ejected;
}
// Shift left and lose bits (shrinks vector)
void BitRegister::ShiftOutLeft(size_t count)
{
if (count >= m_bits.size())
{
// All bits shifted out
m_bits.clear();
return;
}
// Shift and resize
memmove(m_bits.data(), m_bits.data() + count, m_bits.size() - count);
m_bits.resize(m_bits.size() - count);
}
// Shift right by 1, returning ejected bit (shrinks vector)
uint8_t BitRegister::ShiftOutRight()
{
uint8_t ejected = GetRightMost();
ShiftOutRight(1);
return ejected;
}
// Shift right and lose bits (shrinks vector)
void BitRegister::ShiftOutRight(size_t count)
{
// Shifting right means we lose lower bits (which are higher in the
// vector), which means we just trim the vector from the right side
if (count >= m_bits.size())
{
m_bits.clear();
return;
}
m_bits.resize(m_bits.size() - count);
}
// Shift right and lose right-most bits, shifting in new bits from left to
// preserve vector size
void BitRegister::ShiftRight(size_t count)
{
if (count < m_bits.size())
{
// Shift over bits to the right
memmove(m_bits.data() + count, m_bits.data(), m_bits.size() - count);
}
// Fill in the left with "no data"
memset(m_bits.data(), m_no_data, count);
}
// Shift left and lose left-most bits, shifting in new bits from right to
// preserve vector size
void BitRegister::ShiftLeft(size_t count)
{
if (count < m_bits.size())
{
// Shift over bits to the left
memmove(m_bits.data(), m_bits.data() + count, m_bits.size() - count);
}
// Fill in the right with "no data"
memset(m_bits.data() + m_bits.size() - count, m_no_data, count);
}
void BitRegister::Reset()
{
m_bits.clear();
}
// Set single bit, indexed from left, without expanding vector
void BitRegister::SetBit(size_t bitPos, uint8_t value)
{
if (bitPos < m_bits.size())
m_bits[bitPos] = !!value;
}
// Insert value, indexed from left, without expanding vector
void BitRegister::Insert(size_t bitPos, const std::string &value)
{
size_t hexStart = HexStart(value);
if (hexStart != std::string::npos)
{
for (size_t i = hexStart; i < value.length(); i++)
{
char digit = tolower(value[i]);
uint8_t nibble = 0;
if (isxdigit(digit))
nibble = (digit >= 'a') ? (digit - 'a' + 10) : (digit - '0');
SetBit(bitPos++, nibble & 8);
SetBit(bitPos++, nibble & 4);
SetBit(bitPos++, nibble & 2);
SetBit(bitPos++, nibble & 1);
}
}
else
{
for (size_t i = BinStart(value); i < value.length(); i++)
{
SetBit(bitPos++, value[i] == '0' ? 0 : 1);
}
}
}
void BitRegister::Set(const std::string &value)
{
size_t hexStart = HexStart(value);
size_t binStart = BinStart(value);
if (hexStart != std::string::npos)
m_bits.resize(CountBitsHex(value, hexStart));
else
m_bits.resize(CountBitsBin(value, binStart));
Insert(0, value);
}
void BitRegister::SetZeros(size_t count)
{
m_bits.resize(count);
memset(m_bits.data(), 0, count);
}
void BitRegister::SetOnes(size_t count)
{
m_bits.resize(count);
memset(m_bits.data(), 1, count);
}
void BitRegister::SetNoBitValue(uint8_t bit)
{
m_no_data = bit == 0 ? 0 : 1;
}
std::string BitRegister::ToBinaryString() const
{
if (Empty())
return std::string("");
std::string out(Size(), '0');
for (size_t i = 0; i < Size(); i++)
{
out[i] = m_bits[i] == 0 ? '0' : '1';
}
return out;
}
std::ostream &operator<<(std::ostream &os, const BitRegister &reg)
{
if (reg.Empty())
{
os << "[ empty ]";
return os;
}
char *buf = new char[reg.Size() + 1];
buf[reg.Size()] = 0;
for (size_t i = 0; i < reg.Size(); i++)
{
buf[i] = reg.m_bits[i] == 0 ? '0' : '1';
}
os << "[ " << reg.Size() << ": " << buf << " ]";
delete [] buf;
return os;
}
} // Util