Странный вывод сборки

Я просматривал разборку для своего цикла, который, казалось, занимал слишком много времени, и я нашел эти инструкции по сборке, которые я не понимаю. Почему он загружает 0 в r25, а затем выполняет две инструкции adc r25, 25 (которые ничего не сделают, так как r25 равен 0). Кстати, это для ATtiny84.

ПРАВКА: В общем, я не понимаю, почему для установки DDRA, DDRB, ПОРТА и PORTB в последнем цикле требуется так много инструкций. Я чувствую, что LD для чтения портов[j], вывода на вывод и увеличения j должно быть все, что требуется. Я попытался отделить то, что я считаю важной частью разборки.

void loop() {
  set_sleep_mode(SLEEP_MODE_IDLE);
  button = false;
  DDRA = 0;
  DDRB = 0;
  PORTA = 255;
  PORTB = 255;
  do {
    sleep_mode();
  } while (!button);

//  int digits[4];
//  getTime(digits);
//
//  long lights = calcDisp(digits);
  static const byte highLow[28][2] = {{2, 0}, {2, 1}, {0, 3}, {1, 3}, {1, 0}, {3, 1}, {0, 1},
                                     {0, 2}, {3, 0}, {2, 4}, {3, 4}, {4, 3}, {0, 4}, {4, 0},
                                     {4, 1}, {1, 4}, {1, 5}, {5, 1}, {1, 2}, {5, 3}, {2, 3},
                                     {2, 5}, {5, 2}, {5, 4}, {4, 5}, {3, 5}, {4, 2}, {3, 2}};
  byte portOuts[112];
  byte nLed = 0;
  long lights = 0b00000000000000001111111111111111; // just a constant, for now
  for (byte b = 0; b < 16; ++b) {
    if (bitRead(lights, b)) {
      byte high = highLow[b][0];
      byte low = highLow[b][1];
      byte highA = regs[high][0];
      byte highB = regs[high][1];
      byte lowA = regs[low][0];
      byte lowB = regs[low][1];
      portOuts[4 * nLed] = (highA)|(lowA);
      portOuts[4 * nLed + 1] = (highB)|(lowB);
      portOuts[4 * nLed + 2] = (highA)|(1<<PA6);
      portOuts[4 * nLed + 3] = (highB);
      ++nLed;
    }
  }
  for (byte i = 0; i < 200; ++i) {
    for (byte j = 0; j < nLed * 4;) {
      DDRA = portOuts[j++];
      DDRB = portOuts[j++];
      PORTA = portOuts[j++];
      PORTB = portOuts[j++];
    }
  }

разборка

void loop() {
  set_sleep_mode(SLEEP_MODE_IDLE);
  button = false;
  DDRA = 0;
  DDRB = 0;
  PORTA = 255;
 228:   bb 24           eor     r11, r11
 22a:   ba 94           dec     r11
                                     {2, 5}, {5, 2}, {5, 4}, {4, 5}, {3, 5}, {4, 2}, {3, 2}};
  byte portOuts[112];
  byte nLed = 0;
  long lights = 0b00000000000000001111111111111111; // just a constant, for now
  for (byte b = 0; b < 16; ++b) {
    if (bitRead(lights, b)) {
 22c:   cc 24           eor     r12, r12
 22e:   ca 94           dec     r12
 230:   dc 2c           mov     r13, r12
 232:   e1 2c           mov     r14, r1
 234:   f1 2c           mov     r15, r1
  }
  return lights;
}

void loop() {
  set_sleep_mode(SLEEP_MODE_IDLE);
 236:   85 b7           in      r24, 0x35       ; 53
 238:   87 7e           andi    r24, 0xE7       ; 231
 23a:   85 bf           out     0x35, r24       ; 53
  button = false;
 23c:   10 92 a6 00     sts     0x00A6, r1      ; 0x8000a6 <button>
  DDRA = 0;
 240:   1a ba           out     0x1a, r1        ; 26
  DDRB = 0;
 242:   17 ba           out     0x17, r1        ; 23
  PORTA = 255;
 244:   bb ba           out     0x1b, r11       ; 27
  PORTB = 255;
 246:   b8 ba           out     0x18, r11       ; 24
  do {
    sleep_mode();
 248:   85 b7           in      r24, 0x35       ; 53
 24a:   80 62           ori     r24, 0x20       ; 32
 24c:   85 bf           out     0x35, r24       ; 53
 24e:   88 95           sleep
 250:   85 b7           in      r24, 0x35       ; 53
 252:   8f 7d           andi    r24, 0xDF       ; 223
 254:   85 bf           out     0x35, r24       ; 53
  } while (!button);
 256:   80 91 a6 00     lds     r24, 0x00A6     ; 0x8000a6 <button>
 25a:   88 23           and     r24, r24
 25c:   a9 f3           breq    .-22            ; 0x248 <main+0xec>
 25e:   ac e6           ldi     r26, 0x6C       ; 108
 260:   b0 e0           ldi     r27, 0x00       ; 0
 262:   90 e0           ldi     r25, 0x00       ; 0
 264:   80 e0           ldi     r24, 0x00       ; 0
  static const byte highLow[28][2] = {{2, 0}, {2, 1}, {0, 3}, {1, 3}, {1, 0}, {3, 1}, {0, 1},
                                     {0, 2}, {3, 0}, {2, 4}, {3, 4}, {4, 3}, {0, 4}, {4, 0},
                                     {4, 1}, {1, 4}, {1, 5}, {5, 1}, {1, 2}, {5, 3}, {2, 3},
                                     {2, 5}, {5, 2}, {5, 4}, {4, 5}, {3, 5}, {4, 2}, {3, 2}};
  byte portOuts[112];
  byte nLed = 0;
 266:   60 e0           ldi     r22, 0x00       ; 0
 268:   30 e0           ldi     r19, 0x00       ; 0
 26a:   20 e0           ldi     r18, 0x00       ; 0
 26c:   a9 01           movw    r20, r18
 26e:   44 0f           add     r20, r20
 270:   55 1f           adc     r21, r21
 272:   44 0f           add     r20, r20
 274:   55 1f           adc     r21, r21
  long lights = 0b00000000000000001111111111111111; // just a constant, for now
  for (byte b = 0; b < 16; ++b) {
    if (bitRead(lights, b)) {
 276:   26 01           movw    r4, r12
 278:   37 01           movw    r6, r14
 27a:   08 2e           mov     r0, r24
 27c:   04 c0           rjmp    .+8             ; 0x286 <__stack+0x27>
 27e:   75 94           asr     r7
 280:   67 94           ror     r6
 282:   57 94           ror     r5
 284:   47 94           ror     r4
 286:   0a 94           dec     r0
 288:   d2 f7           brpl    .-12            ; 0x27e <__stack+0x1f>
 28a:   40 fe           sbrs    r4, 0
 28c:   3d c0           rjmp    .+122           ; 0x308 <__stack+0xa9>
      byte high = highLow[b][0];
      byte low = highLow[b][1];
      byte highA = regs[high][0];
 28e:   ec 91           ld      r30, X
 290:   f0 e0           ldi     r31, 0x00       ; 0
 292:   ee 0f           add     r30, r30
 294:   ff 1f           adc     r31, r31
 296:   e0 5a           subi    r30, 0xA0       ; 160
 298:   ff 4f           sbci    r31, 0xFF       ; 255
 29a:   70 81           ld      r23, Z
      byte highB = regs[high][1];
 29c:   a1 80           ldd     r10, Z+1        ; 0x01
      byte lowA = regs[low][0];
 29e:   11 96           adiw    r26, 0x01       ; 1
 2a0:   ec 91           ld      r30, X
 2a2:   11 97           sbiw    r26, 0x01       ; 1
 2a4:   f0 e0           ldi     r31, 0x00       ; 0
      byte lowB = regs[low][1];
 2a6:   ee 0f           add     r30, r30
 2a8:   ff 1f           adc     r31, r31
 2aa:   e0 5a           subi    r30, 0xA0       ; 160
 2ac:   ff 4f           sbci    r31, 0xFF       ; 255
 2ae:   91 80           ldd     r9, Z+1 ; 0x01
      portOuts[4 * nLed] = (highA)|(lowA);
 2b0:   21 e0           ldi     r18, 0x01       ; 1
 2b2:   30 e0           ldi     r19, 0x00       ; 0
 2b4:   2c 0f           add     r18, r28
 2b6:   3d 1f           adc     r19, r29
 2b8:   24 0f           add     r18, r20
 2ba:   35 1f           adc     r19, r21
 2bc:   e0 81           ld      r30, Z
 2be:   7e 2e           mov     r7, r30
 2c0:   77 2a           or      r7, r23
 2c2:   f9 01           movw    r30, r18
 2c4:   70 82           st      Z, r7
      portOuts[4 * nLed + 1] = (highB)|(lowB);
 2c6:   e2 e0           ldi     r30, 0x02       ; 2
 2c8:   f0 e0           ldi     r31, 0x00       ; 0
 2ca:   ec 0f           add     r30, r28
 2cc:   fd 1f           adc     r31, r29
 2ce:   e4 0f           add     r30, r20
 2d0:   f5 1f           adc     r31, r21
 2d2:   2a 2d           mov     r18, r10
 2d4:   29 29           or      r18, r9
 2d6:   20 83           st      Z, r18
      portOuts[4 * nLed + 2] = (highA)|(1<<PA6);
 2d8:   e3 e0           ldi     r30, 0x03       ; 3
 2da:   f0 e0           ldi     r31, 0x00       ; 0
 2dc:   ec 0f           add     r30, r28
 2de:   fd 1f           adc     r31, r29
 2e0:   e4 0f           add     r30, r20
 2e2:   f5 1f           adc     r31, r21
 2e4:   70 64           ori     r23, 0x40       ; 64
 2e6:   70 83           st      Z, r23
      portOuts[4 * nLed + 3] = (highB);
 2e8:   24 e0           ldi     r18, 0x04       ; 4
 2ea:   30 e0           ldi     r19, 0x00       ; 0
 2ec:   2c 0f           add     r18, r28
 2ee:   3d 1f           adc     r19, r29
 2f0:   42 0f           add     r20, r18
 2f2:   53 1f           adc     r21, r19
 2f4:   fa 01           movw    r30, r20
 2f6:   a0 82           st      Z, r10
      ++nLed;
 2f8:   6f 5f           subi    r22, 0xFF       ; 255
 2fa:   26 2f           mov     r18, r22
 2fc:   30 e0           ldi     r19, 0x00       ; 0
 2fe:   a9 01           movw    r20, r18
 300:   44 0f           add     r20, r20
 302:   55 1f           adc     r21, r21
 304:   44 0f           add     r20, r20
 306:   55 1f           adc     r21, r21
 308:   01 96           adiw    r24, 0x01       ; 1
 30a:   12 96           adiw    r26, 0x02       ; 2
                                     {4, 1}, {1, 4}, {1, 5}, {5, 1}, {1, 2}, {5, 3}, {2, 3},
                                     {2, 5}, {5, 2}, {5, 4}, {4, 5}, {3, 5}, {4, 2}, {3, 2}};
  byte portOuts[112];
  byte nLed = 0;
  long lights = 0b00000000000000001111111111111111; // just a constant, for now
  for (byte b = 0; b < 16; ++b) {
 30c:   80 31           cpi     r24, 0x10       ; 16
 30e:   91 05           cpc     r25, r1
 310:   09 f0           breq    .+2             ; 0x314 <__stack+0xb5>
 312:   ac cf           rjmp    .-168           ; 0x26c <__stack+0xd>
 314:   68 ec           ldi     r22, 0xC8       ; 200
      portOuts[4 * nLed + 3] = (highB);
      ++nLed;
    }
  }

####################### START OF RELEVANT SECTION #############################

  for (byte i = 0; i < 200; ++i) {
    for (byte j = 0; j < nLed * 4;) {
 316:   41 15           cp      r20, r1
 318:   51 05           cpc     r21, r1
 31a:   99 f1           breq    .+102           ; 0x382 <__stack+0x123>
 31c:   30 e0           ldi     r19, 0x00       ; 0
 31e:   20 e0           ldi     r18, 0x00       ; 0
 320:   80 e0           ldi     r24, 0x00       ; 0
      DDRA = portOuts[j++];
 322:   e1 e0           ldi     r30, 0x01       ; 1
 324:   f0 e0           ldi     r31, 0x00       ; 0
 326:   ec 0f           add     r30, r28
 328:   fd 1f           adc     r31, r29
 32a:   2e 0f           add     r18, r30
 32c:   3f 1f           adc     r19, r31
 32e:   f9 01           movw    r30, r18
 330:   90 81           ld      r25, Z
 332:   9a bb           out     0x1a, r25       ; 26      STORE IN DDRA
 334:   e1 e0           ldi     r30, 0x01       ; 1
 336:   e8 0f           add     r30, r24
      DDRB = portOuts[j++];
 338:   21 e0           ldi     r18, 0x01       ; 1
 33a:   30 e0           ldi     r19, 0x00       ; 0
 33c:   2c 0f           add     r18, r28
 33e:   3d 1f           adc     r19, r29
 340:   2e 0f           add     r18, r30
 342:   31 1d           adc     r19, r1
 344:   f9 01           movw    r30, r18
 346:   90 81           ld      r25, Z
 348:   97 bb           out     0x17, r25       ; 23      STORE IN DDRB
      PORTA = portOuts[j++];
 34a:   e3 e0           ldi     r30, 0x03       ; 3
 34c:   e8 0f           add     r30, r24
    }
  }
  for (byte i = 0; i < 200; ++i) {
    for (byte j = 0; j < nLed * 4;) {
      DDRA = portOuts[j++];
      DDRB = portOuts[j++];
 34e:   a2 e0           ldi     r26, 0x02       ; 2
 350:   a8 0f           add     r26, r24
      PORTA = portOuts[j++];
 352:   21 e0           ldi     r18, 0x01       ; 1
 354:   30 e0           ldi     r19, 0x00       ; 0
 356:   2c 0f           add     r18, r28
 358:   3d 1f           adc     r19, r29
 35a:   2a 0f           add     r18, r26
 35c:   31 1d           adc     r19, r1
 35e:   d9 01           movw    r26, r18
 360:   9c 91           ld      r25, X
 362:   9b bb           out     0x1b, r25       ; 27      STORE IN PORTA
      PORTB = portOuts[j++];
 364:   8c 5f           subi    r24, 0xFC       ; 252
 366:   21 e0           ldi     r18, 0x01       ; 1
 368:   30 e0           ldi     r19, 0x00       ; 0
 36a:   2c 0f           add     r18, r28
 36c:   3d 1f           adc     r19, r29
 36e:   2e 0f           add     r18, r30
 370:   31 1d           adc     r19, r1
 372:   f9 01           movw    r30, r18
 374:   90 81           ld      r25, Z
 376:   98 bb           out     0x18, r25       ; 24      STORE IN PORTB
      portOuts[4 * nLed + 3] = (highB);
      ++nLed;
    }
  }
  for (byte i = 0; i < 200; ++i) {
    for (byte j = 0; j < nLed * 4;) {
 378:   28 2f           mov     r18, r24
 37a:   30 e0           ldi     r19, 0x00       ; 0
 37c:   24 17           cp      r18, r20
 37e:   35 07           cpc     r19, r21
 380:   84 f2           brlt    .-96            ; 0x322 <__stack+0xc3>   JUMP BACK TO START OF LOOP
 382:   61 50           subi    r22, 0x01       ; 1
      portOuts[4 * nLed + 2] = (highA)|(1<<PA6);
      portOuts[4 * nLed + 3] = (highB);
      ++nLed;
    }
  }
  for (byte i = 0; i < 200; ++i) {
 384:   41 f6           brne    .-112           ; 0x316 <__stack+0xb7>

        setup();

        for (;;) {
                loop();
                if (serialEventRun) serialEventRun();
 386:   01 15           cp      r16, r1
 388:   11 05           cpc     r17, r1
 38a:   09 f4           brne    .+2             ; 0x38e <__stack+0x12f>
 38c:   54 cf           rjmp    .-344           ; 0x236 <main+0xda>
 38e:   38 de           rcall   .-912           ; 0x0 <__vectors>
 390:   52 cf           rjmp    .-348           ; 0x236 <main+0xda>```

, 👍1

Обсуждение

Пришлось бы просмотреть больше кода, чтобы понять, что происходит - компилятор может перемещать материал, чтобы код asm мог основываться на исходном коде где-то в другом месте., @bigjosh

`что ничего не даст, так как r25 равно 0"... не совсем так ... подумайте о том, что делает "adc", @jsotola

Например, может произойти скачок где-то до " 30e "после того, как" r25 " был обновлен до нового значения. В этом случае "ldi r25,0" просто инициализирует первый проход, и не стоило бы перепрыгивать через начальные добавления, даже если они ничего не делают на этом первом проходе. ., @bigjosh

Также кажется, что " r24` входит в этот блок с полезным значением, но этот код не отображается., @bigjosh


2 ответа


Лучший ответ:

1

Компилятор оптимизировал вычисление nLed * 4 в битовый сдвиг, как указано << 2. Похоже, что nLed-это однобайтовое количество. Однако nLed * 4 может не поместиться в один байт, и семантика языка требует, чтобы nLed был повышен до int перед вычислением. Это делается путем расширения переменной на байт нулей:

    ldi r25, 0

Теперь пара регистров r25:r24 содержит nLed, расширенный до 16 бит.

Следующий шаг-сдвинуть все это влево на две позиции. Это делается путем повторения этой последовательности дважды:

    lsl r24
    rol r25

Первая инструкция сдвигает r24 влево. Самый значимый бит хранится в качестве флага переноса. Вторая инструкция “поворот влево через перенос” похожа на сдвиг, за исключением того, что крайняя правая позиция бита заполняется переносом. Это способ сдвинуть 16-битное значение без потери бита.

Инструкции lsl и rol на самом деле являются псевдонимами add и adc соответственно. Дизассемблер не заботится об псевдонимах и переводит машинный код в наиболее “канонические” инструкции, что вы и видите.

,

Привет, Эдгар, это действительно интересно! Я просто отредактировал свой пост, чтобы включить некоторую дополнительную информацию. 2 вопроса можно ли избежать продвижения и происходит ли это также с моими строками j++?, @Anubhav

@Anubhav: 1. Продвижение требуется языком, но если вы напишете " (байт)(nLed * 4)", компилятор может понять, что он может оптимизировать его. 2. Операторы "DDRA = переНосы[j++];" и следующие требуют некоторых вычислений адресов. Вы можете получить лучшие результаты, объявив "Переносы" статическими, что сделает его адрес постоянной во время компиляции., @Edgar Bonet

Спасибо, мне показалось, что от этого стало лучше. Что сделало его действительно хорошим, так это выполнение "byte* p = portOuts;" вне моего внутреннего цикла, а затем просто увеличение этого указателя. Теперь компилятор просто генерирует LDD и out, как и ожидалось., @Anubhav


0

Все просто: ацп имеет три операнда. Вы, кажется, смотрите на это так, как если бы у него было два :)

,