我想拉伸一个掩码,其中每个位代表4位拉伸掩码。 我正在寻找一个优雅的位操作来使用c ++和systemC进行拉伸
例如:
输入:
mask (32 bits) = 0x0000CF00
输出:
stretched mask (128 bits) = 0x00000000 00000000 FF00FFFF 00000000
只是为了澄清这个例子让我们看一下字节C:
0xC = 1100 after stretching: 1111111100000000 = 0xFF00
答案 0 :(得分:3)
以优雅的形式做到这一点并不容易。 简单模式可能是创建一个带有移位位的循环
sc_biguint<128> result = 0;
for(int i = 0; i < 32; i++){
if(bit_test(var, i)){
result +=0x0F;
}
result << 4;
}
答案 1 :(得分:3)
这是一种将16位掩码扩展为64位的方法,其中每位代表4位拉伸掩码:
uint64_t x = 0x000000000000CF00LL;
x = (x | (x << 24)) & 0x000000ff000000ffLL;
x = (x | (x << 12)) & 0x000f000f000f000fLL;
x = (x | (x << 6)) & 0x0303030303030303LL;
x = (x | (x << 3)) & 0x1111111111111111LL;
x |= x << 1;
x |= x << 2;
从底部16位的掩码开始。然后它将掩码的前8位移动到前32位,如下所示:
0000000000000000 0000000000000000 0000000000000000 ABCDEFGHIJKLMNOP
成为
0000000000000000 00000000ABCDEFGH 0000000000000000 00000000IJKLMNOP
然后它解决了将掩码从32位字的底部8位拉伸到顶部和底部32位的类似问题:
000000000000ABCD 000000000000EFGH 000000000000IJKL 000000000000MNOP
然后它在16内进行4位,依此类推,直到比特分散开来:
000A000B000C000D 000E000F000G000H 000I000J000K000L 000M000N000O000P
然后它&#34;涂抹&#34;它们通过对结果进行两次OR运算得到4位:
AAAABBBBCCCCDDDD EEEEFFFFGGGGHHHH IIIIJJJJKKKKLLLL MMMMNNNNOOOOPPPP
您可以通过添加额外的第一步将其扩展到128位,其中您将移位48位并使用128位常量进行掩码:
x = (x | (x << 48)) & 0x000000000000ffff000000000000ffffLLL;
您还必须通过重复位模式将其他常量拉伸到128位。但是(据我所知),没有办法在C ++中声明128位常量,但也许你可以用宏或其他东西(see this question)来实现。您也可以分别在顶部和底部16位使用64位版本制作128位版本。
如果加载掩蔽常数结果是一个困难或瓶颈,你可以使用移位和掩蔽从前一个生成每个:
uint64_t m = 0x000000ff000000ffLL;
m &= m >> 4; m |= m << 16; // gives 0x000f000f000f000fLL
m &= m >> 2; m |= m << 8; // gives 0x0303030303030303LL
m &= m >> 1; m |= m << 4; // gives 0x1111111111111111LL
答案 2 :(得分:2)
这对你有用吗?
#include <stdio.h>
long long Stretch4x(int input)
{
long long output = 0;
while (input & -input)
{
int b = (input & -input);
long long s = 0;
input &= ~b;
s = b*15;
while(b>>=1)
{
s <<= 3;
}
output |= s;
}
return output;
}
int main(void) {
int input = 0xCF00;
printf("0x%0x ==> 0x%0llx\n", input, Stretch4x(input));
return 0;
}
<强>输出强>:
0xcf00 ==> 0xff00ffff00000000
答案 3 :(得分:2)
其他解决方案都很好。但是,大多数它们比C ++更多。这个解决方案很简单:它使用std::bitset
并为每个输入位设置4位。
#include <bitset>
#include <iostream>
std::bitset<128>
starch_32 (const std::bitset<32> &input)
{
std::bitset<128> output;
for (size_t i = 0; i < input.size(); ++i) {
// If `input[N]` is `true`, set `output[N*4, N*4+4]` to true.
if (input.test (i)) {
const size_t output_index = i * 4;
output.set (output_index);
output.set (output_index + 1);
output.set (output_index + 2);
output.set (output_index + 3);
}
}
return output;
}
// Example with 0xC.
int main() {
std::bitset<32> input{0b1100};
auto result = starch_32 (input);
std::cout << "0x" << std::hex << result.to_ullong() << "\n";
}
答案 4 :(得分:0)
在x86上,您可以使用PDEP
intrinsic将16个掩码位移动到64位字的正确半字节(例如,每个半字节的低位),然后使用几个shift +或将它们涂抹在其余部分:
unsigned long x = _pdep_u64(m, 0x1111111111111111);
x |= x << 1;
x |= x << 2;
您也可以通过0xF
的单次乘法替换这两个OR和两个移位,这样可以完成相同的拖尾操作。
最后,您可以考虑使用SIMD方法:上面的samgak等解决方案应该自然地映射到SIMD。