В даташите AVR102 рассматривается реализация на языке ассемблера следующих базовых операций:
• Копирование из памяти программ (FLASH) в оперативную память (SRAM) • Копирование в пределах оперативной памяти (из SRAM в SRAM)
Подпрограммы копирования экстремально эффективны: операция FLASH -> SRAM занимает 6 слов (т. е. 12 байт), SRAM -> SRAM занимает 5 слов (10 байт). К подпрограммам прилагается запускаемый тест для проверки работы подпрограмм.
Подпрограммы копирования работают с блоками до 256 байт, и могут копировать из любого исходного адреса по любому адресу назначения.
[FLASH -> SRAM, подпрограмма flash2ram]
Перед вызовом этой подпрограммы должны быть настроены следующие входные параметры:
• flashsize – регистровая переменная, содержащая размер копируемого блока данных. • Z-pointer – указатель, равный двухбайтовому исходному адресу первого байта копируемого блока в памяти FLASH. • Y-pointer – указатель, адрес назначения первого байта из копируемого блока в памяти SRAM.
Подпрограмма для копирования использует инструкцию LPM, которая предназначена для передачи данных из FLASH в регистровый файл. Инструкция выбирает слово из памяти FLASH (2 байта, 16 бит) которое указано 15 старшими битами из указателя Z-pointer. Если младший бит Z-pointer равен 0, то будет возвращен младший байт слова из FLASH, иначе будет возвращен старший байт слова из FLASH. Возвращенный байт всегда будет находиться в регистре R0. Чтобы получить 15 старших битов для Z, соответствующих корректному значению слова, программист должен внимательно загрузить Z дважды адресом первого двойного байта в таблице. Листинг программы показывает, как обработать это условие.
Во время передачи данных используется автоинкремент указателей. Запись в SRAM выполняется с использованием инструкции ST Y+,Rs. Инструкция LPM не поддерживает автоинкремент или автодекремент, поэтому для инкремента 16-битного указателя используется инструкция ADIW.
Регистровая переменная flashsize используется в подпрограмме для счетчика цикла.
Рис. 1. Алгоритм flash2ram.
;***************************************************************************
;* flash2ram
;***************************************************************************
;***** регистровые переменные подпрограммы
.def flashsize=r16 ;размер копируемого блока
flash2ram:
lpm ;получить константу
st Y+,r0 ;сохранить её в SRAM и инкрементировать Y-pointer
adiw ZL,1 ;инкремент Z-pointer
dec flashsize
brne flash2ram ;продолжим, если счетчик не равен 0
ret
Таблица 1. Использование регистров подпрограммой flash2ram.
Регистр |
Вход |
Внутреннее использование |
R0 |
|
Временное хранилище данных |
R16 |
flashsize - размер копируемого блока данных |
|
R28 |
YL- младший байт адреса назначения (начало блока SRAM) |
|
R29 |
YH - старший байт адреса назначения (начало блока SRAM) |
|
R30 |
ZL - младший байт адреса источника (начало блока FLASH) |
|
R31 |
ZH - старший байт адреса источника (начало блока FLASH) |
|
Таблица 2. Параметры эффективности подпрограммы flash2ram.
Параметр |
Значение |
Размер кода (в словах) |
5 + возврат |
Время выполнения |
(10 * размер_блока) + возврат |
Использование регистров |
6 (из них 4 регистра приходится на указатели Z и Y) |
Прерывания |
не используются |
Периферийные устройства |
не используются |
[SRAM -> SRAM, подпрограмма ram2ram]
Перед вызовом этой подпрограммы должны быть настроены следующие входные параметры:
• ramsize – регистровая переменная, в которой содержится размер блока данных. • Z-pointer – адрес первого байта в блоке источника данных. • Y-pointer – адрес первого байта в блоке места назначения данных.
Из-за того, что используется автоинкремент указателей, эта подпрограмма получилась экстремально компактной и быстрой. Перемещение одного байта данных и инкремент обоих указателей требуют только 2 инструкций. Еще 2 инструкции нужны для декремента и проверки регистровой переменной ramsize, которая используется в качестве счетчика цикла в подпрограмме. Во время передачи данные временно хранятся в регистровой переменной ramtemp.
Рис. 2. Алгоритм ram2ram.
;***************************************************************************
;* ram2ram
;***************************************************************************
;***** регистровые переменные подпрограммы
.def ramtemp =r1 ;регистр для временного хранения байта данных
.def ramsize =r16 ;размер копируемого блока
ram2ram:
ld ramtemp,Z+ ;получение данных из BLOCK1
st Y+,ramtemp ;сохранение данных в BLOCK2
dec ramsize
brne ram2ram ;продолжим, если счетчик не равен 0
ret
Таблица 3. Использование регистров подпрограммой ram2ram.
Регистр |
Вход |
Внутреннее использование |
R1 |
|
ramtemp - временное хранилище данных |
R16 |
ramsize - размер копируемого блока данных |
|
R28 |
YL- младший байт адреса назначения (начало блока SRAM) |
|
R29 |
YH - старший байт адреса назначения (начало блока SRAM) |
|
R30 |
ZL - младший байт адреса источника (начало блока SRAM) |
|
R31 |
ZH - старший байт адреса источника (начало блока SRAM) |
|
Таблица 4. Параметры эффективности подпрограммы ram2ram.
Параметр |
Значение |
Размер кода (в словах) |
4 + возврат |
Время выполнения |
(6 * размер_блока) + возврат |
Использование регистров |
6 (из них 4 регистра приходится на указатели Z и Y) |
Прерывания |
не используются |
Периферийные устройства |
не используются |
[Программа для примера/тестирования]
Программа апноута содержит файл, содержащий рабочий тест, который использует подпрограммы копирования 2 байт данных из FLASH в SRAM, затем делают 2 копию данных в другой области SRAM. Тест-программа была сделана для микроконтроллера AT90S8515. Путем смены подключаемого файла *def.inc на другой программа может быть использована с любым другим микроконтроллером AVR, у которого есть память SRAM.
;****************************************************************************
;* Тест-программа
;*
;* Эта программа копирует 20 байт данных из памяти программ (FLASH) в SRAM,
;* начиная с адреса BLOCK1. Затем она делает вторую копию этих данных
;* начиная с адреса BLOCK2.
;****************************************************************************
.equ BLOCK1 =$60 ;start address of SRAM array #1
.equ BLOCK2 =$80 ;start address of SRAM array #2
.def temp =r16 ;временная переменная для хранения данных
RESET:
ldi temp,low(RAMEND)
out SPL,temp ;инициализация стека
ldi temp,high(RAMEND)
out SPH,temp
;***** копирование 20 байт FLASH -> RAM
ldi ZH,high(F_TABLE*2)
ldi ZL,low(F_TABLE*2) ;инициализация Z-pointer
ldi YH,high(BLOCK1)
ldi YL,low(BLOCK1) ;инициализация Y-pointer
ldi flashsize,20
rcall flash2ram
;***** копирование 20 байт RAM -> RAM
ldi ZH,high(BLOCK1)
ldi ZL,low(BLOCK1) ;инициализация Z-pointer
ldi YH,high(BLOCK2) ;(хотя это и необязательно для нашего случая)
ldi YL,low(BLOCK2) ;инициализация Y-pointer
ldi ramsize,20
rcall ram2ram
forever:
rjmp forever ;бесконечный цикл
F_TABLE:
.db 0,1 ;начало таблицы из 20 байт
.db 2,3
.db 4,5
.db 6,7
.db 8,9
.db 10,11
.db 12,13
.db 14,15
.db 16,17
.db 18,19
[Ссылки]
1. AVR102: Block Copy Routines site:atmel.com. |