代码之家  ›  专栏  ›  技术社区  ›  frank_010

在32位字存储器中连续读取3个字节

  •  0
  • frank_010  · 技术社区  · 6 年前

    我有一个32位字可寻址内存,我的数据段可以在内存中的任何字节开始和结束。

    让我们假设我的数据部分从字0x3的字节2(0是最低字节)开始。

    然后我必须从单词0x3的字节2和3以及单词0x4的字节0读取数据。在此之后,我必须读取单词0x4的字节1、2和3,以此类推。。。只有当我所有的3个字节都为零或我的数据段结束时才停止。下一个部分有可扩展的边界,它可以移动到我的数据部分,因此结尾的字或字节不是固定的。

    你对解决这个问题的最佳算法有什么建议吗。我想出了一种方法,可以创建两个总共24位的掩码,我可以在单词之间移动,但这似乎有些过分,给了我很大的代码。我试图用尽可能少的C指令来解决这个问题。期待您的建议。

    2 回复  |  直到 6 年前
        1
  •  1
  •   old_timer    6 年前

    从你的陈述中,这意味着你一次只能读32位单词,不能读16位或8位,这也意味着你不必思考/谈论对齐。

    就像支持字节可寻址内存的处理器一样,如果您有一个地址0x1002,并且您有一些24位的项,那么您可以用同样的方式实现它

    0x1002=0B00010000000000010低位描述单词中的字节,高位描述单词编号/地址0B000100000000000 0b10,因此单词地址0x400以字节2开头(endianness当然是一个因素,假设很少)。您还知道,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;
           }
        }
    }
    

    在另一个答案中,您可以采用基于字节的方法,但您必须确保编译器知道基于单词的内存限制,不能允许它进行字节读取(这取决于体系结构),也不能进行未对齐的访问(取决于体系结构)。

    您可以尝试基于表格

    //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;
    }
    

    或基于跳转表

    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;
        }
    }
    
        2
  •  0
  •   Ringo Store    6 年前

    我真的不明白你的意思 下一节 , 可扩展边界 它可以移动 . 忽略以下代码应该用于读取数据:

    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
    }
    

    我们的想法是不要太在意单词和按字节工作。