Речь о том, что ЛЮБАЯ вставка на ассемблере в Си подчиняется правилам проекта в целом
еще раз вставки НЕТ - есть файлы (можно только ассемблерные), а сборка всего проекта проводится по предельно простым правилам:
Код:
1)# Assemble: create object files from assembler source files. 2)# Compile: create object files from C source files. 3)# Link: create ELF output file from object files.
гуглеперевод:
Код:
1) # Assemble: создание объектных файлов из исходных файлов на ассемблере. 2) # Компиляция: создание объектных файлов из исходных файлов Си. 3) # Link: создать выходной файл ELF из объектных файлов.
Запускаем полный комплект ассемблер - линкер - библиотекарь, да еще относительно компилятора СИ? Он же будет планировку для Си делать. Да и указанное в приведенном Вами выше файле не выходит за рамки типичной подпрограммы, которую можно разместить в рамках проекта ЛЮБОГО компилятора (хоть ассемблер хоть Си).
полный комплект состоит всего из одного файлика avr-gcc.exe - он компилирует и си и асм файлы и линкует вдобавок
ой ли? по-моему, он всего лишь вызывает соответствующие модули из папки bin тулчейна, передавая между ними параметры... или нет?
Добавлено after 7 minutes 58 seconds: сам себе отвечаю: не прав был... действительно, один файл все делать может... во всяком случае для однофайлового проекта, на котором протестировал.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
GCC также известен как программа-драйвер, поскольку он знает о ней и легко управляет другими программами для создания конечного результата. Ассемблер и компоновщик являются частью другого проекта с открытым исходным кодом, называемого GNU Binutils. GCC знает, как заставить GNU-ассемблер (газ) собирать выходные данные компилятора. GCC знает, как управлять компоновщиком GNU (ld), чтобы связать все объектные модули в конечный исполняемый файл.
но вопрос странноватый был;
Цитата:
Запускаем полный комплект ассемблер - линкер - библиотекарь, да еще относительно компилятора СИ?
ответ (тоже странный) - запускаем один файлик. з.ы. BOB51 бы ручками позапускал бы компилятор в командной строке и много вопросов отпало бы и ардуино оказалось не нужным бы
Да запускал и запускаю. Только ассемблер относительно 51-й и из батника. Можно было бы попробовать Ваш вариант подключения с готовой АВРкиной прожкой, но она у меня несколько на слэнге сделана - под "чистокровный ассемблер" придется перелопатить...
Это всего-то тест светиков. Попробуйте его вставкой в Сишный проект сделать. Допустим ... как исполнительный драйвер индикации для проекта какого-либо прикладного назначения (индикация при сработке будильника к примеру). Вернее даже не всю прожку, а только обработчик вывода - trd2812_m.txt.... С учетом его особенностей...
.section .bss .global bufout ; xfunc_out must be initialized before using this module. bufout: .ds.w 5 .section .text
.global bob51_func .func bob51_func bob51_func: rjmp mass_trm slot0: ; 6/14 (6-4=2 посему роль остатка выполняет CBI) cbi port_out, out_line ; 2 цикла nop nop nop nop nop nop nop nop nop ret ; 4 цикла slot1: nop ; 13/7 (13-4=9) nop nop nop nop nop nop cbi port_out,out_line ; 2 цикла nop nop ret ; 4 цикла xslot0: ; 6/14 (6-5=1 посему роль остатка выполняет CBI с избытком в 1 nop) cbi port_out,out_line ; 2 цикла cbr zl,(1<<6) ; модификация указателя 1 цикл nop nop nop nop nop nop ; -2 цикла на ld R16,x+ dec R17 ; 1 цикл brbs SREG_Z,ends_trd ; 1 цикл при неисполнении (в цикле) rjmp trasstt ; 2 цикла xslot1: nop ; 13/7 (13-5=8) cbr zl,(1<<6) ; модификация указателя 1 цикл nop nop nop nop nop cbi port_out,out_line ; 2 цикла ; -2 цикла на ld R16,x+ dec R17 ; 1 цикл brbs SREG_Z,ends_trd ; 1 цикл при неисполнении (в цикле) rjmp trasstt ; 2 цикла ; ends_trd: pop R16 pop R17 pop xl pop xh pop zl pop zh ; восстановить рабочую область из стека ret ;---------- ; ; предварительно: ; линия out_line настроена на вывод ; исходный уровень out_line =0 ; указатель стека усатновлен на RAMEND ; массив данных (bufout:bufout_size) предварительно загружен ; флаг готовности массива данных установлен ; mass_trm: push zh push zl push xh push xl push R17 push R16 ; храним рабочую область в стеке res_line: ldi R16, 4 ser R17 cbi port_out,out_line res_time: dec R17 brne res_time dec R16 brne res_time ; =>50uS time out ldi XH,hi8(bufout) ldi XL,lo8(bufout) ; загрузка начального адреса массива ; в указатель ldi R17, 5 ;bufout_size ldi ZL, lo8(slot0) ; адрес начала таблицы в указателе ldi ZH, hi8(slot0) ;---------- trasstt: ld R16,x+ ; 2 цикла slot_0: sbi port_out,out_line ; 2 цикла реально до установки 3 цикла bst R16,7 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла = 4 цикла от out_line=1 ;---------- slot_1: sbi port_out,out_line bst R16,6 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_2: sbi port_out,out_line bst R16,5 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_3: sbi port_out,out_line bst R16,4 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_4: sbi port_out,out_line bst R16,3 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_5: sbi port_out,out_line bst R16,2 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_6: sbi port_out,out_line bst R16,1 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_7: sbi port_out,out_line sbr zl,(1<<6) ; модификация указателя под завершающий фрагмент ; 1 цикл bst R16,0 ; 1 цикл bld zl,4 ; 1 цикл ijmp ; 3 цикла ;---------- .endfunc
Makefile Спойлер
Код:
### Project name (also used for output file name) PROJECT = BOB51_test
ЖУТЬ... И для простенького фрагмента выписывать тот Makefile?... Легче уж под чистым ассемблером несколько файликов настрочить. Надеюсь обратили внимание, что там точки входа с жестко заданными адресами (или с определенным пропуском) даже если использовать вариант перемещаемого кода slot1=slot0+16 А не линейное продолжение как в Вашем примере. на всякий случай оригинал, чтоб понятнее было в чем ловушка: Спойлер
Код:
; ; ; trd2812_m.txt ; ; файл обработчика передачи массива ; из буфера вывода в линейку на основе WS2812B ; базовый МК из линейки АТМЕЛ при тактовой частоте ; от 16 Мегагерц ( 0,000000062 S) ; ; требуемые интервалы по даташиту WS2812B ; ;Data transfer time( TH+TL=1.25µs±600ns) ; T0H 0 code ,high voltage time 0.4us ±150ns ; T1H 1 code ,high voltage time 0.8us ±150ns ; T0L 0 code ,low voltage time 0.85us ±150ns ; T1L 1 code ,low voltage time 0.45us ±150ns ; RES low voltage time Above 50µs ; исходный уровень линии связи = 0 ; данные передаются пакетами из трех байт на точку ; старшими битами вперед в последовательности ; соответствующей G - R - B цветам точки ; количество блоков должно соответствовать ; количеству точек в ленте ; ; реальные данные согласно тест - отладки дебаггером (версия1!) ; авр-студио 4.19 ; ; Data transfer time( TH+TL=1.38µs -10ns) ; T0H 0 code ,high voltage time 0.44us ±10ns ; T1H 1 code ,high voltage time 0.88us ±10ns ; T0L 0 code ,low voltage time 0.94us ±10ns ; T1L 1 code ,low voltage time 0.50us ±10ns ; RES low voltage time 192,88uS (Above 50µs) ; ; длина прерывания с пакетом загрузки (x60*3) = 2175uS (0.002175) ; интервал между прерываниями (irq t/c0) = 0.004S (4000uS) ; ; define datas ; .equ port_out = PORTB ; порт вывода (по усмотрению) ; .equ out_line = 0 ; линия вывода данных ; .equ bufout = SRAM_START ; начальный адрес буфера вывода ; .equ pixel = 60 ; количество точек в линейке/ленте ; .equ bufout_size = (pixel * 3) ; не может быть более объема ОЗУ - стек!!!
.cseg .org 0x0020 ; старовая позиция 0х0020 !!! slot0: ; 6/14 (6-4=2 посему роль остатка выполняет CBI) cbi port_out,out_line ; 2 цикла nop nop nop nop nop nop nop nop nop ret ; 4 цикла .org (slot0+16) slot1: nop ; 13/7 (13-4=9) nop nop nop nop nop nop cbi port_out,out_line ; 2 цикла nop nop ret ; 4 цикла .org 0x0060 xslot0: ; 6/14 (6-5=1 посему роль остатка выполняет CBI с избытком в 1 nop) cbi port_out,out_line ; 2 цикла cbr zl,(1<<6) ; модификация указателя 1 цикл nop nop nop nop nop nop ; -2 цикла на ld tmp0,x+ dec tmp1 ; 1 цикл brbs SREG_Z,ends_trd ; 1 цикл при неисполнении (в цикле) rjmp trasstt ; 2 цикла .org (xslot0+16) xslot1: nop ; 13/7 (13-5=8) cbr zl,(1<<6) ; модификация указателя 1 цикл nop nop nop nop nop cbi port_out,out_line ; 2 цикла ; -2 цикла на ld tmp0,x+ dec tmp1 ; 1 цикл brbs SREG_Z,ends_trd ; 1 цикл при неисполнении (в цикле) rjmp trasstt ; 2 цикла ; ends_trd: pop tmp0 pop tmp1 pop xl pop xh pop zl pop zh ; восстановить рабочую область из стека ret ;---------- ; ; предварительно: ; линия out_line настроена на вывод ; исходный уровень out_line =0 ; указатель стека усатновлен на RAMEND ; массив данных (bufout:bufout_size) предварительно загружен ; флаг готовности массива данных установлен ; mass_trm: push zh push zl push xh push xl push tmp1 push tmp0 ; храним рабочую область в стеке res_line: ldi tmp0,4 ser tmp1 cbi port_out,out_line res_time: dec tmp1 brne res_time dec tmp0 brne res_time ; =>50uS time out ldi xh,high (bufout) ldi xl,low (bufout) ; загрузка начального адреса массива ; в указатель ldi tmp1,bufout_size ldiw z,slot0 ; адрес начала таблицы в указателе ;---------- trasstt: ld tmp0,x+ ; 2 цикла slot_0: sbi port_out,out_line ; 2 цикла реально до установки 3 цикла bst tmp0,7 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла = 4 цикла от out_line=1 ;---------- slot_1: sbi port_out,out_line bst tmp0,6 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_2: sbi port_out,out_line bst tmp0,5 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_3: sbi port_out,out_line bst tmp0,4 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_4: sbi port_out,out_line bst tmp0,3 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_5: sbi port_out,out_line bst tmp0,2 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_6: sbi port_out,out_line bst tmp0,1 ; 1 цикл bld zl,4 ; 1 цикл icall ; 3 цикла ;---------- slot_7: sbi port_out,out_line sbr zl,(1<<6) ; модификация указателя под завершающий фрагмент ; 1 цикл bst tmp0,0 ; 1 цикл bld zl,4 ; 1 цикл ijmp ; 3 цикла ;----------
механизм обработки тайм-слотов основан на фиксированных адресах начала блоков формирования тайм-слотов. slot0 = 0x0020 slot1 = slot0+16 xslot0 = 0x0060 xslot1 = xslot0+16 Можно конечно то и препроцессору поручить - но тогда переписываем определенные участки обработчика trasstt. Иначе хоть и соберется - но работать не будет.
makefile скопирован из проекта Чена, легким движением настраивается - тип микроконтроллера и перечень исходников. Теперь он НАВСЕГДА - легко идет в другие проекты и даже под армы подправить можно. Насчет жестких адресов (никогда не приходилось) - легко решаемо другими способами (имхо), даже любимыми вставками обходятся https://github.com/lpodkalicki/blog/blo ... t_ws2812.c
на всякий случай оригинал, чтоб понятнее было в чем ловушка
я бегло посмотрел... и понял, в чем ловушка... или догадался. ваш код абсолютно непортируемый. вот это большое количество NOP-ов - это же задержки? чуть поменялась тактовая частота, и надо пересчитывать неизвестно как новое их количество... жестко привязанные точки входа - это не достоинство, а недостаток: чуть изменился тип МК (например, взяли МК с более чем 64К памяти, чтобы Jmp/call стал четырехбайтным - все, сливай воду... и так далее.
ваш пример как раз хорош в качестве "страшилки" для начинающих программистов: будете дети вот так писать - никто вас на работу не возьмет, так и будете всю жизнь вручную pop-push по 30 раз писать...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Ну так.. на то и ассемблер, чтоб подобные вопросы решать. Насчет четырехбайтового вызова - то только при вызове самой программы - в теле используется косвенная адресация (IJMP)- а она НЕИЗМЕННА по времени. Использование высчитываемых вручную задержек в принципе вполне обосновано в данном случае (фазовая манипуляция с помощью ногодрыга под протокол WS2812 при обеспечении долговременной стабильности комплектов слотов). Вопрос же был в том - все ли варианты приемов "чистого ассемблера" легко переносятся в Си. Кроме прочего - алгоритм не только для АВРок... Мне надо иметь возможность однотипные приемы на разных семействах отрабатывать. Посему и предпочитаю правило - не мешать чистый ассемблер с ЯВУ в варианте разнообразных ассемблерных вставок. Другое дело приемы работы и алгоритмические решения, если таковое возможно (и за шо меня периодически поцарапывают).
Последний раз редактировалось BOB51 Пт мар 20, 2020 21:13:20, всего редактировалось 1 раз.
все ли варианты приемов "чистого ассемблера" легко переносятся в Си
ну знаете... вопрос из разряда "где взять упряжь для кошки?" - зачем ВСЕ ВАРИАНТЫ переносить? в Си следует переносить лишь то, без чего принципиально невозможно решить задачу!
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Ну так.. на то и ассемблер, чтоб подобные вопросы решать
Подобные вопросы в современном мире теперь принято аппаратно решать - см. AN1606: Using the Configurable Logic Cell (CLC) to Interface a PIC16F1509 and WS2811 LED Driver
ARV Вот и я про то же - не следует пихать в ЯВУ примитивы. Для того соответствующие средства имеются. В адуринке следует следовать концепту применения референса, а не пытаться "гибриды" лепить (по крайней мере на уровне "продвинутого пользователя"). А мне рекомендуют скрещивать адуринку с ассемблерными файлами. Говорю же уже какой раз - в рамках IDE руководствуемся возможностями, предлагаемыми референсом. А ежли хотим повыделываться - берем нашу DIP микросборку (ту же нанку) и программируем в рамках соответствующего компилятора (хоть Си, хоть ассемблер) - но то уже не ардуино, а конструкция на базе соответствующего МК.
Насчет аппаратных... Там где много аппаратных модулей понатыкано есть побочный эфект - надо детально изучать начинку на предмет начального состояния МК. Дабы изолировать неиспользуемые узлы. А это ужшшш... Весьма муторное занятие (да и накладно). Обычно ограничиваемся определенным набором проработанных кристаллов в каждом семействе.
Снова мимо! А я то думал, найдется таки умная усато-полосатая сущность и покажет решение средствами препроцессора. Я - то ведь всего лишь "продвинутый пользователь-любитель". В прожке позиционно-программный селектор (аналогия табличного дешифратора для скоростного двоично-десятичного преобразования в диапазоне 0-99 - классического приема при работе под ассемблером). Это касательно АВРок более актуально - анализ и выдача значения с одинаковым интервалом (оптимизация по скорости и равным интервалам для определения как 0 так и 1). Для получения ограниченно перемещаемого кода там всего-то надо жестко обусловить начальный адрес подпрограммы. У стартового адреса допустимы любые из нижеприведенных значений: 0хnn00 0xnn20 0xnn40 0xnn60
лично я экспериментировать не буду - ибо писал эта и подобные задачи легко решаются другим путем или програмным или аппаратным. Нет такой задачи, где понадобились бы фиксированые адреса (имхо) - а если есть просьба, описать словами такую задачу с обоснованием необходимости. По исходнику трудно понять что требовалось - если зажигать светодиоды, то была ссылка как это делать без фиксированых адресов.
А при помощи препроцессора компилятора ассемблера никак? Печалька однако... Ибо писать скрипты линкера под каждый файл, коих в многофайловом проекте может быть энное количество, весьма муторно... А в варианте моего "слэнга" практически от такой заморочки я избавлен. Касательно "других решений" - естественно оные имеются, однако вопрос о некорректности применения "чисто ассемблерных файлов", не учитывающих специфику работы компилятора Си, в проектах заточенных под Си похоже закрыт. Пример, который я привёл выше - всего лишь одна из разновидностей классического решения при работе под " чистым ассемблером". И таких приёмов, некорректных по отношению к "чистому Си" достаточно много встречается. Просто не стоит "впадать в крайности" - у каждого из компиляторов свои особенности, которые надо учитывать при работе.
Да любых авторов - зависит от самого проекта и рациональности применения. Просто Вы, почуствовав сложности работы с "чистым ассемблером", пораньше на Си соскочили. Писанина скриптов и маке-файлов должна быть осознанно - самостоятельной. А коль такового уровня нету - стараемся в дебри не лазить без особой необходимости. Существует достаточно много методов, позволяющих обойти подобные осложнения.
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения