Странный вывод сборки
Я просматривал разборку для своего цикла, который, казалось, занимал слишком много времени, и я нашел эти инструкции по сборке, которые я не понимаю. Почему он загружает 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>```
@Anubhav, 👍1
Обсуждение2 ответа
Лучший ответ:
Компилятор оптимизировал вычисление 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
Все просто: ацп
имеет три операнда. Вы, кажется, смотрите на это так, как если бы у него было два :)
- более низкая тактовая частота, чем ожидалось на attiny202
- Atmega собирает и ретранслирует вызовы прерывания
- При использовании Arduino Uno в качестве ISP: "Yikes! Invalid device signature" - плохое соединение, неверную конфигурацию или неверную версию avrdude?
- Связь ATtiny85 с компьютером через USB
- Получить доступ к EEPROM ATtiny с помощью кода Arduino?
- avrdude: ошибка проверки, первое несоответствие в байте 0x0000 : 0x00 != 0x16 с использованием USBasp
- Ошибка компиляции кода для Arduino/Genuino Uno
- Разные и самые быстрые способы вычисления синусов и косинусов в Arduino
Пришлось бы просмотреть больше кода, чтобы понять, что происходит - компилятор может перемещать материал, чтобы код asm мог основываться на исходном коде где-то в другом месте., @bigjosh
`что ничего не даст, так как r25 равно 0"... не совсем так ... подумайте о том, что делает "adc", @jsotola
Например, может произойти скачок где-то до " 30e "после того, как" r25 " был обновлен до нового значения. В этом случае "ldi r25,0" просто инициализирует первый проход, и не стоило бы перепрыгивать через начальные добавления, даже если они ничего не делают на этом первом проходе. ., @bigjosh
Также кажется, что " r24` входит в этот блок с полезным значением, но этот код не отображается., @bigjosh