读取 32 位字存储器中连续的 3 个字节
Reading successive 3 bytes in a 32-bit word memory
我有一个 32 位字可寻址内存,我的数据部分可以在内存中的任何字节开始和结束。
假设我的数据部分从字 0x3 的字节 2(0 是最低字节)开始。
然后我必须从字 0x3 的字节 2 和字节 3 以及字 0x4 的字节 0 读取数据。在此之后,我必须读取字 0x4 的字节 1、2 和 3,依此类推......并且仅当我将所有 3 个字节都设为零或我的数据部分结束时才停止。下一个部分有可扩展的边界,它可以移动到我的数据部分,所以结束字或字节不固定。
您对解决此问题的最佳算法有什么建议吗?我想出了一种方法来创建两个总共 24 位的掩码,我在单词之间移动它们,但这似乎有点过分并且给了我很大的代码。我试图用尽可能少的 C 指令来解决它。期待您的建议。
我不太明白你所说的下一节、可扩展边界和它可以移动。忽略下面的代码应该可以读取数据:
int start_word = 3;
int start_byte = 2;
int end_word = 100;
uint8_t* p = data + start_word * 4 + start_byte;
uint8_t* end = data + end_word * 100;
while (p + 3 <= end) { // 3 more bytes must be available
uint8_t b0 = *p++;
uint8_t b1 = *p++;
uint8_t b2 = *p++;
if (b0 == 0 && b1 == 0 && b2 == 0)
break;
// do something with the 3 bytes
}
想法是不要太在意单词,按字节工作。
从你的陈述来看,这意味着你一次只能读取 32 位字,不能读取 16 位或 8 位,这也意味着你不必 think/talk 关于对齐。
就像支持字节可寻址内存的处理器一样,如果你有一个地址 0x1002 并且你有一些 24 位的项目,那么你可以用同样的方式实现它
0x1002 = 0b0001000000000010 低两位描述字中的字节 高位描述字 number/address 0b00010000000000 0b10 因此字地址 0x400 从字节 2 开始(字节顺序当然是一个因素,假设很少)。您还知道 4 - 0b10 = 2 表示该单词中还剩下两个字节,如果您需要第三个字节,则从下一个单词的偏移量 0 开始。
所以你可以做类似这个未经测试的代码:
unsigned int get24 ( unsigned int x )
{
unsigned int ra;
unsigned int ret;
unsigned int wa;
unsigned int shift;
unsigned int rb;
ret=0;
wa=x>>2;
shift=(x&3)<<3;
rb=load32(wa);
for(ra=0;ra<3;ra++)
{
ret<<=8;
ret|=(rb>>shift)&0xFF;
shift+=8;
if(shift>=32)
{
wa++;
rb=load32(wa);
shift=0;
}
}
}
你可以在另一个答案中采用基于字节的方法,但你必须确保编译器知道你基于字的内存限制,它不能被允许进行字节读取(取决于体系结构),也不未对齐的访问(取决于架构)。
您可以尝试 table 基于
//0x00000000 0x00FFFFFF
//0x00000000 0xFFFFFF00
//0x000000FF 0xFFFF0000
//0x0000FFFF 0xFF000000
unsigned int al[4]={0,0,24,16};
unsigned int ar[4]={0,0,8,8};
unsigned int bl[4]={8,0,16,24};
unsigned int br[4]={8,8,16,24};
unsigned int wa;
unsigned int off;
unsigned int ra;
unsigned int rb;
unsigned int ret;
wa=byte_address>>2;
off=byte_address&3;
rb=load32(wa);
ret=(rb<<bl[off])>>br[off];
//ret=(rb<<bl[off])>>(off<<3);
if(off&2)
{
ra=load32(wa+1);
//ret|=(ra<<al[off])>>ar[off];
ret|=(ra<<al[off])>>8;
}
或跳table基础
wa=byte_address>>2;
rb=load32(wa);
//if(byte_address&0xC)
ra=load32(wa+1);
switch(byte_address&3)
{
case 0:
{
ret=(rb<<8)>>8;
break;
}
case 1:
{
ret=rb>>8;
break;
}
case 2:
{
ret=(rb<<16)>>16;
ret|=(ra<<24)>>8;
break;
}
case 3:
{
ret=(rb<<24)>>24;
ret|=(ra<<16)>>8;
break;
}
}
我有一个 32 位字可寻址内存,我的数据部分可以在内存中的任何字节开始和结束。
假设我的数据部分从字 0x3 的字节 2(0 是最低字节)开始。
然后我必须从字 0x3 的字节 2 和字节 3 以及字 0x4 的字节 0 读取数据。在此之后,我必须读取字 0x4 的字节 1、2 和 3,依此类推......并且仅当我将所有 3 个字节都设为零或我的数据部分结束时才停止。下一个部分有可扩展的边界,它可以移动到我的数据部分,所以结束字或字节不固定。
您对解决此问题的最佳算法有什么建议吗?我想出了一种方法来创建两个总共 24 位的掩码,我在单词之间移动它们,但这似乎有点过分并且给了我很大的代码。我试图用尽可能少的 C 指令来解决它。期待您的建议。
我不太明白你所说的下一节、可扩展边界和它可以移动。忽略下面的代码应该可以读取数据:
int start_word = 3;
int start_byte = 2;
int end_word = 100;
uint8_t* p = data + start_word * 4 + start_byte;
uint8_t* end = data + end_word * 100;
while (p + 3 <= end) { // 3 more bytes must be available
uint8_t b0 = *p++;
uint8_t b1 = *p++;
uint8_t b2 = *p++;
if (b0 == 0 && b1 == 0 && b2 == 0)
break;
// do something with the 3 bytes
}
想法是不要太在意单词,按字节工作。
从你的陈述来看,这意味着你一次只能读取 32 位字,不能读取 16 位或 8 位,这也意味着你不必 think/talk 关于对齐。
就像支持字节可寻址内存的处理器一样,如果你有一个地址 0x1002 并且你有一些 24 位的项目,那么你可以用同样的方式实现它
0x1002 = 0b0001000000000010 低两位描述字中的字节 高位描述字 number/address 0b00010000000000 0b10 因此字地址 0x400 从字节 2 开始(字节顺序当然是一个因素,假设很少)。您还知道 4 - 0b10 = 2 表示该单词中还剩下两个字节,如果您需要第三个字节,则从下一个单词的偏移量 0 开始。
所以你可以做类似这个未经测试的代码:
unsigned int get24 ( unsigned int x )
{
unsigned int ra;
unsigned int ret;
unsigned int wa;
unsigned int shift;
unsigned int rb;
ret=0;
wa=x>>2;
shift=(x&3)<<3;
rb=load32(wa);
for(ra=0;ra<3;ra++)
{
ret<<=8;
ret|=(rb>>shift)&0xFF;
shift+=8;
if(shift>=32)
{
wa++;
rb=load32(wa);
shift=0;
}
}
}
你可以在另一个答案中采用基于字节的方法,但你必须确保编译器知道你基于字的内存限制,它不能被允许进行字节读取(取决于体系结构),也不未对齐的访问(取决于架构)。
您可以尝试 table 基于
//0x00000000 0x00FFFFFF
//0x00000000 0xFFFFFF00
//0x000000FF 0xFFFF0000
//0x0000FFFF 0xFF000000
unsigned int al[4]={0,0,24,16};
unsigned int ar[4]={0,0,8,8};
unsigned int bl[4]={8,0,16,24};
unsigned int br[4]={8,8,16,24};
unsigned int wa;
unsigned int off;
unsigned int ra;
unsigned int rb;
unsigned int ret;
wa=byte_address>>2;
off=byte_address&3;
rb=load32(wa);
ret=(rb<<bl[off])>>br[off];
//ret=(rb<<bl[off])>>(off<<3);
if(off&2)
{
ra=load32(wa+1);
//ret|=(ra<<al[off])>>ar[off];
ret|=(ra<<al[off])>>8;
}
或跳table基础
wa=byte_address>>2;
rb=load32(wa);
//if(byte_address&0xC)
ra=load32(wa+1);
switch(byte_address&3)
{
case 0:
{
ret=(rb<<8)>>8;
break;
}
case 1:
{
ret=rb>>8;
break;
}
case 2:
{
ret=(rb<<16)>>16;
ret|=(ra<<24)>>8;
break;
}
case 3:
{
ret=(rb<<24)>>24;
ret|=(ra<<16)>>8;
break;
}
}