2022-06-06 21:22:18 -04:00
|
|
|
#include "Util.h"
|
|
|
|
#include "Golay24.h"
|
|
|
|
|
2022-07-04 17:03:07 -04:00
|
|
|
namespace modemm17 {
|
2022-06-06 21:22:18 -04:00
|
|
|
|
|
|
|
std::array<Golay24::SyndromeMapEntry, Golay24::LUT_SIZE> Golay24::LUT = Golay24::make_lut();
|
|
|
|
|
|
|
|
Golay24::Golay24()
|
|
|
|
{}
|
|
|
|
|
|
|
|
uint32_t Golay24::syndrome(uint32_t codeword)
|
|
|
|
{
|
|
|
|
codeword &= 0xffffffl;
|
|
|
|
|
|
|
|
for (size_t i = 0; i != 12; ++i)
|
|
|
|
{
|
|
|
|
if (codeword & 1) {
|
|
|
|
codeword ^= POLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
codeword >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (codeword << 12);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Golay24::parity(uint32_t codeword)
|
|
|
|
{
|
|
|
|
return popcount(codeword) & 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Golay24::SyndromeMapEntry Golay24::makeSyndromeMapEntry(uint64_t val)
|
|
|
|
{
|
|
|
|
return SyndromeMapEntry{uint32_t(val >> 16), uint16_t(val & 0xFFFF)};
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t Golay24::makeSME(uint64_t syndrome, uint32_t bits)
|
|
|
|
{
|
|
|
|
return (syndrome << 24) | (bits & 0xFFFFFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Golay24::encode23(uint16_t data)
|
|
|
|
{
|
|
|
|
// data &= 0xfff;
|
|
|
|
uint32_t codeword = data;
|
|
|
|
|
|
|
|
for (size_t i = 0; i != 12; ++i)
|
|
|
|
{
|
|
|
|
if (codeword & 1) {
|
|
|
|
codeword ^= POLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
codeword >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return codeword | (data << 11);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Golay24::encode24(uint16_t data)
|
|
|
|
{
|
|
|
|
auto codeword = encode23(data);
|
|
|
|
return ((codeword << 1) | parity(codeword));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Golay24::decode(uint32_t input, uint32_t& output)
|
|
|
|
{
|
|
|
|
auto syndrm = syndrome(input >> 1);
|
|
|
|
|
|
|
|
auto it = std::lower_bound(
|
|
|
|
LUT.begin(),
|
|
|
|
LUT.end(),
|
|
|
|
syndrm,
|
|
|
|
[](const SyndromeMapEntry& sme, uint32_t val){
|
|
|
|
return (sme.a >> 8) < val;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
if ((it->a >> 8) == syndrm)
|
|
|
|
{
|
|
|
|
// Build the correction from the compressed entry.
|
|
|
|
auto correction = ((((it->a & 0xFF) << 16) | it->b) << 1);
|
|
|
|
// Apply the correction to the input.
|
|
|
|
output = input ^ correction;
|
|
|
|
// Only test parity for 3-bit errors.
|
|
|
|
return popcount(syndrm) < 3 || !parity(output);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::array<Golay24::SyndromeMapEntry, Golay24::LUT_SIZE> Golay24::make_lut()
|
|
|
|
{
|
|
|
|
constexpr size_t VECLEN=23;
|
|
|
|
Golay24_detail::array<uint64_t, LUT_SIZE> result{};
|
|
|
|
|
|
|
|
size_t index = 0;
|
|
|
|
result[index++] = makeSME(syndrome(0), 0);
|
|
|
|
|
|
|
|
for (size_t i = 0; i != VECLEN; ++i)
|
|
|
|
{
|
|
|
|
auto v = (1 << i);
|
|
|
|
result[index++] = makeSME(syndrome(v), v);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i != VECLEN - 1; ++i)
|
|
|
|
{
|
|
|
|
for (size_t j = i + 1; j != VECLEN; ++j)
|
|
|
|
{
|
|
|
|
auto v = (1 << i) | (1 << j);
|
|
|
|
result[index++] = makeSME(syndrome(v), v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i != VECLEN - 2; ++i)
|
|
|
|
{
|
|
|
|
for (size_t j = i + 1; j != VECLEN - 1; ++j)
|
|
|
|
{
|
|
|
|
for (size_t k = j + 1; k != VECLEN; ++k)
|
|
|
|
{
|
|
|
|
auto v = (1 << i) | (1 << j) | (1 << k);
|
|
|
|
result[index++] = makeSME(syndrome(v), v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = Golay24_detail::sort(result);
|
|
|
|
|
|
|
|
std::array<SyndromeMapEntry, LUT_SIZE> tmp;
|
|
|
|
for (size_t i = 0; i != LUT_SIZE; ++i)
|
|
|
|
{
|
|
|
|
tmp[i] = makeSyndromeMapEntry(result[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2022-07-04 17:03:07 -04:00
|
|
|
} // modemm17
|