- •«Пермский национальный исследовательский политехнический университет»
- •«Встроенные микропроцессорные системы»
- •Составитель о.В. Гончаровский
- •Оглавление
- •2. Программное обеспечение встроенных систем ……….
- •Введение
- •Аппаратные средства встроенных систем
- •Организация аппаратных средств встроенных
- •1.2. Элементы архитектуры процессоров встроенных систем
- •1.2.1. Множество команд
- •1.2.3.1. Адресное пространство
- •1.2.3.2. Порядок байт
- •1. 2.3.3. Когерентность памяти
- •1. 2.3.4. Защита памяти
- •1. 2. 4. Модель прерываний
- •1.2. 5.Модель управления памятью
- •1.2.5.1. Страничная организация памяти
- •1.2.5.2. Сегментация памяти
- •1.3. Типы процессоров
- •1.4. Формы параллелизма в процессорах
- •1.4.1. Конвейеризация
- •1.4.2. Параллелизм уровня команд
- •1.5.Технологии памяти
- •1.5.1. Оперативная память
- •1.5.1. 1. Статическое озу
- •1.5.2. Постоянное запоминающее устройство (rom)
- •1.6. Иерархия памяти
- •1.6.1. Распределение или карта памяти
- •1.6.2. Блокнотная и кэш память
- •1.6.2.2. Ассоциативная по множеству кэш-память
- •1.6.2.3. Обновление кэш-памяти.
- •1.6.2.4. Протокол когерентности кэширования с обратной записью
- •1.7. Магистраль микропроцессорной системы
- •1.8. Базовые устройства ввода-вывода встроенных систем
- •1.8.1. Порты ввода-вывода общего назначения
- •1.7.2. Таймер-счетчик
- •1.8.3. Импульсно-кодовая модуляция.
- •1.8.4. Многоканальный аналого-цифровой преобразователь
- •1.9. Базовые последовательные интерфейсы ввода-вывода
- •1.9.2. Последовательный интерфейс spi
- •1.9.4.1. Введение в usb
- •1.9.4.2. Интерфейс Open Host Controller для usb
- •Вопросы для самопроверки
- •Модуль 2
- •1.10. Язык проектирования аппаратуры vhdl
- •1.10.2. Введение в vhdl
- •1.10.2.1. Программирование на vhdl для моделирования и синтеза [22]
- •1.10.2.3. Операторы присваивание и process [22]
- •1.10.2.4. Цикл моделирования vhdl
- •1.10.2.5. Многозначная логика и стандарт ieee 1164
- •1.11. Проектирование устройств ввода-вывода и контроллеров
- •1.12. Интегрированная среда разработки аппаратных средств
- •Вопросы для самопроверки
- •Модуль 3
- •2. Программное обеспечение встроенных систем
- •2.1 Модель вычислений
- •2.2 Автомат с конечным числом состояний
- •2.3. Асинхронный язык проектирования sdl
- •2.4. Синхронный язык проектирования Lustre
- •2.5. Многозадачность.
- •2.5.1. Язык программирования Си
- •2.5.2. Потоки
- •2.5.2.1. Реализация потоков
- •2.5.2.2. Взаимное исключение
- •2.5.2.3. Взаимная блокировка
- •2.5.2.4. Модели непротиворечивости памяти
- •2.5.2.5. Проблемы с потоками
- •2.5.3. Процессы и передача сообщений
- •2.6. Интегрированная среда разработки прикладного программного
- •2.6.2. Комплект программ Telelogic Tau sdl Suite
- •2.6.3. Средства разработки программного обеспечения
- •2.7.1. Моделирование, эмуляция и макетирование
- •2.7.2. Формальная верификация
- •2.7.3. Оценка производительности
- •2.7.3.1. Оценка wcet
- •2.7.3.2. Исчисление реального времени
- •2.7.4. Модели энергии и мощности
- •2.7.5. Тепловая модель
- •Задания
- •1. Конвейеризация
- •2. Иерархия памяти
- •3. Базовые устройства ввода-вывода встроенных систем
- •5. Многозадачность
- •6. Валидация и оценка проекта
- •Заключение
- •Библиографический список
- •Встроенные микропроцессорные системы
2.5.2.4. Модели непротиворечивости памяти
Е
x = 1;
w = y;
Т
y = 1; z
= x;
Интуитивно получаем, что после выполнения потоками этих операций мы должны надеяться, что хотя бы одна из двух переменных w и z имеют значение 1. Такая гарантия относится к последовательной непротиворечивости. Это означает, что результат любого выполнения точно такой же, как если бы операции всех потоков всегда выполнялись в некотором порядке и операции каждого индивидуального потока всегда появлялись в этой последовательности в порядке, определенном в потоке.
Однако последовательная непротиворечивость не гарантируется большинством (или возможно всеми) реализаций Pthreads. Обеспечение такой гарантии весьма трудно для современных процессоров, использующих современные компиляторы. Компилятор, например, свободен в вариантах переупорядочивании команд в каждом из потоков, т.к. не существует зависимости между ними (так это может казаться компилятору). Даже если компилятор не переупорядочивает команды, это может сделать аппаратура. Поэтому для доступа к разделяемым переменным остается лишь использовать взаимоисключающие замки и надеяться, что они реализованы корректно. О проблемах непротиворечивости памяти можно посмотреть в [31], [32].
2.5.2.5. Проблемы с потоками
Многопоточные программы могут быть очень трудными для понимания. Более того они могут быть трудными для построения конфиденциальности в программах, потому что проблемы кодировки не могут быть обнаружены при тестировании. Программа, например, возможно может содержать взаимоблокировку, но, не смотря на это работать корректно несколько лет без ее проявления. Программист должен быть очень внимательным, но судить о программе адекватно, полагая, что возможны ошибки.
В примере на рис. 73 можно устранить потенциальную взаимоблокировку, использую простой трюк, но он приводит к коварным ошибкам (не возникают при тестировании, не извещаются при наличии). Предположим, функция update модифицирована следующим образом:
void
update(int
newx)
{ x
= newx;
//
копирование списка в headc
и tailc
pthread_mutex_lock(&lock); element_t*
headc = NULL; element_t*
tailc = NULL; element_t*
element = head;
while
(element
!= 0) {
if
(headc
== NULL) {
headc
= malloc(sizeof(element_t));
headc->listener =
head->listener; headc->next
= 0; tailc
= headc;
}
else
{
tailc->next
= malloc(sizeof(element_t)); tailc
= tailc->next;
tailc->listener =
element->listener; tailc->next
= 0; } element
= element->next;
} pthread_mutex_unlock(&lock); //
извещение пользователей с помощью
копии списка
element
= headc;
while
(element
!= 0) {
(*(element->listener))(newx); element
= element->next;
} }
Эта реализации не удерживает замок, когда вызывается функция listener. Вместо этого программа удерживает замок, когда формирует копию списка слушателей и затем освобождает замок. После возвращения замка программа использует копию списка слушателей для их оповещения.
Этот код, однако, имеет потенциально серьезную проблему, которая не может быть обнаружена тестированием. Предположим, что поток A вызывает update с аргументом newx = 0, индицирующим, что «все системы в норме». Предположим, что поток A отложен сразу после освобождения замка, но перед выполнением оповещения. Предположим, что пока он отложен поток B вызывает update с аргументом newx = 1, означающим «авария! двигатель в огне!». Предположим, что этот вызов update завершается перед тем как поток A получает шанс на выполнение. Когда поток A получает разрешение на выполнение, он будет оповещать всех слушателей, но неправильным значением! Если один из слушателей обновляет дисплей пилота самолета, дисплей будет показывать, что все нормально, когда фактически двигатель объят пламенем. Нетривиальные многопоточные программы очень трудно понимать. Они могут содержать коварные ошибки, состязания и взаимоблокировку. Проблемы многопоточных программ могут оставаться незамеченными годы даже при интенсивном использовании программ. Эти проблемы очень важны для встроенных систем т.к. оказывают влияние на безопасность и средства существования. Фактически каждая встроенная система включает параллельное программное обеспечение, потому инженеры, проектирующие встроенные системы должны противостоять всевозможным ловушкам.