Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

Побитовый сдвиг массива

#c #массивы #ассемблер #avr


Вообще мне нужно последовательно (побитно) передать и потом принять пакет длиной 48 бит.

Если бы пакет был длиной 32 бита, то решение могло бы быть примерно такое:

unsigned long data=0x12345678;

for(i=0;i<32;i++){
  if(data & 0x80000000)
    setb_MOD;
  else
    clrb_MOD;
  data <<= 1;
}


Этот код компилируется очень приятно и компактно. Именно так я бы и сделал на ассемблере:

        code<<=1;
  ac:   88 0f           add r24, r24
  ae:   99 1f           adc r25, r25
  b0:   aa 1f           adc r26, r26
  b2:   bb 1f           adc r27, r27
  b4:   80 93 63 00     sts 0x0063, r24
  b8:   90 93 64 00     sts 0x0064, r25
  bc:   a0 93 65 00     sts 0x0065, r26
  c0:   b0 93 66 00     sts 0x0066, r27


Но т.к. пакет имеет длину 48 бит, приходится обяъвлять его как массив и сдвигать
его побайтно в цикле:

unsigned char data[6]={0x12,0x34,0x56,0x78,0xAB,0xCD};

for(i=0;i<48;i++){
  if(data[5] & 0x80)
    setb_MOD;
  else
    clrb_MOD;
  for(j=5;j>0;j--){
    data[j]<<=1;
    if(data[j-1] & 0x80)
      data[j]+=1;
  }
  data[0] <<= 1;
}


Результаты компиляции несколько зависят от настроек оптимизатора, видно, что делает
он ровно то, что ему и положено: т.е. компилирует он довольно буквально и не использует
очевидную для человека коснтрукцию (см. выше). Вот что получается:

        for(j=5;j>0;j--){
            code[j]<<=1;
  a8:   82 91           ld  r24, -Z
  aa:   88 0f           add r24, r24
  ac:   80 83           st  Z, r24
            if(code[j-1]&0x80)
  ae:   9e 91           ld  r25, -X
  b0:   97 fd           sbrc    r25, 7
  b2:   13 c0           rjmp    .+38        ; 0xda <__vector_2+0x74>
            clrb_MOD;
        }
        else{
            setb_MOD;
        }
        for(j=5;j>0;j--){
  b4:   80 e0           ldi r24, 0x00   ; 0
  b6:   a3 36           cpi r26, 0x63   ; 99
  b8:   b8 07           cpc r27, r24
  ba:   b1 f7           brne    .-20        ; 0xa8 <__vector_2+0x42>
            code[j]<<=1;
            if(code[j-1]&0x80)
                code[j]+=1;
        }


Мне бы очень хотелось избежать использования инлайн вставок кода на ассемблере. Во-первых
по-тому, что я не очень владею этой техникой и совершенно не представляю как мне обращаться
из ассемблерного кода к переменным, объявленным в C. Хотя, я точно знаю, что все это
возмжоно.

Есть ли еще какие-то альтернативы получить оптимальный код?
    


Ответы

Ответ 1



Вы все то же самое могли бы сделать, используя тип uint64_t или unsigned long long. Например, #include //... uint64_t data = 0x123456780123; for ( i = 0; i < 48; i++ ) { ( data & 0x8000000000 ) ? setb_MOD : clrb_MOD; data <<= 1; }

Ответ 2



Если всё-таки надо сдвигать массив: #include #define ARRAY_LENGTH 6 void rightShift(uint8_t * array){ uint8_t preBuffer = 0; uint8_t postBuffer = 0; for(uint8_t i = 0; i < ARRAY_LENGTH; ++i){ postBuffer = (array[i] & 0b00000001) << 7; array[i] =>> 1; array[i] |= preBuffer; preBuffer = postBuffer; } } void leftShift(uint8_t * array){ uint8_t preBuffer = 0; uint8_t postBuffer = 0; for(uint8_t i = ARRAY_LENGTH - 1; i < ARRAY_LENGTH; --i){ postBuffer = (array[i] & 0b10000000) >> 7; array[i] =<< 1; array[i] |= preBuffer; preBuffer = postBuffer; } }

Комментариев нет:

Отправить комментарий