Немедленно нажми на RESET, All!
При программировании пик-контроллеров семейства AVR на ассемблере вручную распределять переменные по регистрам r0..r31 неудобно и опасно возникновением ошибок. Использование же компилятора C может быть либо неоправданно по каким-либо соображениям, либо вовсе невозможно. Особенно при работе с контроллерами AT90S1200 и ATtiny.
Фирменный ассемблер (avrasm), включаемый во всевозможные IDE, имеет чрезвычайно ограниченные возможности, настолько, что его использование вообще затруднительно. В выборе между использованием неполноценного ассемблера и компилятора C (или ассемблера вклаченного в компилятор) есть и третий вариант: использование просто другого ассемблера. Например, AVRA. Он легко может быть найден в интернете. Ассемблер полностью обратно совместим с фирменным, и кроме того, обладает рядом полезных функций. Наиболее полезные из них -- условная трансляция текста и макроопредления. Используя их становится возможным в какой-то степени автоматизировать работу по распределению переменных по регистрам:
; {{{ macro: dynamic registers allocation ; usage: ; lowreg var_name -- define low (r0..r15) register with name var_name ; hireg var_name -- define high (r15..r31) register ; shreg var1, var2 -- define var1 within same register as var2
.set _lowreg = -1 .set _hireg = 15
.ifndef lowreg_limit .set lowreg_limit = 15 .endif .ifndef hireg_limit .set hireg_limit = 31 .endif
.macro _regalloc_msg .message "reg_alloc: @0 = @1" .endm
.macro lowreg .set _lowreg = {_lowreg+1} .if _lowreg > lowreg_limit .error "reg_alloc: too many low registers allocated!" .endif .def @0 = r{_lowreg} .set _reg_@0 = {_lowreg} _regalloc_msg @0, r{_lowreg} .endm
.macro hireg .set _hireg = {_hireg+1} .if _hireg > hireg_limit .error "reg_alloc: too many high registers allocated!" .endif .def @0 = r{_hireg} .def @0 = r{_hireg} .set _reg_@0 = {_hireg} _regalloc_msg @0, r{_hireg} .endm
.macro shreg .ifdef _reg_@1 .def @0 = r{_reg_@1} _regalloc_msg @0, r{_reg_@1} .else .error "reg_alloc: register named @1 is not defined!" .endif .endm
.macro _statregs .message "register usage statistics:" .message "low reginsters range from 1 to @4" .message "low registers allocated @0 free @1" .message "high registers range from 16 to @5" .message "high registers allocated @2 free @3" .endm
.macro statregs _statregs {_lowreg+1}, {lowreg_limit-_lowreg}, {_hireg+1-16}, {hireg_limit-_hireg}, {lowreg_limit}, {hireg_limit} .endm
; }}}
.set hireg_limit = 27 ; only Y and Z used
lowreg zero lowreg iSREG
hireg state_1 hireg state_2 hireg state_3 hireg state_4
lowreg tmr1 shreg tmr1, tmr2
statregs
Выше приведены необходимые макроопределения и пример использования. Определяются четыре макроса:
lowreg <name>
hireg <name> -- распределят переменную name в набор регистров r0..r15 или r16..r31 соответственно.
shreg <name1>, <name2> -- определяет, что переменная name2 должна использовать тот же регистр, что и name1. Для переменной name1 должен быть определён регистр.
statregs -- выводит информацию по числу использованных и свободных регистров. Кроме тоо, при определении каждой переменной ассемблер будет выдавать сообщение указывающее какой регистр назначен для данной переменной.
Возможно зарезервировать часть регистров для ручного выделения. Совершенно точно, -аще всего, необходимо защитить регистры X, Y и Z от возможности быть распределёнными под другие переменные. Для этого служат метки lowreg_limit и hireg_limit, указывающие на последний регистр (память распределяется снизу вверх) доступный для рспределения.
В случае нехватки памяти регистров будет выдано сообщение...
Разумеется, макросы имеет смысл использовать в небольших программах, где нерегистровая память практически не используется. В противном случае компилятор C оказывается гораздо более эффективен.