Обсуждаем контроллеры компании Atmel.
Ответить

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

Сб ноя 26, 2022 11:23:58

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



Расшифровываю. Читаем из flash, умножаем на два. Но мы загружаем в Z прямой адрес. Это и сбивает с толку начинающих.

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

Сб ноя 26, 2022 11:34:04

Да, все верно. Умножать не нужно, так как адрес процедуры пословный и инструкции ICALL нужен такой же пословный адрес.
Адресное пространство побайтного обращения увеличивается в два раза (на AVR), что требует умножения адреса на два.
Я привел рабочий код, который работает в старом проекте, причем на худом камне семейства Tiny.

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

Сб ноя 26, 2022 14:18:35

Таки давненько не занимался, особо "темными делами" с табличными переходами...
Поспешишшш не вспомнив хорошентко и ... :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, а затем просто выполнить
Код:
IJMP

или
Код:
ICALL

Второй вариант предусматривает применение в качестве команды одного байта смещения
относительно начала таблицы команд переходов к подпрограммам исполнителей команд,
размещенной в массиве ПЗУ
Собственно массив команд переходов:
Код:
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)

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

Вс ноя 27, 2022 09:58:54

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

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

Вс ноя 27, 2022 10:53:47

вместо инструкции относительного перехода rjmp существует инструкция jmp для абсолютного перехода на любой адрес внутри 4М слов.

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

Вс ноя 27, 2022 10:57:21

Вы, наверное, забыли. Rjmp слово. Jmp 2 слова. Не экономно, как бы... Так что зачем jmp, rjmp, если можно сразу таблицу из названий?
Ностальгия... Несколько лет сидел на асме. :)

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

Вс ноя 27, 2022 11:59:09

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

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

Вс ноя 27, 2022 12:26:36

Не соглашусь. Хранение адресов в ОЗУ чревато. Данные могут быть нарушены в случае сбоя. И переход неизвестно куда может привести к самым непредсказуемым последствиям.
Правила:
Константы нужно хранить во flash. Константы, текстовые строки, таблицы.

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

Вс ноя 27, 2022 17:22:49

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

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

Вс ноя 27, 2022 18:44:40

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