|
|
  |
Вопрос к ассемблерщикам, Автоматическая растановка адресов |
|
|
|
Mar 9 2009, 21:07
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(Maik-vs @ Mar 8 2009, 19:17)  Какое странное и невнятное обсуждение. То есть некоторые обвиняют ассемблер в его "бедности", не понимании структур и т.д. А я вот видел множество обсуждений сишников: то как объявить переменную в нужной памяти, то как проинвертировать бит в порту то ещё что-нибудь, что у ассемблерщика вызовет недоумённую улыбку. Такой язык. И можно написать кучу макросов каждому на свой вкус, в том числе и для доступа к структурам. К Вашим структурам. А вообще-то конечно, кому что - есть и VBA или вот ЛИСП интересный язык  Ещё раз отмечаю. Само написание проги на асме, как правило занимает даже меньше времени (особенно для млких проектов) чем на асме. Я имею ввиду грамотное написание там и там. Но ... сопровождение и развитие проекта на Си ... на порядок быстрее и комфортнее. На порядок это в 10 раз. И это не для красного словца, а это приблизительно мои оценки затрат. По обсуждаемой теме всётаки на мой взгляд правильнее автоматическое выделение памяти. А не относительное со смещением. То есть я не вижу преимуществ (Зато кучу недостатков) в конструкции типа: Код .equ SRAM_NEXT_1 = SRAM_START + 1; .equ SRAM_NEXT_2 = SRAM_NEXT_1 + 10; .equ SRAM_NEXT_3 = SRAM_NEXT_2 + 100; На мой взгляд правильнее конструкция типа: Код .dseg .org SRAM_START_ADR SRAM_START: .byte 1 SRAM_NEXT_1: .byte 10 SRAM_NEXT_2: .byte 100 SRAM_NEXT_2: Причём 1,10,100 я бы задал через "equ". Точно также я работаю и со структурами. Например: Код ; Структура X(i-1), Y(i-1)*2, Y(i-2)*2, Z(i-1)*2, Z(i-2)*2 MADC: .byte 6*9 ; Измерения по каналам MADC_SR: ; Усреднённое значение измерения по каналам MADC_0: .byte 1 ; Усреднённое значение измерения канала 0 MADC_1: .byte 1 ; Усреднённое значение измерения канала 1 MADC_2: .byte 1 ; Усреднённое значение измерения канала 2 MADC_3: .byte 1 ; Усреднённое значение измерения канала 3 MADC_4: .byte 1 ; Усреднённое значение измерения канала 4 MADC_5: .byte 1 ; Усреднённое значение измерения канала 5 MADC_SRx2: .byte 6 ; Усреднённое значение измерения по каналам после второго усреднения MStrel: .byte 12 ; Значение для стрелки в шагах MTStrel: ; Текущее значение для стрелки в шагах MTStr0: .byte 2 MTStr1: .byte 2 MTStr2: .byte 2 MTStr3: .byte 2 MTStr4: .byte 2 MTStr5: .byte 2 Для IAR ассемблера, естественно, используется принцип размещения структур Си. Причём очень органично всё получается. Приведу пример: Вот структура в Си Код struct { uint8_t OutBuf[32]; // 0 uint8_t *HeadOutBuf,*EndOutBuf; // +32 +34 uint8_t AddrWake; // +36 uint8_t ComAnswerWake, // +37 ParComAnswer, // +38 Com485; // +39 uint16_t LenPack485; // +40 RS232. Длина передаваемого пакета данных uint8_t *EndInBuf; // +42 RS232. Указатель на конец принятых данных struct { uint8_t Answ485 : 1, // Выдать ответ по rs485 Esc485 : 1, // Пришёл код FESC с RS485 RcvCompl : 1, // Разрешить исполнение команд Ldr : 1, // Разрешить загрузку ПО NoEndPacket : 1; // Пакет незавершён } Flag; // +44 } volatile Out485; Вот её объявление на ASMе Код EXTERN Out485
#define HeadOutBuf 32 // +32 #define EndOutBuf 34 // +34 #define AddrWake 36 // +36 #define ComAnswerWake 37 // +37 #define ParComAnswer 38 // +38 #define Com485 39 // +39 #define LenPack485 40 // +40 RS232. Длина передаваемого пакета данных 16 #define EndInBuf 42 // смещение +41 RS232. Указатель на конец принятых данных #define FlagS 44 // +43 Признаки #define Answ485 0 // Бит 0 Выдать ответ по rs485 #define Esc485 1 // Бит 1 Пришёл код FESC с RS485 #define RcvCompl 2 // Бит 2 Разрешить исполнение команд #define Ldr 3 // Бит 3 Разрешить загрузку ПО #define NoEndPacket 4 // Бит 4 Пакет незавершён Вот пример обращения к полю Код ldd crc485,Z+AddrWake // AddrWake std Z+HeadOutBuf,ZL // HeadOutBuf std Z+HeadOutBuf+1,ZH // HeadOutBuf+1 ldi data485,FEND
|
|
|
|
|
Mar 10 2009, 08:27
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(SasaVitebsk @ Mar 10 2009, 00:07)  Ещё раз отмечаю. Само написание проги на асме, как правило занимает даже меньше времени (особенно для млких проектов) чем на асме. Я имею ввиду грамотное написание там и там. Но ... сопровождение и развитие проекта на Си ... на порядок быстрее и комфортнее. На порядок это в 10 раз. И это не для красного словца, а это приблизительно мои оценки затрат. Что такое "на порядок", я знаю  . Порядок/не порядок - всё зависит от правильного оформления. Я вначале (как многие, думаю) не понимал нафига эта куча комментариев, правила поименования и т.д. Пришло со временем. Цитата(SasaVitebsk @ Mar 10 2009, 00:07)  По обсуждаемой теме всётаки на мой взгляд правильнее автоматическое выделение памяти. А не относительное со смещением. То есть я не вижу преимуществ (Зато кучу недостатков) в конструкции типа: Код .equ SRAM_NEXT_1 = SRAM_START + 1; .equ SRAM_NEXT_2 = SRAM_NEXT_1 + 10; .equ SRAM_NEXT_3 = SRAM_NEXT_2 + 100; На мой взгляд правильнее конструкция типа: Код .dseg .org SRAM_START_ADR SRAM_START: .byte 1 SRAM_NEXT_1: .byte 10 SRAM_NEXT_2: .byte 100 SRAM_NEXT_2: Причём 1,10,100 я бы задал через "equ". +100 А вот это я не понял, зачем: Цитата(SasaVitebsk @ Mar 10 2009, 00:07)  Вот её объявление на ASMе Код EXTERN Out485
#define HeadOutBuf 32 // +32 #define EndOutBuf 34 // +34 #define AddrWake 36 // +36 #define ComAnswerWake 37 // +37 #define ParComAnswer 38 // +38 #define Com485 39 // +39 ... Если задана структура Код OutBuf: byte 32; // 0 HeadOutBuf: byte 2 EndOutBuf: byte 2 // +32 +34 AddrWake: byte 2 // +36 ComAnswerWake: byte 1 // +37 ParComAnswer: byte 1 // +38 Com485: byte 1 // +39 и т.д. Я пишу Код LD2 Z,OutBuf // LD2 макрос 2-байтовой загрузки std Z+ AddrWake-OutBuf и не надо всех этих дефайнов.
|
|
|
|
|
Mar 10 2009, 17:34
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(Maik-vs @ Mar 10 2009, 12:27)  А вот это я не понял, зачем: .... и не надо всех этих дефайнов. То что вы написали - понятно. Согласен. Просто в моём примере - структура объявлена на Си. В файле ASMа, я её объявляю внешней. Поэтому не могу размещать заново. А дефайнами объявляю смещение полей. Ну а асмовое обращение - фактически именное получается. Наглядно на мой взгляд. Можно, наверное, наоборот. Размещать на асме как вы, а в Си-шном модуле объявлять её внешней. Тогда будет как в вашем примере. У меня просто порядок написания был "от Си".
|
|
|
|
|
Mar 10 2009, 17:56
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(galjoen @ Mar 10 2009, 18:55)  Пусть они там говорят, что 10 раз всё это исправили. Не верю я им больше. И не вижу смысла в риске. Если рассматривать под таким углом (я не ярый сторонник Си), то получается как-бы такое: в случае асма между программером и железом кроме примитивной программы нет никаких посредников. В случае Си - есть. Отсюда появились всякие MISRA и прочие "нематериальные сущности" Цитата(SasaVitebsk @ Mar 10 2009, 20:34)  Можно, наверное, наоборот. Размещать на асме как вы, а в Си-шном модуле объявлять её внешней. Тогда будет как в вашем примере. У меня просто порядок написания был "от Си".  На примере WinAVR: в одном хедере содержится описание полей для гнутого асма и typedef Код #ifndef __ASSEMBLER__ typedef struct { uint8_t field1; unsigned flag1:1; unsigned flag2:1; unsigned enu:6; } packet_t
volatile packet_t pack;
#else
#define packet_field1 0 #define packet_flag1 0x01 #define packet_flag2 0x02 #define packet_enu_msk 0xfc #define packet_enu_offset 0x02 #define flags 0x01 #define sz_packet 2 .extern pack
#endif
|
|
|
|
|
Mar 11 2009, 08:46
|
Участник

Группа: Новичок
Сообщений: 24
Регистрация: 20-10-06
Пользователь №: 21 500

|
Цитата(galjoen @ Mar 8 2009, 13:45)  ... Код .MACRO TAB_Z subi ZL,low(-low(@0)); получение sbc ZH,ZH; адреса в subi ZH,low(-high((@0)-1))-1; таблице .ENDMACRO ... Спасибо за интересный ход, ибо ситуация действительно частая. Сам долгое время работал с ассемблером, но в последнее время, ввиду объемности проектов, пользуюсь связкой eclipse+gcc (последняя сборка от Klen'а), однако по-прежнему, в критических местах люблю подписать на асме. попытка внедрить этот код увенчалась провалом - никак компилятор сожрать не может такую конструкцию Код "subi %A[queue],-lo8(%[heap])" "\n\t" /*получение*/ "sbc %B[queue],%B[queue]" "\n\t" /*адреса в*/ "subi %B[queue],lo8(-hi8(%[heap]-1)-1)" "\n\t" /*таблице*/ ошибки выдает дурные C:\DOCUME~1\electro\LOCALS~1\Temp/ccX8y7d0.s:1163: Error: garbage at end of line C:\DOCUME~1\electro\LOCALS~1\Temp/ccX8y7d0.s:1165: Error: `)' required C:\DOCUME~1\electro\LOCALS~1\Temp/ccX8y7d0.s:1165: Error: garbage at end of line судя по всему не может выполнять арифметические операции потому как простейшие конструкции типа Код "subi %A[queue],lo8(%[heap])" "\n\t" /*получение*/ "subi %B[queue],hi8(%[heap])" "\n\t" /*таблице*/ или "subi %A[queue],%A[heap]" "\n\t" /*получение*/ "subi %B[queue],%B[heap]" "\n\t" /*таблице*/ скармливаются успешно чуть более подробный код для введения в курс дела: CODE struct { uint8_t Put; uint8_t Get; MPACKET* Container[CONST_FREEMEM_QUEUE_SIZE]; }QueueFreePacket;
исходный код на С void QueuePut(TQUEUE* Queue,MPACKET* Packet){ if (Packet){ if(Queue){ //uint8_t tmp=Queue->Put + 1; //if(tmp==CONST_QUEUE_SIZE)tmp=0;
uint8_t tmp=Queue->Put - (CONST_QUEUE_SIZE-1); if(tmp)tmp+=CONST_QUEUE_SIZE;
if (tmp!=Queue->Get){ Queue->Container[Queue->Put]=Packet; Queue->Put=tmp; return; } } QueueFreePacket.Container[QueueFreePacket.Put++]=Packet; if (QueueFreePacket.Put==CONST_FREEMEM_QUEUE_SIZE) QueueFreePacket.Put=0; } }
часть асемблерной вставки для помещения пакета в очередь свободных пакетов __asm__ __volatile__( ..... "pkt_move_to_heap%=:" "\n\t" "lds %A[queue],%[heap]" "\n\t" "mov %[tmp],%A[queue]" "\n\t" "subi %A[queue],-lo8(%[heap])" "\n\t" /*получение*/ "sbc %B[queue],%B[queue]" "\n\t" /*адреса в*/ "subi %B[queue],lo8(-hi8(%[heap]-1)-1)" "\n\t" /*таблице*/ "st %a[queue]+,%A[pkt]" "\n\t" "st %a[queue],%B[pkt]" "\n\t" "subi %[tmp],(%[heap_size]-1)<<1" "\n\t" "cpse %[tmp],__zero_reg__" "\n\t" "subi %[tmp],-(%[size]<<1)" "\n\t" "sts %[heap],%[tmp]" "\n\t"
"exit%=:" "\n\t" : "=&d"(tmp) : [queue]"b"(Queue),[pkt]"w"(Packet),[tmp]"r"(tmp),[size]"M"(CONST_QUEUE_SIZE),[heap]"m"(QueueFreePacket),[heap_size]"M"(CONST_FREEMEM_QUEUE_SIZE) : "1","memory" );
Подскажите как коректно переписать это место ассемблерной вставки
Сообщение отредактировал yod - Mar 11 2009, 08:49
|
|
|
|
|
Mar 11 2009, 14:53
|
Знающий
   
Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640

|
Цитата(yod @ Mar 11 2009, 11:46)  ... Подскажите как коректно переписать это место ассемблерной вставки  Я так понимаю, что отрицательное число от "lo8" будет уже не lo8, а int. Т.е. -lo8 преобразуется в int, и вот в этом ошибка, как мне кажется (хотя при чём там мусор?). Поэтому я на асме от него low беру. Хотя некоторые асмы и так понимают. А в вашем случае, чтоб компилятору умничать не позволять, лучше наверное 0xFF& везде делать. Ещё рекомендую на скобках не экономить. Компиляторы они ведь очень умничать любят... Хотя и пробовать нужно конечно. А у меня негде. Т.е. что-то типа такого я написал бы. Код "subi %A[queue],(0xFF&(0-(0xFF&(%[heap]))))" "\n\t" /*получение*/ "sbc %B[queue],%B[queue]" "\n\t" /*адреса в*/ "subi %B[queue],(0xFF&(0-(0xFF&((%[heap]-1)>>8))-1))" "\n\t" /*таблице*/ А м.б и ещё раз lo8 поставить в первой и последней строке придётcя. Но вообще, из меня сейчас писатель на Си для авр никакой...
|
|
|
|
|
Mar 11 2009, 18:52
|
Участник

Группа: Новичок
Сообщений: 24
Регистрация: 20-10-06
Пользователь №: 21 500

|
гхм, спасибо, попробовал, не вышло. теперь пишет иную ошибку: C:\DOCUME~1\electro\LOCALS~1\Temp/ccTCdAe5.s: Assembler messages: C:\DOCUME~1\electro\LOCALS~1\Temp/ccTCdAe5.s:1163: Error: invalid sections for operation on `L0' and `QueueFreePacket' из чего, вероятно, можно сделать вывод, что компилятор пытается "с ассемблировать" код раньше чем генерирует адрес структуры
|
|
|
|
|
Mar 11 2009, 19:12
|
Знающий
   
Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640

|
Цитата(yod @ Mar 11 2009, 21:52)  гхм, спасибо, попробовал, не вышло. теперь пишет иную ошибку: C:\DOCUME~1\electro\LOCALS~1\Temp/ccTCdAe5.s: Assembler messages: C:\DOCUME~1\electro\LOCALS~1\Temp/ccTCdAe5.s:1163: Error: invalid sections for operation on `L0' and `QueueFreePacket' из чего, вероятно, можно сделать вывод, что компилятор пытается "с ассемблировать" код раньше чем генерирует адрес структуры М.б. и так. А откуда компилятор `L0' взял? Но хотя тогда почему: Код "subi %A[queue],lo8(%[heap])" "\n\t" /*получение*/ "subi %B[queue],hi8(%[heap])" "\n\t" /*таблице*/ или "subi %A[queue],%A[heap]" "\n\t" /*получение*/ "subi %B[queue],%B[heap]" "\n\t" /*таблице*/ скармливаются успешно Они в том-же месте размещены были? А если постепенно усложнять, то в какой момент компилятор ругаться начнёт? А м.б. два #define, предварительно размещённые, спасут?
|
|
|
|
|
Mar 12 2009, 02:02
|
Участник

Группа: Новичок
Сообщений: 24
Регистрация: 20-10-06
Пользователь №: 21 500

|
при асемблерной вставке сам код предается как строки, так что девайны не спасут. а ругаться компилятор начинает как только перед lo8 или hi8 появляется знак минуса
Сообщение отредактировал yod - Mar 12 2009, 02:02
|
|
|
|
|
Mar 14 2009, 10:02
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(galjoen @ Mar 8 2009, 09:45)  А массив не выровнен, т.е. может переходить через границу 256. Т.е. старший байт адреса может отличаться на 1. Стандартный способ это 4 такта. Но есть способ лучше. Я написал макро, и всегда и использую. Код .MACRO TAB_Z subi ZL,low(-low(@0)); получение sbc ZH,ZH; адреса в subi ZH,low(-high((@0)-1))-1; таблице .ENDMACRO Перед вызовом смещение д.б. в ZL. Параметр в этой макрокоманде - адрес начала таблицы. В байтах если это данные, в словах если это таблица переходов. Такие макрокоманды у меня обычно и для Y и для X описаны. Рекомендую... Цитата(Сергей Борщ @ Mar 8 2009, 11:52)  Красиво! Спасибо, записал на корочку. Цитата(_Pasha @ Mar 8 2009, 12:04)  Респект! А говорят, что про асм и AVR уже все известно... А-а-а-а!!!! Мужики, что вы делаете? Я на собственной шкуре убедился в реальности тех психологических экспериментов, когда садят человека в компании, как он думает, таких же испытуемых, задают всем несколько вопросов, а потом показывают белый листик и спрашивают "какой цвет?" все говорят "чёрный", доходят до испытуемого, он мучается, перекашивается лицом, но говорит "чёрный". Сначала я пожал плечами. Хотел уже написать в форум. Потом решил, что вечер и я чего-то не соображаю. Долго не мог понять, о каких четырёх тактах речь, если мы говорим об ассемблерном коде, а не том, что генерит gcc. Даже скопировал этот макрос в файл, чтобы утром разобраться. В не очень хорошем состоянии сейчас, так и утром тоже тупил довольно долго (мучался и перекашивался лицом ;-) ). Никаких фокусов с sbc и сложными выражениями тут не надо. Код .MACRO TAB_Z clr ZH subi ZL, low( -@0 ) sbci ZH, high( -@0 ) .ENDMACRO Цитата(yod @ Mar 11 2009, 10:46)  Подскажите как коректно переписать это место ассемблерной вставки  Ну теперь, очевидно, так: Код uint8_t table[8];
uint8_t rd(uint8_t index) { return table[index]; }
uint8_t rda(uint8_t index) { uint8_t result; __asm__ __volatile__ ( "clr %B[ptr]" "\n\t" "subi %A[ptr], lo8(-%[tbl])" "\n\t" "subi %B[ptr], hi8(-%[tbl])" "\n\t" "ld %[result], %a[ptr]" : [result]"=r"(result) : [ptr]"e"(index), [tbl]"m"(table[0]) ); return result; } Код rd: ldi r30,lo8(table) ldi r31,hi8(table) add r30,r24 adc r31,__zero_reg__ ld r24,Z clr r25 ret
rda: mov r30,r24 /* #APP */ clr r31 subi r30, lo8(-table) subi r31, hi8(-table) ld r24, Z /* #NOAPP */ clr r25 ret upd: Тю, gcc генерит то, что надо, а ассемблер потом ругается. upd2: Ещё одни скобки нужны, без них он путается в том, от какого нуля нужно онять tbl для получения -tblЦитата "subi %A[ptr], lo8(-(%[tbl]))" "\n\t" "subi %B[ptr], hi8(-(%[tbl]))" "\n\t" Так линкуется и дизассемблер покзывает что надо. (опять туплю - пока не полез в свой же рабочий асмовый исходник - не вспомнил... как бы это выспаться...)
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 14 2009, 16:27
|
Знающий
   
Группа: Свой
Сообщений: 841
Регистрация: 10-05-07
Из: Чебоксары (Россия)
Пользователь №: 27 640

|
Цитата(ReAl @ Mar 14 2009, 13:02)  Никаких фокусов с sbc и сложными выражениями тут не надо. Код .MACRO TAB_Z clr ZH subi ZL, low( -@0 ) sbci ZH, high( -@0 ) .ENDMACRO Согласен. Сам долго не мог вспомнить почему я так написал (с sbc ZH,ZH). Тоже полез в исходники. И вот что там нашёл: Код .MACRO TAB2_Z subi ZL,low(-low(@0)); получение sbc ZH,ZH ; адреса sub ZL,@1 ; в sbci ZH,low(-high((@0)-1))-1; таблице .ENDMACRO Вот он прародитель. Для двумерного массива он сделан был. Потом я его скопировал, лишний sub убрал и sbci на subi изменил. И получился у меня вариант для одномерного массива.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|