Конечный автомат на ассемблере

Обсуждаем контроллеры компании Atmel.
Ответить
Это не хвост, это антенна
Сообщения: 1492
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Тут вот какое дело. ТС спросил, нужно ли умножать на два адрес подпрограммы при использовании icall, ijmp. Если мы читаем из памяти программ, то нужно. Потому что мы обращаемся к flash побайтово. Если мы напрямую загрузим значение в Z, то не нужно.
Спойлер

Код: Выделить всё

//----------------------------- Отладка ----------------------------------
#if (PROJECT==DEBUG)
   ldi ZH, HIGH (Empty_Func)
   ldi ZL, LOW (Empty_Func)
   ijmp

	nop
#endif
//==================

	rjmp	Load_Task // Диспетчер

//==================
	sei

Main:
	wdr
#if (PROJECT==WORK)
	sleep
	nop
#endif
	rjmp	Main
//==================

Empty_Func:
ret
Расшифровываю. Читаем из flash, умножаем на два. Но мы загружаем в Z прямой адрес. Это и сбивает с толку начинающих.
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)

Сообщение DX168B »

Да, все верно. Умножать не нужно, так как адрес процедуры пословный и инструкции ICALL нужен такой же пословный адрес.
Адресное пространство побайтного обращения увеличивается в два раза (на AVR), что требует умножения адреса на два.
Я привел рабочий код, который работает в старом проекте, причем на худом камне семейства Tiny.
I am DX168B and this is my favourite forum on internet!
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 15736
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Таки давненько не занимался, особо "темными делами" с табличными переходами...
Поспешишшш не вспомнив хорошентко и ... :oops: МНДЯАА...
И так...
память у АВРок заполняется пословно сначала младший байт, затем старший
разночтения в директивах DB и DW вызваны восприятием написания и автодополнением
0x00 до четного количества байт в случае применения DB.
Теперь к тем вопросам...
имеется изначально в основной программе группа подпрограмм,
выполняющих определенные команды:

Код: Выделить всё

prg_ap:
 nop
 ; ret ; при ICALL вызове
prg_dn:
 nop
 ; ret ; при ICALL вызове
prg_left:
 nop
 ; ret ; при ICALL вызове
prg_right:
 nop
 ; ret ; при ICALL вызове
и далее, насколько потребуется...
Проще непосредственно присылать полный двухбайтовый код адреса нужной
подпрограммы, размещать его в Z и затем выполнять IJMP(или удачнее ICALL).
Для пересылки команды prg_dn на передающей стороне выполним

Код: Выделить всё

ldi r16,low(prg_dn)
rcall trb ; trb - обработчик передачи байта
ldi r16,high(prg_dn)
rcall trb ; trb - обработчик передачи байта
на приемной стороне достаточно принять эти два байта и соответственно
разместить их в Z, а затем просто выполнить или Второй вариант предусматривает применение в качестве команды одного байта смещения
относительно начала таблицы команд переходов к подпрограммам исполнителей команд,
размещенной в массиве ПЗУ
Собственно массив команд переходов:

Код: Выделить всё

table:
 rjmp prg_ap ; смещение = 0
 rjmp prg_dn ; смещение = 1
 rjmp prg_left ; смещение = 2
 rjmp prg_right ; смещение = 3
команда в данном случае представляет из себя один байт в диапазоне от
0 до 255(0хFF) соответствующий смещению относительно начала таблицы...
На приемной стороне принятый байт предварительно помещается в R16, в
Zh:Zl загружается адрес начала таблицы table, затем выполняем

Код: Выделить всё

add zl,r16
brcc pt0
inc zh
pt0:
ijmp ; или icall по смыслу выполнения программы
тем самым делаем серию переходов от обработчика приема команды на
таблицу переходов и по rjmp из таблицы непосредственно в исполнитель
если вместо ijmp поставить icall, то ret в конце исполнителя команды
вернет нас в конец обработчика приема команды.
Третий вариант похож на второй, но вместо команд переходов в таблице
занесены адреса исполнительных подпрограмм

Код: Выделить всё

table_m:
 .dw prg_ap, prg_dn, prg_left, prg_right
команда в данном случае также представляет из себя один байт в диапазоне от
0 до 255(0хFF) соответствующий смещению относительно начала таблицы...
Прием байта смещения проводим в R16, адрес начала таблицы table_m
также предварительно заносим в Zh:Zl...
А вот дальше морока с LPM...

Код: Выделить всё

add zl,r16
brcc pt0
inc zh
pt0:
lsl Zl
rol Zh
lpm r16,z+
lpm r17,z
movw zl,r16
; и лишь затем
ijmp ; или icall
Результат исполнения что во втором варианте, что в третьем - одинаков.
Однако третий вариант удобен в том случае, если указатели размещать
не в ПЗУ, а в ОЗУ - но там и команды иные для реализации потребуются.
8)
Это не хвост, это антенна
Сообщения: 1492
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Таблица из rjmp kuda-to не всегда может сработать. У меня на асме есть один проект, где rjmp не достаёт. И нужно либо тасованием заниматься, воткнуть таблицу туда где достанет. Но и это может стать проблемой. Расстояние между подпрограммами далеко за пределами rjmp. Либо писать таблицу из названий. Насчёт, очередности младший байт, старший. Я использую симулятор AVR-Studio. И порой приходится следить за адресами. И чтобы мнемонически видеть адрес в показометре памяти, Я сделал макросы, которые пишут значение как первый младший, второй старший, так и наоборот. Когда мы пихаем значения в регистры, очередность не важна. А случае же со стеком очередность важна. Есть у меня один проект с самописным кооперативным диспетчером. Там игры со стеком. Кстати, пример выше как раз из того проекта. rjmp Load_Task
Table:
Func_1, Func_2, Func_3, Func_4.
В этом случае у нас индексный переход. Примеры кода выше.
Позже покажу макросы. Комп занят.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Модератор
Аватара пользователя
Сообщения: 19088
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

вместо инструкции относительного перехода rjmp существует инструкция jmp для абсолютного перехода на любой адрес внутри 4М слов.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Это не хвост, это антенна
Сообщения: 1492
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Вы, наверное, забыли. Rjmp слово. Jmp 2 слова. Не экономно, как бы... Так что зачем jmp, rjmp, если можно сразу таблицу из названий?
Ностальгия... Несколько лет сидел на асме. :)
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 15736
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Таблица из названий с моего взгляду удобна при размещении в ОЗУ.
Там хош оправдано возможностью оперативной модификации векторов, да и кроме адреса/данных в ОЗУ больше ничего не разместить (в смысле команды из резидентного/внутреннего ОЗУ не выполняются).
В остальном - кому чего удобнее(в зависимости от начинки применяемого кристалла).
8)
Это не хвост, это антенна
Сообщения: 1492
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Не соглашусь. Хранение адресов в ОЗУ чревато. Данные могут быть нарушены в случае сбоя. И переход неизвестно куда может привести к самым непредсказуемым последствиям.
Правила:
Константы нужно хранить во flash. Константы, текстовые строки, таблицы.
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 15736
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Чтобы сбить содержимое ОЗУ нужно достаточно солидное внешнеевозмущение - обычный сторож BOD вполне с ним справляется. А вот от работы со сменными векторами никуда не деться (особо ежли программа под Си пишется).
Это уже для самых дурочтойких применений ограничения требуются - но там и правила составления программ "несколько иные" - практически без использования ОЗУ и ближе к простейшей "программной ленте" (перфокартам).
:beer:
Это не хвост, это антенна
Сообщения: 1492
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Хм, не будем развивать эту тему. Я сам когда то использовал самописный кооперативный диспетчер, переключение задач, контента. И векторы хранились в ОЗУ. Ассемблер. До применения в пром приборах дело не дошло. Мне тогда указали на КА. И надобность в диспетчере отпала. КА сам себе диспетчер.
Контактная информация:
Ответить

Вернуться в «AVR»