Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос к ассемблерщикам
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
_Алексей_
Пример: .equ Napruga = SRAM_START+123
Таких директив может быть сотня и более.
Иногда возникает необходимость вставить посередине новую директиву или расширить массив. Из-за этого возникают проблемы, что нужно менять адресацию. Приходиться много править.
Существуют ли какие-нибудь методы или вспомогательные программы позволяющие решить данную проблему?
bbill
Самый удобный способ, резервирование памяти, расстановку компилятор выполнит автоматически.

;****** Сегмент данных ******
;***************************
.dseg
;****************************
; можно по одному байту
status_system: .byte 1 ;

;можно массивом
data_convert_adc: .byte 12 ;- данные преобразование АЦП
data_sorti_adc: .byte 10 ;- массив для сортировки измеренных значений
average_value_adc: .byte 2 ;- среднее значение измеренного напряжения

Можно вставить/добавить в любое место и далее обращаться по имени.

А в программе:
lds temp,status_system;считать содержимое

Почитайте описание на ассемблер, там это есть.
777777
Цитата(_Алексей_ @ Mar 2 2009, 12:17) *
Пример: .equ Napruga = SRAM_START+123
Таких директив может быть сотня и более.

Почему-то все (без исключения!) программисты, которых я встречал, счтали, что они знают язык ассемблера на том основании, что они знают систему команд и их мнемоники. Некоторые знали директиву equ, а многие даже ее не знали, а распределяли память данных вручную, на листочке, а в программу вбивали готовые числа. О том, чтобы объявлять какие-то там сегменты, они слышали лишь краем уха, сами конечно же никогда этого не делали.
_Pasha
Цитата(777777 @ Mar 2 2009, 14:00) *
 О том, чтобы объявлять какие-то там сегменты, они слышали лишь краем уха, сами конечно же никогда этого не делали.

smile.gif Но и AVRASM тоже хорош - тупой как пробка. Невозможно никаким  макаком описАть структуру, кроме .equ, макросредства - ваще молчу.

Корочче - лучче всего задняя часть антилопы (в смысле  GNU AS)
SasaVitebsk
Цитата(_Pasha @ Mar 2 2009, 14:08) *
smile.gif Но и AVRASM тоже хорош - тупой как пробка. Невозможно никаким  макаком описАть структуру, кроме .equ, макросредства - ваще молчу.

Тоже поддерживаю. По сравнению с тем ассемблером, которым я пользовался для 8051 - это большой скачёк назад. smile.gif
Некоторые моменты отображу.
Код
;-----------------------------------------------------------------------------
.equ    inline    = portd2;(INT0) вход с цифровой линии(_/~~\______/~~~~\______)
;-----------------------------------------------------------------------------
.equ    DTR        = portd4; Готовность компьютера
.equ    portDTR    = portd
.equ    pinDTR    = pind
.equ    ddrDTR    = ddrd
.equ    RTS        = portd3; Запрос передачи компьютера
.equ    portRTS    = portd
.equ    pinRTS    = pind
.equ    ddrRTS    = ddrd

Код
.def    flg2    = r17;регистр битовых признаков No 2
.equ    bline    = 0    ; новая команда от MODEMLN
.equ    ctrll    = 1    ; команда (не данные) от MODEMLN
.equ    ctrlh    = 2    ; команда (не данные) от MODEMH
.equ    bnocar    = 3    ; Пропала несущая
.equ    blast    = 4    ; Выполняется комманда ComL (offline)
.equ    bonline    = 5    ; Бит признака режима (1-online)
.equ    blnint    = 6    ; наличие импульса в телефонной линии (1)
.equ    bautob    = 7    ; запретить AUTOBOD (0-запретить)

.def    outdata    = r18;текущий байт данных в телефонную линию

Код
..equ    lBuf    = $1cf; Длина буферов 463 байта


.dseg
.if chip == 88
    .org    $0100; для ATMEGA88
.else
    .org    $060; для ATMEGA8
.endif

digit:    .byte    1;регистр данных текущей набираемой цифры номера

s0:    .byte    1; число звонков необходимых для автоответа
s1:    .byte    1; счётчик звонков
s2:    .byte    1; +
s3:    .byte    1; cr
s4:    .byte    1; lf
s5:    .byte    1; забой
s6:    .byte    1; число сек. ожидания при "слепом наборе" без dial tone
s7:    .byte    1; ожидание несущей
s8:    .byte    1; время в 0.1 сек на ","
s9:    .byte    1; время в десят. долях сек. установки соед.
s10:    .byte    1; ячейка пользователя


Кстати ассемблер IAR для AVR когда-то был свободно распространяемый. Правда не знаю как с интеграцией его в AVR Studio дела абстоят.

В общем и целом - перешёл на Си и жутко жалею, что не сделал этого лет эдак на 5 раньше.
prottoss
Цитата(_Алексей_ @ Mar 2 2009, 16:17) *
Иногда возникает необходимость вставить посередине новую директиву или расширить массив. Из-за этого возникают проблемы, что нужно менять адресацию. Приходиться много править.
А вот так - древний способ -
Код
.equ    SRAM_START        = 0x0000;
.equ    SRAM_NEXT_1          = SRAM_START + 1;
.equ    SRAM_NEXT_2          = SRAM_NEXT_1 + 10;
.equ    SRAM_NEXT_3          = SRAM_NEXT_2 + 100;

И директив может быть сотня и более.smile.gif А чтобы что то вставить приходится поправить всего-то пару строк.
_Алексей_
>Почитайте описание на ассемблер, там это есть.

Действительно. Даже как-то стыдно стало за свой вопрос.
Сергей Борщ
Цитата(_Pasha @ Mar 2 2009, 12:08) *
Невозможно никаким  макаком описАть структуру, кроме .equ, макросредства - ваще молчу.

Корочче - лучче всего задняя часть антилопы (в смысле  GNU AS)
А можно пример описания структуры средствами GNU AS? Одну штутку можно описать через .byte, .word и т.д. А как описать их несколько одинаковых и как красиво написать обращение к ней, имея в Z адрес начала структуры?
CDT
Цитата(_Алексей_ @ Mar 2 2009, 13:17) *
...
Иногда возникает необходимость вставить посередине новую директиву или расширить массив. Из-за этого возникают проблемы, что нужно менять адресацию. Приходиться много править.
......


Если не хочется чего - не то делать - надо подумать, как этого не делать.
Код
.dseg

.org ... (если очень хочется, но мне не разу не понадобилось. Опять потом искать и менять)

dRcvdBuf:;начало буфера (например, приема)
  dRcvdLen:    .byte    1
  dRcvdAdr:    .byte    2
  dRcvdTime:    .byte    4
  dRcvdName:    .byte    20
  dRcvdErrors:    .byte    1
  dRcvdVolts:    .byte    2
dRcvdBufEnd:;это что бы следить за концом буфера

;И вставляй, что хочешь, само настроиться

;что бы привязать к началу буфера (для использоввания указателей и поддержания
одинакового смещения в разных программах) можно посчитать смещения от начала буфера

Код
.equ shRcvdLen=dRcvdLen-dRcvdBuf
.equ shRcvdAdr=dRcvdAdr-dRcvdBuf
;....................................................
.equ cRcvdBufLen=dRcvdBufE-dRcvdBuf;длина буфера

   ldd   rTmp,z+shRcvdLen

;Можно макрос написать:
Код
.macro mac_BufSet
    @0: .byte @2
    .equ @1=@0-BufStart
.endm
;-------------------------------
.dseg
dRcvdBuf:    
.set BufStart=dRcvdBuf

  mac_BufSet dRcvdLen,shRcvdLen,1
  mac_BufSet dRcvdAdr,shRcvdAdr,2
  mac_BufSet dRcvdTime,shRcvdTime,4
  mac_BufSet dRcvdName,shRcvdName,20
...................
dRcvdBufEnd:

Как и на зеркало, не стоит на ассемблер пенять раньше времени.
Там еще препроцессор есть. Весьма удобная вещь, если научиться.

P.S.
Пришла по дороге идея, но прямо сейчас не на чем проверить:
Код
macro mac_BufSet
    d@0: .byte @1
    .equ sh@0=d@0-BufStart
.endm

  mac_BufSet RcvdLen,1
  mac_BufSet RcvdAdr,2

Еще меньше писанины
_Pasha
Цитата(CDT @ Mar 8 2009, 09:50) *
;Можно макрос написать:
Код
.macro mac_BufSet
    @0: .byte @2
    .equ @1=@0-BufStart
.endm
;-------------------------------


Для того чтобы что-то советовать, желательно хотя бы раз самому поробовать это применить. И вот когда Вы увидите в ответ на желание создать такой макрос, вот это


Цитата
error: .byte directive illegal in macro definition


Я думаю, у Вас возникнет острое желание извиниться за ту чушь, которую Вы написали.
galjoen
Цитата(_Pasha @ Mar 8 2009, 10:10) *
Для того чтобы что-то советовать, желательно хотя бы раз самому поробовать это применить.

+1
А я вот не совсем по теме, но то, что всегда применяю. Тоже про доступ к данным.
Чаще всего приходится использовать таблицы в FLASH или ОЗУ размером до 256 байт или слов. В регистре находится N элемента (индекс массива) и к этому N нужно прибавить адрес начала массива. А массив не выровнен, т.е. может переходить через границу 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 описаны. Рекомендую...
Сергей Борщ
Цитата(galjoen @ Mar 8 2009, 09:45) *
Такие макрокоманды у меня обычно и для Y и для X описаны. Рекомендую...
Красиво! Спасибо, записал на корочку.
_Pasha
Цитата(galjoen @ Mar 8 2009, 10:45) *
Но есть способ лучше.

Респект! А говорят, что про асм и AVR уже все известно... 
Maik-vs
Какое странное и невнятное обсуждение. То есть некоторые обвиняют ассемблер в его "бедности", не понимании структур и т.д. А я вот видел множество обсуждений сишников: то как объявить переменную в нужной памяти, то как проинвертировать бит в порту то ещё что-нибудь, что у ассемблерщика вызовет недоумённую улыбку.
Такой язык. И можно написать кучу макросов каждому на свой вкус, в том числе и для доступа к структурам. К Вашим структурам. А вообще-то конечно, кому что - есть и VBA или вот ЛИСП интересный язык smile.gif
CDT
Цитата(_Pasha @ Mar 8 2009, 11:10) *

Что ж так нервничать. Можно было бы и предложить правильное решение.
Я сразу предупредил, что обкатать не на чем было.
И что думать надо говорил.
Сейчас есть на чем обкатать.

Вот то, что работает.
Код
;задает: dX-мл. адр. блока ячеек, shX-смещение от начала буфера, cX- длина данного блока ячеек
;Y - число выделяемых ячеек
.macro mac_BufSet;X,Y
    .equ d@0=BufNext
    .equ sh@0=d@0-BufStart
    .equ c@0=@1
    .set BufNext=BufNext+@1
.endm
;-------------------------------
.dseg

.equ cRcvdNameLen=20

dRcvdBuf:    
   .set BufStart=dRcvdBuf;задаем начало определяемого буфера
   .set BufNext=dRcvdBuf

    mac_BufSet RcvdLen,1
    mac_BufSet RcvdAdr,2
    mac_BufSet RcvdTime,4
    mac_BufSet RcvdName, cRcvdNameLen

.equ dRcvdBufEnd=BufNext        ;задаем конец определяемого буфера
.byte dRcvdBufEnd-dRcvdBuf;резервируем ОЗУ под определяемый буфер

.cseg

Интересно, что работают конструкции типа:
Код
    .equ c@0Long=@1;добавляет к базовой метке "с" и "Long"
    .equ @0@2=@1;собирает в одну метку 0-й и 2-й параметр макроса

Можно и еще чего по вычислять, зависимое от этих определений.
А кто еще чего полезного предложит?
SasaVitebsk
Цитата(Maik-vs @ Mar 8 2009, 19:17) *
Какое странное и невнятное обсуждение. То есть некоторые обвиняют ассемблер в его "бедности", не понимании структур и т.д. А я вот видел множество обсуждений сишников: то как объявить переменную в нужной памяти, то как проинвертировать бит в порту то ещё что-нибудь, что у ассемблерщика вызовет недоумённую улыбку.
Такой язык. И можно написать кучу макросов каждому на свой вкус, в том числе и для доступа к структурам. К Вашим структурам. А вообще-то конечно, кому что - есть и VBA или вот ЛИСП интересный язык smile.gif

Ещё раз отмечаю. Само написание проги на асме, как правило занимает даже меньше времени (особенно для млких проектов) чем на асме. Я имею ввиду грамотное написание там и там. Но ... сопровождение и развитие проекта на Си ... на порядок быстрее и комфортнее. На порядок это в 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
adc
Цитата(SasaVitebsk @ Mar 10 2009, 00:07) *
Само написание проги на асме, как правило занимает даже меньше времени (особенно для млких проектов) чем на асме.

"Золотые слова Юрий Бенедиктович и человек ты золотой,не бережёшь ты себя,отдохнуть тебе надо." (НР) rolleyes.gif
_Pasha
Цитата(CDT @ Mar 9 2009, 09:15) *
Что ж так нервничать. Можно было бы и предложить правильное решение.
Я  не нервный. Более того, в предыдущем посте Вы совершенно логично мыслили. Беда в том, что AVRASM хоть 1 хоть 2 хоть пицот - дебильные асмы.
Maik-vs
Цитата(SasaVitebsk @ Mar 10 2009, 00:07) *
Ещё раз отмечаю. Само написание проги на асме, как правило занимает даже меньше времени (особенно для млких проектов) чем на асме. Я имею ввиду грамотное написание там и там. Но ... сопровождение и развитие проекта на Си ... на порядок быстрее и комфортнее. На порядок это в 10 раз. И это не для красного словца, а это приблизительно мои оценки затрат.

Что такое "на порядок", я знаюsmile.gif.
Порядок/не порядок - всё зависит от правильного оформления. Я вначале (как многие, думаю) не понимал нафига эта куча комментариев, правила поименования и т.д. Пришло со временем.
Цитата(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

и не надо всех этих дефайнов.
SasaVitebsk
Цитата(Maik-vs @ Mar 10 2009, 12:27) *
А вот это я не понял, зачем:
....
и не надо всех этих дефайнов.

То что вы написали - понятно. Согласен.
Просто в моём примере - структура объявлена на Си. В файле ASMа, я её объявляю внешней. Поэтому не могу размещать заново. А дефайнами объявляю смещение полей.

Ну а асмовое обращение - фактически именное получается. Наглядно на мой взгляд.

Можно, наверное, наоборот. Размещать на асме как вы, а в Си-шном модуле объявлять её внешней. Тогда будет как в вашем примере. У меня просто порядок написания был "от Си". smile.gif
_Pasha
Цитата(galjoen @ Mar 10 2009, 18:55) *
Пусть они там говорят, что 10 раз всё это исправили. Не верю я им больше. И не вижу смысла в риске.

Если рассматривать под таким углом (я не ярый сторонник Си), то получается как-бы такое: в случае асма между программером и железом кроме примитивной программы нет никаких посредников. В случае Си - есть. Отсюда появились всякие MISRA и прочие "нематериальные сущности"

Цитата(SasaVitebsk @ Mar 10 2009, 20:34) *
Можно, наверное, наоборот. Размещать на асме как вы, а в Си-шном модуле объявлять её внешней. Тогда будет как в вашем примере. У меня просто порядок написания был "от Си". smile.gif

На примере 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


 
yod
Цитата(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"
);

Подскажите как коректно переписать это место ассемблерной вставки laughing.gif
galjoen
Цитата(yod @ Mar 11 2009, 11:46) *
...
Подскажите как коректно переписать это место ассемблерной вставки laughing.gif

Я так понимаю, что отрицательное число от "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я. Но вообще, из меня сейчас писатель на Си для авр никакой...
yod
гхм, спасибо, попробовал, не вышло.
теперь пишет иную ошибку:
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'
из чего, вероятно, можно сделать вывод, что компилятор пытается "с ассемблировать" код раньше чем генерирует адрес структуры
galjoen
Цитата(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, предварительно размещённые, спасут?
yod
при асемблерной вставке сам код предается как строки, так что девайны не спасут.
а ругаться компилятор начинает как только перед lo8 или hi8 появляется знак минуса
_Pasha
Цитата(yod @ Mar 11 2009, 11:46) *
Подскажите как коректно переписать это место ассемблерной вставки


Не пользуйтесь идиотскими фичами, и счастие да пребудет с Вами smile.gif 
ReAl
Цитата(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) *
Подскажите как коректно переписать это место ассемблерной вставки laughing.gif

Ну теперь, очевидно, так:
Код
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"

Так линкуется и дизассемблер покзывает что надо.

(опять туплю - пока не полез в свой же рабочий асмовый исходник - не вспомнил... как бы это выспаться...)
SasaVitebsk
Цитата(ReAl @ Mar 14 2009, 14:02) *
как бы это выспаться...

bb-offtopic.gif
Просто. Забить на всё и выспаться. smile.gif
Я вот закончил первую часть проекта и отоспался... (Формально занимаюсь второй частью) smile.gif
Даже 2 раза за неделю на рыбалку съездил... Лафа!!!
galjoen
Цитата(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 изменил. И получился у меня вариант для одномерного массива.
ReAl
Цитата(galjoen @ Mar 14 2009, 18:27) *
Для двумерного массива он сделан был. Потом я его скопировал, лишний sub убрал и sbci на subi изменил. И получился у меня вариант для одномерного массива.
Тогда понятно smile.gif Но напугали мну крепко.
Не зря кто-то сказал - для радикального улучшения программного обеспечения нуна просто из всех редактров убрать функцию "копировать-вставить" biggrin.gif

Кстати, в любом случае low(-high((@0)-1)) - 1 не нужно, это просто длинный путь сделать high( -(@0) )
ReAl
Опа, тут мне на описку указали, а я уже не могу поправить сообщение.
Цитата(ReAl @ Mar 14 2009, 12:02) *
"subi %A[ptr], lo8(-(%[tbl]))" "\n\t"
"sbci %B[ptr], hi8(-(%[tbl]))" "\n\t"

Всё тот же копипаст :-) - сдублировал строку и не всё в ней отредактировал
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.