Это, так сказать, "гвоздь не от той стенки". Ассемблер - это представление машинных команд конкретного процессора в символическом виде. В частности, для AVR ассемблер позволяет, например, вместо кода 0xE41A написать команду LDI R17,0x4A, что означает "загрузить в регистр R17 шестнадцатеричную константу 4A". И, соответственно, объекты, которыми может манипулировать программа не ассемблере - только те, которыми может манипулировать процессор. То есть, 32 условно-общих регистра, какое-то количество регистров-портов ввода-вывода, какое-то количество ячеек памяти (отдельно флеш-памяти, отдельно оперативки, отдельно NVRAM), и (почти) все. Переменные в этот список, увы, не входят. И вообще, переменная - это более высокий уровень абстракции, чем ассемблер.AQ29 писал(а):А что, существует какой-то запрет на применение переменных в ассемблере? Про такой запрет я, действительно, ничего не слышал.
Ассемблер (ASM) для AVR в вопросах и ответах
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
- Реклама
от названия суть не меняется.
нравится ему называть один бит переменной или весь регистр называть переменной - пусть называет ...
я, вот, никогда не пользуюсь ни макросами, на какими-то подстановками (то есть, всякими костылями) - просто пишу на ассемблере, и горя не знаю.
нравится ему называть один бит переменной или весь регистр называть переменной - пусть называет ...
я, вот, никогда не пользуюсь ни макросами, на какими-то подстановками (то есть, всякими костылями) - просто пишу на ассемблере, и горя не знаю.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Нет. Разговор следует вести на одном языке. Соответственно и слова надо употреблять правильно.Starichok51 писал(а):от названия суть не меняется.
нравится ему называть один бит переменной или весь регистр называть переменной - пусть называет ...
Ну, в общем-то, нормальные макроассемблеры во многом облегчают жизнь. Но не это АВР-овское убожество. Такое впечатление, что его авторы ни разу не видели нормального ассемблера. И вообще ничего не видели, кроме Паскаля на писюке. Один их набор символических наименований для битов в регистрах периферии чего стоит? Это какую такую траву надо курить, чтобы придумать метод набора двоичного числа в группу смежных бит одного регистра путем сдвигов нулей или единиц на обозначенное символически число бит? Я имею в виду конструкцию, вроде 0<<CS02 | 1<<CS01 | 1<<CS00 для прескалера таймера 0 вместо простого и понятного (допустим) T0prs64, которое в подключаемом по .Include файле было бы определено, как 0x03. Да даже для одиночных битов оно малополезно - команды SBI/CBI - единственные, для которых такие наименования имеют смысл, работают только с первыми тридцатью двумя портами I/O (00-1F), даже у самого первого AT90S1200 почти половина регистров I/O для этих команд недоступна.Starichok51 писал(а):я, вот, никогда не пользуюсь ни макросами, на какими-то подстановками (то есть, всякими костылями) - просто пишу на ассемблере, и горя не знаю.
А макросредства? Один тот факт, что метки в макроопределениях только локальные (временные, действительные только внутри этого макроопределения), отсекает добрую половину тех возможностей, которые предоставляют программисту нормальные макросредства.
В общем, единственное, для чего полезны макросредства этого недоассемблера, это мелкие операции из двух-трех команд, вроде загрузки слова в регистровую пару, типа, когда надо загрузить в XL LOW(ADR), а в XH - high(ADR)
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
- Сообщения: 473
- Зарегистрирован: Ср янв 11, 2012 18:20:26
В макросах ни чего плохого не вижу, тем более, если макрос создаёшь сам и знаешь для чего и как он работает. Сейчас с TFT дисплеями работаю, там постоянно нужно передавать координаты поля для вывода текста / изображения. При этом нужно отослать по SPI 3-и 8-ми битных параметра и 4-ре 16-ти битных.
Забивать код лишними строками, причём не информативными не вижу смысла.
В итоге в коде координаты поля (для вывода I-ой строки текста) выглядят так:
соответственно макрос:
Макросы идут отдельным файлом. Применение каждого оправдано.

Забивать код лишними строками, причём не информативными не вижу смысла.
В итоге в коде координаты поля (для вывода I-ой строки текста) выглядят так:
Код: Выделить всё
LCD_FIELD 5,310,0,47Код: Выделить всё
; Макрос для установки поля вывода изображения на дисплей.
.MACRO LCD_FIELD
ldi R16 , 0x2b ; Column Address Set Координата X
rcall dspl_SEND_COM
ldi R16, high(@0) ; XS
ldi R17, low(@0)
ldi R18, high(@1) ; XE
ldi R19, low(@1)
rcall dspl_SEND_DATA_32
ldi R16 , 0x2a ; Row Address Set Координата Y
rcall dspl_SEND_COM ;
ldi R16, high(@2) ; YS
ldi R17, low(@2)
ldi R18, high(@3) ; YE
ldi R19, low(@3)
rcall dspl_SEND_DATA_32
ldi R16 , 0x2C ; RAMWR (2Ch): Memory Write
call dspl_SEND_COM
.ENDMACRO
Разница между макросом и подпрограммой -
макрос каждый раз кушает память программ, подпрограмма лежит в одном месте и только вызывается из многих, экономя ресурс ОЗУ.
Другое дело когда коротенький макрос-подстановка с перечнем параметров - замещение не имеющейся команды к примеру.
Особо актуально в случае "сокращенного набора команд" к группе которых и АВРки относятся...
Посему в Вашем, shonty, случае лучше таки подпрограмма с передачей параметров через стек или блок регистров (массив в ОЗУ).
примерно:
в макросе только заполнение параметров (для всех обработчиков) и вызов подпрограммы обработчика
а не многократный вызов разных подпрограмм у каждой из которых свои параметры.

макрос каждый раз кушает память программ, подпрограмма лежит в одном месте и только вызывается из многих, экономя ресурс ОЗУ.
Другое дело когда коротенький макрос-подстановка с перечнем параметров - замещение не имеющейся команды к примеру.
Особо актуально в случае "сокращенного набора команд" к группе которых и АВРки относятся...
Посему в Вашем, shonty, случае лучше таки подпрограмма с передачей параметров через стек или блок регистров (массив в ОЗУ).
примерно:
в макросе только заполнение параметров (для всех обработчиков) и вызов подпрограммы обработчика
а не многократный вызов разных подпрограмм у каждой из которых свои параметры.
- Реклама
- Сообщения: 473
- Зарегистрирован: Ср янв 11, 2012 18:20:26
[uquote="BOB51",url="/forum/viewtopic.php?p=3804114#p3804114"]Разница между макросом и подпрограммой -
макрос каждый раз кушает память программ, подпрограмма лежит в одном месте и только вызывается из многих, экономя ресурс ОЗУ.[/uquote]
Когда начинал работать с TFT тоже придерживался такого принципа.
Но через год всё привёл именно к такому виду. И это был осознанный шаг. Дисплей требует скорости вывода. Пришлось уходить от call-ов и ret-ов и дажеоформлять макросом, да, в ущерб памяти.
Вот теперь в скорости вывода могу посоревноваться с более современным железом.
Опять же я не призываю втыкать это везде, но если есть необходимость - почему не воспользоваться.
BOB51, очень понравилось ваше высказывание:
[uquote="BOB51",url="/forum/viewtopic.php?p=3798010#p3798010"]права на самостоятельное распределение ресурсов и свободу применяемых приемов.
[/uquote] 
макрос каждый раз кушает память программ, подпрограмма лежит в одном месте и только вызывается из многих, экономя ресурс ОЗУ.[/uquote]
Когда начинал работать с TFT тоже придерживался такого принципа.
и через ОЗУ тоже работал... И это было год назад.shonty писал(а):Посему в Вашем, shonty, случае лучше таки подпрограмма с передачей параметров через стек или блок регистров (массив в ОЗУ).
Но через год всё привёл именно к такому виду. И это был осознанный шаг. Дисплей требует скорости вывода. Пришлось уходить от call-ов и ret-ов и даже
Код: Выделить всё
SPI_WAITВот теперь в скорости вывода могу посоревноваться с более современным железом.
Опять же я не призываю втыкать это везде, но если есть необходимость - почему не воспользоваться.
BOB51, очень понравилось ваше высказывание:
[uquote="BOB51",url="/forum/viewtopic.php?p=3798010#p3798010"]права на самостоятельное распределение ресурсов и свободу применяемых приемов.
А через push/pop?
Там ведь предзагрузки индексного регистра не требуется (как и счетчика позиций) как в случае с
ST Rd,N+/LD Rd,N-.
Единственно порядок загрузки обратный - первый из используемых параметров загоняем с втек последним.
Это просто как предположение достаточно редкоиспользуемого варианта решения.

Там ведь предзагрузки индексного регистра не требуется (как и счетчика позиций) как в случае с
ST Rd,N+/LD Rd,N-.
Единственно порядок загрузки обратный - первый из используемых параметров загоняем с втек последним.
Это просто как предположение достаточно редкоиспользуемого варианта решения.
- Сообщения: 473
- Зарегистрирован: Ср янв 11, 2012 18:20:26
[uquote="BOB51",url="/forum/viewtopic.php?p=3804128#p3804128"]А через push/pop?
...
Это просто как предположение достаточно редкоиспользуемого варианта решения.
[/uquote]
Спасибо. Идею понял. Подумаю.
PS Немного математики. Что бы просто залить дисплей 240х320 фоном, нужно отправить 76800 16-битных пакетов данных. Это в восьмибитных будет 153600. И если добавить сюда ещё и переходы на подпрограмму SPI_WAIT, то дисплей будет заливаться медленно и печально. Так что приходится жертвовать памятью во ради скорости. Для того и "SPI_WAIT" и оформил макросом, для наглядности и сокращения кода.
...
Это просто как предположение достаточно редкоиспользуемого варианта решения.
Спасибо. Идею понял. Подумаю.
PS Немного математики. Что бы просто залить дисплей 240х320 фоном, нужно отправить 76800 16-битных пакетов данных. Это в восьмибитных будет 153600. И если добавить сюда ещё и переходы на подпрограмму SPI_WAIT, то дисплей будет заливаться медленно и печально. Так что приходится жертвовать памятью во ради скорости. Для того и "SPI_WAIT" и оформил макросом, для наглядности и сокращения кода.
Вовсе не обязательно. Никто не заставляет дожидаться передачи каждого байта по SPI wait-ом. Пока он передаётся (16 тактов CPU, как минимум), вполне можно успеть подготовить следующий.
У меня в проекте велокомпьютера на C я практически максимальные 6.5 FPS выжал на 16MHz тактовой.
Основная суть трюка - ожидать готовности не после того, как байт положен в регистр SPI, а перед этим.
У меня в проекте велокомпьютера на C я практически максимальные 6.5 FPS выжал на 16MHz тактовой.
Основная суть трюка - ожидать готовности не после того, как байт положен в регистр SPI, а перед этим.
- Сообщения: 473
- Зарегистрирован: Ср янв 11, 2012 18:20:26
[uquote="WiseLord",url="/forum/viewtopic.php?p=3804145#p3804145"]Основная суть трюка - ожидать готовности не после того, как байт положен в регистр SPI, а перед этим.[/uquote]
Не понял разницы, ждать до или после. Весь код выкладывать не буду, но там реально всё плотненько и ничего лишнего. Просто отключил сейчас при заливки spi_wait. Не пролило фон. А это значит, что и подготовка быстрая.

PS
Например при выводе текста, цвет переднего плана заранее помещён в регистры R12, R13.
Там и ждать то больше негде, кроме как на spiwait-е
Не понял разницы, ждать до или после. Весь код выкладывать не буду, но там реально всё плотненько и ничего лишнего. Просто отключил сейчас при заливки spi_wait. Не пролило фон. А это значит, что и подготовка быстрая.
PS
Например при выводе текста, цвет переднего плана заранее помещён в регистры R12, R13.
Код: Выделить всё
out SPDR,color_front_H
SPI_WAIT
out SPDR,color_front_L
SPI_WAIT
Последний раз редактировалось shonty Пн мар 09, 2020 09:46:51, всего редактировалось 2 раза.
[uquote="afz",url="/forum/viewtopic.php?p=3804027#p3804027"]Я имею в виду конструкцию, вроде (0<<CS02 | 1<<CS01 | 1<<CS00)[/uquote]
Да ну. Неужели не схавает конструкцию вида (6<<CS00)?
Да ну. Неужели не схавает конструкцию вида (6<<CS00)?
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Разница существенная.shonty писал(а):Не понял разницы, ждать до или после
Если ждать после - то фактически всё то время, пока SPI аппаратно что-то передаёт, основной цикл программы тупо висит в ожидании. И только потом начинает готовить (доставать из массива или ещё что-то) следующий байт для отправки.
Гораздо более правильно положить байт в регистр SPI и сразу же перейти к подготовке (доставанию из массива) следующего байта. И только когда он извлечён и готов к отправки - только тогда повисеть в ожидании, отправился ли предыдущий байт. И как только отвисло - тут же положить готовые данные.
Во втором случае ожидание будет гораздо меньше (если будет вообще).
P.S. Да, когда вся передача закончена и нужно дёрнуть CS или D/C, нужно в самом конце тоже ещё подождать один раз, чтобы передача до конца завершилась.
- Сообщения: 473
- Зарегистрирован: Ср янв 11, 2012 18:20:26
[uquote="WiseLord",url="/forum/viewtopic.php?p=3804187#p3804187"]Если ждать после - то фактически всё то время, пока SPI аппаратно что-то передаёт, основной цикл программы тупо висит в ожидании. И только потом начинает готовить (доставать из массива или ещё что-то) следующий байт для отправки.[/uquote]
Да, возможно при многоцветовом выводе так будет рациональнее.
Подумаю...
У меня текст переменной ширины символов, И поиск параметров символа идёт через таблицу индекса.
И если однотонная заливка просто бешеная, то при выводе текста (переписать одну строку не ощутимо, а вот когда весь экран переписать текстом...) вывод притормаживает немного.
Подумаю как можно использовать этот метод.
Да, возможно при многоцветовом выводе так будет рациональнее.
Подумаю...
У меня текст переменной ширины символов, И поиск параметров символа идёт через таблицу индекса.
И если однотонная заливка просто бешеная, то при выводе текста (переписать одну строку не ощутимо, а вот когда весь экран переписать текстом...) вывод притормаживает немного.
Подумаю как можно использовать этот метод.
Я не знаю, как у Вас вывод шрифтов сделан, но у меня подход такой:
Шрифт, по сути - картинка некоторого размера W*H. ILI9341 (да и все подобные) поддерживает вывод в режиме окна. То есть, задаются координаты (x, y, w, h) этого окна, а дальше можно посылать байты сплошным потоком. В зависимости от настроек, это окно будет заполняться в определённом порядке. У меня выбран такой: сверху вниз первый столбец, затем переход к столбцу правее, и так далее.
То есть, если заранее подготовить шрифт в подходящем формате, то отрисовка становится очень быстрой. Накладные расходы - это по сути только установка окна и установка указателей на нужную "картинку". Дальше - сплошной поток данных, без пауз (из-за wait в нужном месте).
Текст/картинка, получается, рисуется практически с той же скоростью, что и просто заливка экрана.
Шрифт, по сути - картинка некоторого размера W*H. ILI9341 (да и все подобные) поддерживает вывод в режиме окна. То есть, задаются координаты (x, y, w, h) этого окна, а дальше можно посылать байты сплошным потоком. В зависимости от настроек, это окно будет заполняться в определённом порядке. У меня выбран такой: сверху вниз первый столбец, затем переход к столбцу правее, и так далее.
То есть, если заранее подготовить шрифт в подходящем формате, то отрисовка становится очень быстрой. Накладные расходы - это по сути только установка окна и установка указателей на нужную "картинку". Дальше - сплошной поток данных, без пауз (из-за wait в нужном месте).
Текст/картинка, получается, рисуется практически с той же скоростью, что и просто заливка экрана.
- Сообщения: 473
- Зарегистрирован: Ср янв 11, 2012 18:20:26
Да и у меня так же. Один в один.WiseLord писал(а):Я не знаю, как у Вас вывод шрифтов сделан, но у меня подход такой:
Шрифт, по сути - картинка некоторого размера W*H. ILI9341 (да и все подобные) поддерживает вывод в режиме окна. То есть, задаются координаты (x, y, w, h) этого окна, а дальше можно посылать байты сплошным потоком. В зависимости от настроек, это окно будет заполняться в определённом порядке. У меня выбран такой: сверху вниз первый столбец, затем переход к столбцу правее, и так далее.
Но первая заливка фоном (возможно) немного отличается. Фон (черный) 0000h. Это 2x 00h.
По этому просто заливку поля можно реализовать проливая один байт 00h в цикле, но в 2 раза больше.
И RGB565 вообще можно сделать однобайтовым. Например 4E4Eh, 0202h, и т.д. По таблице нужно подбирать. И лить по 2 раза.
Цветов конечно поубавится, но судя по тому как эти дисплеи воспроизводят цвета, то не существенно.
PS Эксперименты по удалению и перемещению SPI_wait-ов дали очень интересные и неожиданные результаты, но не положительные. Всё таки возможно есть разница программ на C или Asm. Возможно C вставляет лишние циклы, может ещё что...
PS2 Что бы не голословить, видео вывода. Шрифт 24х40. Вторую сторку специально через паузу сделал.
Спойлер
По порядку....
Сначала покажите мне в ассемблере такую сущность как переменная. ИХ ТАМ НЕТ. То что мы называем переменными - это абстракция более высокого уровня чем ассемблер. Ассемблер и процессор не работает с переменными - он работает с РЕГИСТРАМИ и такой большой абстракцией как память. ДА! то что вы называете памятью это не обязательно ячейки с долговременным хранением данных, просто чаще всего память используется для хранения данных, но вот сюрприз - это не всегда так. И это становится большой неожиданностью для некоторых программистов, особенно в таких специфических штуках как микроконтроллеры и встраиваемые системы. Поэтому для процессора память не более чем устройство с которого можно читать и записывать данные адресно. Таким же образом ассемблер не может в принципе дать вам то что не может процессор, но перед ассемблером есть ещё надстройки всевозможные, которые реализуют тот или иной "человеческий" функционал и некоторое подобие так называемых переменных. Но тут возникает диллема. С одной стороны для человека "переменная" звучит однозначно и понятно, но для процессора.... начинается АД. Ведь процессор может адресовать совершенно различные виды памяти - РЕГИСТРЫ, ВНУТРЕННЕЕ адресное пространство, ВНЕШНЕЕ адресное пространство, всевозможные параллельные и последовательные чипы памяти как с программным доступом так и аппаратным - I2C, SPI, параллельный доступ... Вы хотите чтобы ассемблер прозрачно поддерживал всё это разнообразие прямо из коробки? Так этого не будет. Такая поддержка потянет за собой накладные расходы. И получим в итоге... язык С. Вот что значит изобретать велосипед.
Но в принципе, хорошо зная язык можно строить такие конструкции на ЯВУ которые разворачиваются компилятором и оптимизатором в быстрый код. Но да, при этом надо много знать особенностей и всяких заморочек.
Сначала покажите мне в ассемблере такую сущность как переменная. ИХ ТАМ НЕТ. То что мы называем переменными - это абстракция более высокого уровня чем ассемблер. Ассемблер и процессор не работает с переменными - он работает с РЕГИСТРАМИ и такой большой абстракцией как память. ДА! то что вы называете памятью это не обязательно ячейки с долговременным хранением данных, просто чаще всего память используется для хранения данных, но вот сюрприз - это не всегда так. И это становится большой неожиданностью для некоторых программистов, особенно в таких специфических штуках как микроконтроллеры и встраиваемые системы. Поэтому для процессора память не более чем устройство с которого можно читать и записывать данные адресно. Таким же образом ассемблер не может в принципе дать вам то что не может процессор, но перед ассемблером есть ещё надстройки всевозможные, которые реализуют тот или иной "человеческий" функционал и некоторое подобие так называемых переменных. Но тут возникает диллема. С одной стороны для человека "переменная" звучит однозначно и понятно, но для процессора.... начинается АД. Ведь процессор может адресовать совершенно различные виды памяти - РЕГИСТРЫ, ВНУТРЕННЕЕ адресное пространство, ВНЕШНЕЕ адресное пространство, всевозможные параллельные и последовательные чипы памяти как с программным доступом так и аппаратным - I2C, SPI, параллельный доступ... Вы хотите чтобы ассемблер прозрачно поддерживал всё это разнообразие прямо из коробки? Так этого не будет. Такая поддержка потянет за собой накладные расходы. И получим в итоге... язык С. Вот что значит изобретать велосипед.
А чем встроенная будет отличаться от не встроенной? По времени вызова? по скорости работы? А вот встроенность потянет за собой дополнительные ограничения - вы не сможете изменить код этой функции под свои потребности, не сможете убрать лишнее, будете мириться с ограничениями накладываемыми этой функцией...Основной смысл – не изобретать велосипед, а использовать готовую функцию.
Думаю, встроенную функцию вызвать проще, соответственно, удобней.
Это не трава, а тот же самый способ задания констант что и ваш. Только более безопасный. Ваша константа в инклуднике даже в таком виде является магической - это просто плохая практика написания кода, которая предрасполагает к ошибкам по невнимательности. В случае, если в другой ревизии контроллера поменяется адрес этих бит вам придётся шерстить весь исходник в поисках этой константы и заменять на правильную(открывать даташит, пересчитывать константу и прочее), при этом есть вероятность пропустить какое-то место и одну такую константу не поменять. Это неудобный, но ошибкоустойчивый способ задания подобных констант. И его кстати не придумали, ведь это не более чем логические операции над целыми числами которые встроены в язык/препроцессор. Вы вольны делать определения констант так как вы показали, но когда вам понадобится переиспользовать ваш же код в другом проекте с другим родственным контроллером(не писать же для него код с нуля?) вы столкнётесь с такими неочевидными проблемами как разные адреса функциональных бит в регистрах, и все ваши вшитые константы будут требовать пересмотра и проверки, а так же все места где они используются - нет ли там неочевидных способов работы с константами, которые могут поломаться если их адреса поменяются. С записью вроде приведённой вами как "травокурной" такого не будет - там изначально имеется в виду что адрес бита может измениться.Это какую такую траву надо курить, чтобы придумать метод набора двоичного числа в группу смежных бит одного регистра путем сдвигов нулей или единиц на обозначенное символически число бит? Я имею в виду конструкцию, вроде 0<<CS02 | 1<<CS01 | 1<<CS00 для прескалера таймера 0 вместо простого и понятного (допустим) T0prs64, которое в подключаемом по .Include файле было бы определено, как 0x03.
Это не костыли а необходимость. Причем, обратите внимание сколько при этом нужно предоставить сведений о вашей вставке компилятору чтобы он не поломал ваш код. И сколько требований предъявляется к вставке чтобы она не поломала СИ-шный код. Всё это плата за высокоуровневость.В СИ приходится делать вставки из ассемблера - это вроде как костыли. А костыли свидетельствуют об инвалидности программы, здоровому костыли не нужны.
Но в принципе, хорошо зная язык можно строить такие конструкции на ЯВУ которые разворачиваются компилятором и оптимизатором в быстрый код. Но да, при этом надо много знать особенностей и всяких заморочек.
[uquote="Alexeyslav",url="/forum/viewtopic.php?p=3804403#p3804403"]По порядку....
Сначала покажите мне в ассемблере такую сущность как переменная. ИХ ТАМ НЕТ. То что мы называем переменными - это абстракция более высокого уровня чем ассемблер.[/uquote]
Вы, милостивый государь, путаете транслятор с железом.
Ассемблер, как и любой язык, имеет сущности сходные с языками более высокого уровня. В том числе и переменные. Причем, В ЗАВИСИМОСТИ ОТ АРХИТЕКТУРЫ контроллера, эти переменные могут размещаться не только в резидентном ОЗУ, но и во внешней памяти. Главное тут, чтобы было единое адресное пространство данных.
Приличный ассемблер всегда имеет контроль за размещением данных в памяти. Так, если для одной переменной выделено 2 байта, а для другой 4, то линкер не позволит одной наехать на другую, а при явном указании на адрес выдаст ошибку размещения.
Таким образом, если в начале кода я выделил для некоей целостной сущности кода некое пространство в памяти данных, а так же объявил символьное имя этой сущности, то эта сущность с точностью до неразличимости стала переменной. Эта переменная отображается в среде разработки именно как переменная заявленной разрядности, а при совместной компиляции АСМ кода (не вставки, а именно кода), имя объявленное в Си кочует без изменений формата в АСМ и наоборот.
Единственное отличие - отсутствие некоторых ограничений на использование этих переменных в АСМе, что может привести к ошибкам. Но если человек имеет опыт работы с ассемблером, эти ошибки крайне редки. Все зависит от МЕТОДОВ написания кода. Ошибки такого рода можно и в Си долго искать, если не владеешь им в дОлжной мере. Взять хотя бы приведение типов...
Сначала покажите мне в ассемблере такую сущность как переменная. ИХ ТАМ НЕТ. То что мы называем переменными - это абстракция более высокого уровня чем ассемблер.[/uquote]
Вы, милостивый государь, путаете транслятор с железом.
Ассемблер, как и любой язык, имеет сущности сходные с языками более высокого уровня. В том числе и переменные. Причем, В ЗАВИСИМОСТИ ОТ АРХИТЕКТУРЫ контроллера, эти переменные могут размещаться не только в резидентном ОЗУ, но и во внешней памяти. Главное тут, чтобы было единое адресное пространство данных.
Приличный ассемблер всегда имеет контроль за размещением данных в памяти. Так, если для одной переменной выделено 2 байта, а для другой 4, то линкер не позволит одной наехать на другую, а при явном указании на адрес выдаст ошибку размещения.
Таким образом, если в начале кода я выделил для некоей целостной сущности кода некое пространство в памяти данных, а так же объявил символьное имя этой сущности, то эта сущность с точностью до неразличимости стала переменной. Эта переменная отображается в среде разработки именно как переменная заявленной разрядности, а при совместной компиляции АСМ кода (не вставки, а именно кода), имя объявленное в Си кочует без изменений формата в АСМ и наоборот.
Единственное отличие - отсутствие некоторых ограничений на использование этих переменных в АСМе, что может привести к ошибкам. Но если человек имеет опыт работы с ассемблером, эти ошибки крайне редки. Все зависит от МЕТОДОВ написания кода. Ошибки такого рода можно и в Си долго искать, если не владеешь им в дОлжной мере. Взять хотя бы приведение типов...
не соглашусь с вами, КРАМ. ассемблер все-таки оперирует "метками", сопоставляя им некие константы, а не переменными. и что именно эта константа будет обозначать, транслятору ассемблера неведомо: вы можете запросто обявить метку М1 в сегменте кода (для JMP), и использовать её в команде пересылки MOV A, #M1 (ну или как там по синтаксису), и ничего "не будет". или запузырить переход на метку M2, которая объявлена примерно так: M2: db 6 - и снова ничего не будет. скорее всего, ничего хорошего 
и распределением памяти ассемблер никак не занимается - программист сам метки расставляет, и будут они обозначать пересекающиеся области памяти или нет - его личное дело. и вряд ли линкер на это среагирует.
еще в ассемблере есть "подстановки" (директива EQU), или алиасы - но это тоже не эквивалент переменных.
главное отличие переменной, как сущности, в её независимости от контекста. т.е. при пересылках , присваивании и т.п. переменная выступает как атомарная единица программы. естественно, ассемблер такой абстракции не поддерживает.
во всяком случае ассемблеры MCS51, AVR, TASM и MASM работают именно так, как я и описал - с другими не имел чести быть знакомым...
и распределением памяти ассемблер никак не занимается - программист сам метки расставляет, и будут они обозначать пересекающиеся области памяти или нет - его личное дело. и вряд ли линкер на это среагирует.
еще в ассемблере есть "подстановки" (директива EQU), или алиасы - но это тоже не эквивалент переменных.
главное отличие переменной, как сущности, в её независимости от контекста. т.е. при пересылках , присваивании и т.п. переменная выступает как атомарная единица программы. естественно, ассемблер такой абстракции не поддерживает.
во всяком случае ассемблеры MCS51, AVR, TASM и MASM работают именно так, как я и описал - с другими не имел чести быть знакомым...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
[uquote="ARV",url="/forum/viewtopic.php?p=3804430#p3804430"]с другими не имел чести быть знакомым...[/uquote]
Это ключевая фраза в Вашем сообщении.
Не работал с Ассемблером АВР, но поскольку нынче АВР принадлежит Микрочипу, приведу пример из MPASM.
Проблема в том, что мало кто удосуживается прочитать мануал на Ассемблер.
Так подавляющее большинство АСМописателей работающих с 8-битными ПИКами тупо брали манеру написания кода из темплейтов прилагавшихся к самому MPASM-у Микрочипом, которые написал какой то туповатый индус на удаленке.
И поэтому с удивлением обнаруживали при переходе на MPLAB X, что куда то исчезла видимость объявленных "переменных", которые объявили как КОНСТАНТЫ директивами EQU или CBLOCK/ENDC.
А всего то нужно было объявить переменные как неинициализированные данные директивой udata/udata_shr/udata_ovr/udata_acs и "таинственным" образом символьное имя будет привязано именно к адресу ДАННЫХ, а совсем не будет меткой со всеми вытекающими при трансляции последствиями. Мало того, квалификатор при директиве после подчеркивания разместит данные не где нибудь, а во вполне определенном сегменте ОЗУ. И при попытке "прибить гвоздями" пересекающиеся адреса переменных при явном определении расположения данных, в дело тут же вступит линкер, обматерив страдальца...
Таки да, имя объявленное для переменной будет означать АДРЕС этой переменной и использовать его можно или как указатель, или как непосредственные данные, определится это СИНТАКСИСОМ ассемблера этой платформы. То есть ровно так же, как и в Си - varname/*varname/&varname, только немного иными методами - размещением внутри инструкций в соответствующей позиции.
Метки кода при попытке их размещения в инструкции, как правило, приведут к ошибке линкера.
Аналогичные примеры могу привести из ASM30/ASM16 того же Микрочипа.
Да, метка кода - это перемещаемый или абсолютный адрес флеша, а имя переменной - это тоже адрес, но в ОЗУ. Но что тут может быть противоестественного, если в фон-неймановской архитектуре и данные и код находятся в одном адресном пространстве и метка кода действительно может быть именем переменной....
[uquote="ARV",url="/forum/viewtopic.php?p=3804430#p3804430"]при пересылках , присваивании и т.п. переменная выступает как атомарная единица программы.[/uquote] Ну нащщет ее атомарности бабка надвое сказала... Ее атомарность сильно зависит от архитектуры МК (его разрядности). Сколько удивлений вызывает у начинающих нарушение целостности int при присвоении в 8-битном МК... А еще эту целостность можно развалить методами Си специально...
Это ключевая фраза в Вашем сообщении.
Не работал с Ассемблером АВР, но поскольку нынче АВР принадлежит Микрочипу, приведу пример из MPASM.
Проблема в том, что мало кто удосуживается прочитать мануал на Ассемблер.
Так подавляющее большинство АСМописателей работающих с 8-битными ПИКами тупо брали манеру написания кода из темплейтов прилагавшихся к самому MPASM-у Микрочипом, которые написал какой то туповатый индус на удаленке.
И поэтому с удивлением обнаруживали при переходе на MPLAB X, что куда то исчезла видимость объявленных "переменных", которые объявили как КОНСТАНТЫ директивами EQU или CBLOCK/ENDC.
А всего то нужно было объявить переменные как неинициализированные данные директивой udata/udata_shr/udata_ovr/udata_acs и "таинственным" образом символьное имя будет привязано именно к адресу ДАННЫХ, а совсем не будет меткой со всеми вытекающими при трансляции последствиями. Мало того, квалификатор при директиве после подчеркивания разместит данные не где нибудь, а во вполне определенном сегменте ОЗУ. И при попытке "прибить гвоздями" пересекающиеся адреса переменных при явном определении расположения данных, в дело тут же вступит линкер, обматерив страдальца...
Таки да, имя объявленное для переменной будет означать АДРЕС этой переменной и использовать его можно или как указатель, или как непосредственные данные, определится это СИНТАКСИСОМ ассемблера этой платформы. То есть ровно так же, как и в Си - varname/*varname/&varname, только немного иными методами - размещением внутри инструкций в соответствующей позиции.
Метки кода при попытке их размещения в инструкции, как правило, приведут к ошибке линкера.
Аналогичные примеры могу привести из ASM30/ASM16 того же Микрочипа.
Да, метка кода - это перемещаемый или абсолютный адрес флеша, а имя переменной - это тоже адрес, но в ОЗУ. Но что тут может быть противоестественного, если в фон-неймановской архитектуре и данные и код находятся в одном адресном пространстве и метка кода действительно может быть именем переменной....
[uquote="ARV",url="/forum/viewtopic.php?p=3804430#p3804430"]при пересылках , присваивании и т.п. переменная выступает как атомарная единица программы.[/uquote] Ну нащщет ее атомарности бабка надвое сказала... Ее атомарность сильно зависит от архитектуры МК (его разрядности). Сколько удивлений вызывает у начинающих нарушение целостности int при присвоении в 8-битном МК... А еще эту целостность можно развалить методами Си специально...
Это функционал IDE(или по крайней мере препроцессора) а не ассемблера, ага прикрутили проверку и связи меток с именами переменных сверху, над ассемблером чтобы удобней их визуализировать - как раз это и есть пример типичного костыля. Скажите, как именно сам ассемблер решит что метка с адресом 0x0023 является переменной? и какой у неё размер? Все эти проверки прикручены в виде костылей и выполняются до того как будет вообще запущен компилятор или на первом его проходе. На уровне линкера проверять пересечения диапазонов? Ну это в качестве бреда... линкер работает уже после компилятора... когда код почти готов и осталось собрать все куски кода воедино, вычислив все смещения, поздновато на этом этапе сообщать об ошибках.


