С недавних пор начал разбираться с компилятором IAR, до этого писал на ассемблере. Начал простенький проектик с графическим дисплеем. Пытаюсь вывести на экран строку, расположенную в памяти программ. Строка, конечно, выводится, отображается как надо, но вот какими методами...
В общем, есть у меня функция:
Код
void lcd_write_string(char __flash * string)
{
char i= * string++;
while(i--!=0)
{
lcd_write_character(*string++);
}
}
{
char i= * string++;
while(i--!=0)
{
lcd_write_character(*string++);
}
}
Принимает она указатель на flash, где переменная где у меня выглядит следующим образом:
char __flash string[]={5,'A','B','C','D','E'};
5 - число символов в строке, дальше символы.
При компиляции всего этого начинаются для меня непонятные вещи:
Код
@00000057: lcd_write_string
46: void lcd_write_string(char __flash * string)
47: {
+00000057: 940E00D2 CALL 0x000000D2 Call subroutine;тут компилятор сохраняет в программный стек регистры, хотя это и не нужно, ну да ладно
+00000059: 01C8 MOVW R24,R16 Copy register pair;тут получили указатель, переданный через пару регистров R16:R17
48: char i= * string++;
+0000005A: 01FC MOVW R30,R24 Copy register pair;но почему было сразу их не занести в ZH:ZL???
+0000005B: 91A4 LPM R26,Z Load program memory;если бы сразу занесли в ZH:ZL, можно бы было сделать LPM R26,Z+
+0000005C: 9601 ADIW R24,0x01 Add immediate to word;тогда эта строка лишняя
+0000005D: C004 RJMP PC+0x0005 Relative jump;прыг +5
51: lcd_write_character(*string++);
+0000005E: 01FC MOVW R30,R24 Copy register pair;опять переносим в Z указатель
+0000005F: 9104 LPM R16,Z Load program memory
+00000060: DFE9 RCALL PC-0x0016 Relative call subroutine;собственно, запись символа
+00000061: 9601 ADIW R24,0x01 Add immediate to word;и почему-то увеличиваем указатель уже после выполнения функции
49: while(i--!=0)
+00000062: 2F0A MOV R16,R26 Copy register;вот зачем дальше вся эта чехарда, когда можно просто проверить R26???
+00000063: 2FA0 MOV R26,R16 Copy register
+00000064: 95AA DEC R26 Decrement
+00000065: 2300 TST R16 Test for Zero or Minus
+00000066: F7B9 BRNE PC-0x08 Branch if not equal;прыг на -8
53: }
+00000067: E0E3 LDI R30,0x03 Load immediate
+00000068: 940C00D6 JMP 0x000000D6 Jump
46: void lcd_write_string(char __flash * string)
47: {
+00000057: 940E00D2 CALL 0x000000D2 Call subroutine;тут компилятор сохраняет в программный стек регистры, хотя это и не нужно, ну да ладно
+00000059: 01C8 MOVW R24,R16 Copy register pair;тут получили указатель, переданный через пару регистров R16:R17
48: char i= * string++;
+0000005A: 01FC MOVW R30,R24 Copy register pair;но почему было сразу их не занести в ZH:ZL???
+0000005B: 91A4 LPM R26,Z Load program memory;если бы сразу занесли в ZH:ZL, можно бы было сделать LPM R26,Z+
+0000005C: 9601 ADIW R24,0x01 Add immediate to word;тогда эта строка лишняя
+0000005D: C004 RJMP PC+0x0005 Relative jump;прыг +5
51: lcd_write_character(*string++);
+0000005E: 01FC MOVW R30,R24 Copy register pair;опять переносим в Z указатель
+0000005F: 9104 LPM R16,Z Load program memory
+00000060: DFE9 RCALL PC-0x0016 Relative call subroutine;собственно, запись символа
+00000061: 9601 ADIW R24,0x01 Add immediate to word;и почему-то увеличиваем указатель уже после выполнения функции
49: while(i--!=0)
+00000062: 2F0A MOV R16,R26 Copy register;вот зачем дальше вся эта чехарда, когда можно просто проверить R26???
+00000063: 2FA0 MOV R26,R16 Copy register
+00000064: 95AA DEC R26 Decrement
+00000065: 2300 TST R16 Test for Zero or Minus
+00000066: F7B9 BRNE PC-0x08 Branch if not equal;прыг на -8
53: }
+00000067: E0E3 LDI R30,0x03 Load immediate
+00000068: 940C00D6 JMP 0x000000D6 Jump
Итак, вопрос: это такая работа компилятора, или это я чего-то не знаю? Как напрямую в регистр ZH:ZL скормить указатель и работать именно с этими регистрами? Нет, я могу то же самое написать на ассемблере, и ассемблерную библиотеку прикрутить, но зачем тогда мне компилятор?