PIC и mikroPascal
Ассемблерные вставки в mikroPascal
Язык ассемблера традиционно считается одним из непременнейших атрибутов программирования микроконтроллеров. Только его использование позволяет иметь полный контроль над процессором и программой. Другие высокоуровневые языки, как правило, дают значительно худший результат. Особенности компиляции приводят к увеличению объема кода, усложнению структуры программы и замедлению ее работы. При этом сложность освоения языков высокого уровня не намного меньше чем у ассемблера. Главное их достоинство, позволившее вытеснить ассемблер, заключается в более быстром и понятном написании исходных текстов программ. Поэтому сейчас языки высокого уровня повсеместно используются даже для простых микроконтроллеров.
Несмотря на объективные достоинства mikroPascal, встречаются ситуации когда требуется иной подход. В первую очередь потребность возникает при нехватке памяти процессора. Объем памяти программ у простых моделей совсем не большой и компилятор способен очень быстро его выбрать. Про оптимизацию высокого уровня былотнаписано в предыдущей статье. Тогда, когда ее оказывается недостаточно, приходиттся применять вариант включения в текст программы фрагментов кода, написанных на ассемблере. Также такой подход может оказаться востребованным при необходимости получения быстродействующего фрагмента кода.
В mikroPascal вставка ассемблерного кода оформляется конструкцией вида asm end;. Между этими словами используются стандартные ассемблерные команды Microchip. При желании можно вообще не использовать Pascal, а полностью написать код на ассемблере.
Компилятор mikroPascal допускает использование в ассемблерных вставках имен переменных, объявленных в основной программе. Единственное, что необходимо при этом сделать, это добавить знак подчеркивания перед именем переменной в ассемблерной команде.
В качестве примера рассмотрим небольшую программу на языке Pascal. (Программа учебная и реального смысла не несет). Она просто заносит в одну переменную число, инкрементирует его и затем меняет местами полубайты занося результат в другую переменную.
program a12;
var a,b:byte;
begin a:=%10101100; a:=a+1; b:=swap(a);
end.
Результат компиляции можно посмотреть вызвав из меню View пункт Assembly. Выглядеть он будет выглядеть следующим образом:
_main:
;a12.mpas,3 :: begin
;a12.mpas,4 :: a:=%10101100; MOVLW 172 MOVWF _a+0;a12.mpas,5 :: a:=a+1; MOVLW 173 MOVWF _a+0;a12.mpas,6 :: b:=swap(a); MOVLW 173 MOVWF FARG_Swap_arg+0
CALL _Swap+0 MOVF R0+0, 0 MOVWF _b+0;a12.mpas,7 :: end. L_end_main: GOTO $+0
Первые две команды MOVLW 172 и MOVWF _a+0 выполняют стандартную функцию занесения константы в регистр общего назначения. Далее компилятор умничает. Пытаясь использовать предпросмотр кода, он заранее выполняет функцию инкремента константы и снова заносит ее в этот же регистр. Далее становится уже страшно:
MOVLW 173 MOVWF FARG_Swap_arg+0
CALL _Swap+0 MOVF R0+0, 0 MOVWF _b+0
Компилятор вновь берет константу и заносит ее уже в служебную переменную, а затем вызывает подпрограмму обмена полубайтами. И только после этого записывает результат в переменную b. Учитывая служебные команды и многочисленные преходы объем скомпилированного кода составил 20 байт. Полный код можно посмотреть вызвав Listing из меню View.
Как сделал бы человек с использованием ассемблера:
program a12;var a,b:byte; begin a:=%10101100; asm incf _a,0 swapf _a,0 movwf _b end; end.
Результат занимает всего 7 байт (учитываются служебные команды в программе). Выигрыш просто огромный. Здесь следует отметить один важный момент. Видя такие цифры - 20 и 7 байт хочется обругать компилятор и его разработчиков, которые якобы чего-то неправильно наделали и итоговая программа разбухла. На самом деле в примерах используется только один тип данных - байт. Он отлично работает с 8-ми разрядными процессорами. Но как только произойдет переход к большей разрядности, ассемблерный код тут же резко возрастет как по объему, так и по сложности. Компилятор, наоборот, предоставляет программисту единый подход к работе с различными типами данных. За это и приходится платить увеличением объема кода при простых операциях.То же самое справедливо и для всех других высокоуровневых команд.