jcxz 184 23 июня, 2015 Опубликовано 23 июня, 2015 · Жалоба Если бы эксклюзивные операции отслеживали только сами себя, толку от них было бы никакого. Так можно и обычным флагом обойтись, когда захотел - установил, когда надо - проверил... Смысл именно в том, что мониторится любое обращение к памяти А зачем Вам мониторить все обращения? Ведь нужны только те обращения, которые могут использоваться для доступа к переменным синхронизации. Если Вам нужна чтение-модификация-запись переменной синхронизации, или неатомарное чтение (несколькиим командами) этой переменной, или запись (любая) в эту переменную, то извольте все эти операции выполнять только инструкциями LDREX/STREX. Тогда всё будет нормально и ставить этот бит по каждому обращению к памяти совсем излишне (но конечно возможно для упрощения реализации ядра CPU). А просто чтение этой-же переменной синхронизации можно делать и вообще одной командой LDR (которая априори атомарна) пусть даже она и попадёт между LDREX и STREX выполняющимися в другом потоке - это никак не повлияет на результат. В Cortex-M4 операция STREX даст отбой даже если в прерывании запись была сделана командой STR и совсем в другую ячейку памяти. Вполне возможно для упрощения реализации механизма в ядре сделали срабатывание не только на эксклюзивный доступ. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 2 23 июня, 2015 Опубликовано 23 июня, 2015 · Жалоба Вполне возможно для упрощения реализации механизма в ядре сделали срабатывание не только на эксклюзивный доступ. С LDREX/STREX все еще более запутанней. Решил тут протестировать как там насчет работы из разных областей памяти. Выяснилось, что LDREX/STREX правильно работает когда переменные находятся в RAM вблизи 0x1000_0000-0x3000_0000 То, что кэширование разное сверху и снизу границы 0x2000_0000 никак не влияет, барьеры памяти можно не ставить. А вот если использовать память которая находится после границы 0x4000_0000 , то пара LDREX/STREX там никакого эффекта не дает, хотя и исключений не вызывает. Т.е. можно спокойно испортить переменную, а STREX ничего не покажет. Ну и как положительный момент можно отметить, что выполнение кода из RAM на работу LDREX/STREX тоже не влияет. А с DMA вопрос еще темный. Мутный момент также с областями внешней памяти. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 23 июня, 2015 Опубликовано 23 июня, 2015 · Жалоба Выяснилось, что LDREX/STREX правильно работает когда переменные находятся в RAM вблизи 0x1000_0000-0x3000_0000 А какой контроллер вы тестировали? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 2 23 июня, 2015 Опубликовано 23 июня, 2015 · Жалоба А какой контроллер вы тестировали? MK60FN1M0VLQ12 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ArtDenis 0 23 июня, 2015 Опубликовано 23 июня, 2015 (изменено) · Жалоба На моём STM32L151 получились такие результаты: Монитор НЕ отлавливает нарушение эксклюзивного доступа при простом изменение области памяти для которой был вызван LDREX или любой другой области памяти Монитор отлавливает нарушение эксклюзивного доступа если 1. Был вызван STREX на любую область ОЗУ (не обязательно на ту, для которой был вызван LDREX) 2. Произошло любое прерывание Изменено 23 июня, 2015 пользователем ArtDenis Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 23 июня, 2015 Опубликовано 23 июня, 2015 · Жалоба Т.е. можно спокойно испортить переменную, а STREX ничего не покажет. Вы портили при помощи другой STREX или просто STR? Если второе - эксперимент некорректный. И надо посмотреть как классифицируется память находящаяся по этим адресам. Возможна это область памяти периферии, возможно с этим связано, лень заглядывать в карту памяти в описании М-ядра. :-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 2 23 июня, 2015 Опубликовано 23 июня, 2015 · Жалоба Монитор отлавливает нарушение эксклюзивного доступа если 2. Произошло любое прерывание Странно, у меня не на любое, а только такое где был STREX или STR во внутреннюю RAM , а вот на PUSH в ту же RAM не реагирует. Вы портили при помощи другой STREX или просто STR? Если второе - эксперимент некорректный. И надо посмотреть как классифицируется память находящаяся по этим адресам. Возможна это область памяти периферии, возможно с этим связано, лень заглядывать в карту памяти в описании М-ядра. :-) Конечно использовал STREX. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ArtDenis 0 23 июня, 2015 Опубликовано 23 июня, 2015 · Жалоба Странно, у меня не на любое, а только такое где был STREX или STR во внутреннюю RAM , а вот на PUSH в ту же RAM не реагирует Вообще, в прерывании был STR. Не подумал когда тестировал, что это имеет значение Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ArtDenis 0 24 июня, 2015 Опубликовано 24 июня, 2015 · Жалоба Вообще, в прерывании был STR. Не подумал когда тестировал, что это имеет значение Проверил ещё раз. Достаточно любого прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 24 июня, 2015 Опубликовано 24 июня, 2015 · Жалоба Программы - в студию. И выводы, желательно, не противоречивые. :rolleyes: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ArtDenis 0 24 июня, 2015 Опубликовано 24 июня, 2015 (изменено) · Жалоба Программы - в студию. К сожалению по мере тестирования программа менялась :( Последний вариант - тестирование пустого прерывания. Устроит? А выводы - вроде как работает, но не настолько эффективно как хотелось. Скорее всего буду использовать. Изменено 24 июня, 2015 пользователем ArtDenis Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 24 июня, 2015 Опубликовано 24 июня, 2015 · Жалоба К сожалению по мере тестирования программа менялась :( Последний вариант - тестирование пустого прерывания. Устроит? А выводы - вроде как работает, но не настолько эффективно как хотелось. Скорее всего буду использовать. Устроят любые программы, как образец. И тестировщиков прибавится. И выводы скорректируются. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ArtDenis 0 24 июня, 2015 Опубликовано 24 июня, 2015 (изменено) · Жалоба Устроят любые программы, как образец. И тестировщиков прибавится. И выводы скорректируются. Ну держи. Правда, используется собственная либа для работы с периферией. Если светодиод загорелся, то монитор не отловил нарушений, если не загорелся, то отловил. К сожалению, светодиод на плате один. Поскупился я на них )) #include <stdint.h> #include "stm32_lib/stm32l1xx/hl_gpio.hpp" #include "stm32_lib/stm32l1xx/hl_adc.hpp" #include "stm32_lib/stm32l1xx/hl_rcc.hpp" using namespace hl; typedef PA8 LedPin; static void init_led() { PA::clock_on(); PA::reset(); LedPin::conf_out_push_pull(); LedPin::off(); } static void adc_init() { rcc_enable_hsi(); ADC_<1>::clock_on(); ADC_<1>::reset(); ADC_<1>::set_regular_len(1); ADC_<1>::set_regular_channel_pos(1, 0); ADC_<1>::enable_eoc_interrupt(); ADC_<1>::enable(); NVIC_EnableIRQ(ADC1_IRQn); } static void led_on(bool value) { LedPin::set_out(value); } // Нулевой тест. Между LDREXW и STREXW почти ничего нету // Монитор НЕ отлавливает нарушение static void test0() { volatile uint32_t var = 0; __LDREXW(&var); bool res = __STREXW(10, &var) == 0; led_on(res); } // Изменение памяти при помощи STR // Монитор НЕ отлавливает нарушение static void test1() { volatile uint32_t var = 0; __LDREXW(&var); var = 20; bool res = __STREXW(10, &var) == 0; led_on(res); } // Изменение одного участка памяти при помощи STREX // Монитор отлавливает нарушение static void test2() { volatile uint32_t var = 0; __LDREXW(&var); __STREXW(20, &var); bool res = __STREXW(10, &var) == 0; led_on(res); } // Изменение разных участков памяти при помощи STREX // Монитор отлавливает нарушение static void test3() { volatile uint32_t var = 0; volatile uint32_t var2 = 0; __LDREXW(&var); __STREXW(20, &var2); bool res = __STREXW(10, &var) == 0; led_on(res); } // Прерывание между LDREX и STREX // Монитор отлавливает нарушение // volatile bool interrupt_executed = false; static void test4() { volatile uint32_t var = 0; __LDREXW(&var); // Вот таким вот нехитрым образом добиваемся прерывания )) ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); ADC_<1>::start_regular_conversion(); // Тут прерывание точно произошло, т.к. мы работаем на частоте 2 МГц, а АЦП на 16 Мгц // Это осталось от предыдущего теста: // while (!interrupt_executed) {} bool res = __STREXW(10, &var) == 0; led_on(res); } extern "C" void ADC1_IRQHandler() { // interrupt_executed = true; ADC_<1>::clear_eoc_flag(); } int main() { init_led(); adc_init(); // test0(); // test1(); // test2(); // test3(); test4(); } Один из старых вариантов тестирования прерывания был таким: static void test4() { volatile uint32_t var = 0; __LDREXW(&var); ADC_<1>::start_regular_conversion(); while (!interrupt_executed) {} bool res = __STREXW(10, &var) == 0; led_on(res); } extern "C" void ADC1_IRQHandler() { interrupt_executed = true; ADC_<1>::clear_eoc_flag(); } Он тоже показывал что монитор отловил нарушение эксклюзивного доступа. PS: критика крайне приветствуется )) Изменено 24 июня, 2015 пользователем ArtDenis Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ArtDenis 0 24 июня, 2015 Опубликовано 24 июня, 2015 · Жалоба Недокопипастил. Там в конце main() ещё for (;;) {} стоит Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 24 июня, 2015 Опубликовано 24 июня, 2015 · Жалоба Ну, вроде всё вполне согласуется с моими опытами. Единственный момент, ADC_<1>::clear_eoc_flag() - наверняка делает STR в область периферии. Для чистоты эксперимента хорошо бы сделать совсем пустой обработчик прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться