Перейти к содержанию
    

Битовые поля, кто ж вас выдумал?

4 minutes ago, esaulenka said:

Объясните, пожалуйста.

Например непонимание работы exclusive monitor'а ядра тут:

Quote

Если между LDREX и STREX произошло прерывание и оно что-то записало в память (а оно обязательно хоть регистры, да сохранит в стек), то STREX ничего не запишет в память и в выходной регистре будет записана 1.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, Rst7 said:

Например непонимание работы exclusive monitor'а ядра тут:

Это прямая цитата из статьи изиэлектроникса, которую написал @neiver. Вполне грамотный дядька, я б ему тоже поверил.

Зря... Его там ниже поправили, но в самой статье ничего не поменялось.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Когда мы в прошлый раз проверяли всё это дело практически, то выяснили, что прерывания таки сбрасывают флаг экслюзивного доступа, даже если в обработчике ничего не делается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

17 minutes ago, AHTOXA said:

что прерывания таки сбрасывают флаг экслюзивного доступа, даже если в обработчике ничего не делается.

Я не об этом. Обычная запись в память (или чтение) между LDREX/STREX не сбрасывает флаг.

volatile unsigned int testvar;
volatile unsigned int testvar2;
void TestEX(void)
{
  unsigned int tv;
  tv=__LDREX(&testvar);
  __no_operation();
  __no_operation();
  __no_operation();
  testvar2=1;
  testvar2;
  __no_operation();
  __no_operation();
  __no_operation();
  tv=__STREX(tv,&testvar);
  DEBUG_PRINTF("__STREX result %d\r\n",tv);
}

Такой код печатает "__STREX result 0", несмотря на наличие LDR/STR между LDREX/STREX.

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

 

Ага, вот в чем дело (из мануала на CM4)

Quote

The processor removes its exclusive access tag if:

• It executes a CLREX instruction.

• It executes a Store-Exclusive instruction, regardless of whether the write succeeds.

• An exception occurs. This means the processor can resolve semaphore conflicts between different threads.

Т.к. прерывания - это тоже эксепшн, то вот и ответ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, это только к Cortex-M относится, всякие -А вроде не сбрасывают.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, haker_fox сказал:

Как я понимаю, зависит от little или big-endian. Во всяком случае заголовчники для микроконтроллеров строятся на этом принципе и работают. Более того, обмениваемся битовыми полями, изготовленными двумя разными компиляторами: IAR и GCC. Но за документ спасибо!

Но, на удивление, работает. А что вы используете вместо полей? Кстати я использую поля активно не только для доступа к регистрам. Очень удобная штука. Пока не подводила.

Не совсем, компилятор может выбрать какой-то способ, по своей логике.

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

Постепенно убираю их из своих исходников в пользу дедовских сдвигов и битовых операций. Естетсвенно стараюсь обернуть это в разумные сервисные функции с логическим смыслом, без портянок в более высокоуровневом коде. Думал над темплейт-класс магией, но морально пока не созрел.

38 минут назад, Rst7 сказал:

Я не об этом. Обычная запись в память (или чтение) между LDREX/STREX не сбрасывает флаг.

Ага, вот в чем дело (из мануала на CM4)

Эээ т.е. если просто записать в тот же адрес STR'ом вся схема сломается?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Rst7 сказал:

Я не об этом. Обычная запись в память (или чтение) между LDREX/STREX не сбрасывает флаг.

Да, обычная запись не сбрасывает. Но всё же объяснение

Цитата

Если между LDREX и STREX произошло прерывание и оно что-то записало в память...

- верно описывает результат. Хотя причины объясняет неверно :-)

40 минут назад, Kabdim сказал:

Эээ т.е. если просто записать в тот же адрес STR'ом вся схема сломается?

Естественно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Дык, RISC vs CISC. Не удивлюсь, если в x86 где-то на уровне микрокода всё делается примерно так же, через какие-то свои LDREX/STREX :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Kabdim сказал:

Жесть, насколько же x86 в этом аспекте прямолинейно правильней.

В чём правильней? И что неправильного в механизме LDREX/STREX? Вроде там всё предельно ясно и логично.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, AHTOXA said:

- верно описывает результат. Хотя причины объясняет неверно :-)

Верно описывает результат только для Cortex-M. Потому что объяснение неверное.

3 hours ago, Kabdim said:

Эээ т.е. если просто записать в тот же адрес STR'ом вся схема сломается?

А зачем писать в переменную, к которой Вы организуете эксклюзивный доступ, обычным способом?

2 hours ago, Kabdim said:

Жесть, насколько же x86 в этом аспекте прямолинейно правильней.

Только менее универсальный. Например, взять элемент из списка на ARM выглядит так:

#define ExAddr(VAL) ((volatile unsigned int *)(&(VAL)))

typedef struct LLITEM
{
  struct LLITEM *next;
  unsigned char data[100];
}LLITEM;

volatile LLITEM *FreeBlocks;

LLITEM *AllocBlock(void)
{
  LLITEM *p;
  LLITEM *next;
  do
  {
    p=(LLITEM*)__LDREX(ExAddr(FreeBlocks));
    if (!p) {__CLREX(); return p;}
    next=p->next;
  }while(__STREX((unsigned long)next,ExAddr(FreeBlocks)));
  return p;
}
Spoiler

    163          LLITEM *AllocBlock(void)
    164          {
   \                     AllocBlock: (+1)
   \        0x0   0x.... 0x....      LDR.W    R2,??DataTable6_1
    165            LLITEM *p;
    166            LLITEM *next;
    167            do
    168            {
    169              p=(LLITEM*)__LDREX(ExAddr(FreeBlocks));
   \                     ??AllocBlock_0: (+1)
   \        0x4   0xE852 0x0F00      LDREX    R0,[R2]
    170              if (!p) {__CLREX(); return p;}
   \        0x8   0xB128             CBZ.N    R0,??AllocBlock_1
    171              next=p->next;
    172            }while(__STREX((unsigned long)next,ExAddr(FreeBlocks)));
   \        0xA   0x6803             LDR      R3,[R0, #+0]
   \        0xC   0xE842 0x3100      STREX    R1,R3,[R2]
   \       0x10   0x2900             CMP      R1,#+0
   \       0x12   0xD1F7             BNE.N    ??AllocBlock_0
    173            return p;
   \       0x14   0x4770             BX       LR               ;; return
   \                     ??AllocBlock_1: (+1)
   \       0x16   0xF3BF 0x8F2F      CLREX    
   \       0x1A   0x4770             BX       LR
    174          }

 

А на x86 с его единственным lock'ом надо извращаться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

52 минуты назад, jcxz сказал:

В чём правильней? И что неправильного в механизме LDREX/STREX? Вроде там всё предельно ясно и логично.

Тем что его нельзя сломать, даже если захочется.

46 минут назад, Rst7 сказал:

на x86 с его единственным lock'ом надо извращаться.

Есть такое. Если бы load/store гарантировали что их нельзя сломать...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, Kabdim said:

Если бы load/store гарантировали что их нельзя сломать...

В смысле?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мое понимание такое, что если между LDREX и STREX было прерывание, то STREX не сработает, потому  что при каждом входе и выходе из прерывания выполняется CLREX.

Изменено пользователем lamer0k

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...