- •Системное программирование
- •Контрольные вопросы
- •2. Программная модель микропроцессора 8086
- •2.1. Представление информации
- •2.2. Регистры микропроцессора
- •2.3. Формат машинной команды
- •2.4. Способы задания операндов команды
- •Контрольные вопросы
- •3. Основные понятия языка ассемблера
- •3.1. Предложения
- •3.2. Директивы определения данных
- •3.3. Выражения
- •Контрольные вопросы
- •4. Сегментированная модель памяти
- •4.1. Сегментирование адресов
- •4.2. Директивы сегментации
- •4.3. Общая структура программы
- •4.4. Модели памяти
- •Контрольные вопросы
- •5. Основные группы команд
- •5.1. Соглашению по описанию команд
- •5.2. Команды пересылки данных
- •5.3. Арифметические команды
- •5.4. Логические команды
- •5.5. Команды переходов
- •5.6. Команды организации циклов
- •5.7. Команды обработки строк
- •5.8. Стековые команды
- •5.9. Команды ввода-вывода
- •5.10. Команды прерываний
- •5.11. Команды управления микропроцессором
- •Контрольные вопросы
- •6. Подпрограммы
- •Контрольные вопросы
- •7. Разработка одномодульной программы
- •7.1. Трансляция и компоновка программы
- •7.2. Отладка программы
- •Контрольные вопросы
- •8. Разработка многомодульных программ
- •8.1. Принципы разработки модулей
- •8.2. Расширенное применение директивы сегментации
- •9. Упражнения
- •Контрольные вопросы
- •Программирование микропроцессорных устройств
- •10. Программирование системного таймера
- •10.1. Описание таймера-счетчика 8254
- •10.2. Режимы работы таймера
- •10.3. Структура регистров таймера
- •10.4. Упражнения
- •Контрольные вопросы
- •11. Программирование контроллера прерываний
- •11.1. Механизм обработки прерываний
- •11.2. Типы прерываний
- •11.3. Приоритеты прерываний
- •11.4. Контроллер прерываний 8259
- •11.5. Идентификация прерываний
- •11.6. Прерывания bios и ms-dos
- •11.7. Упражнения
- •Контрольные вопросы
- •12. Программирование параллельного порта
- •12.1. Интерфейс Centronics
- •12.2. Работа с параллельным портом на низком уровне
- •12.3. Стандартные средства работы с параллельным портом
- •12.4. Упражнения
- •Контрольные вопросы
- •13. Программирование последовательного порта
- •13.1. Основы последовательной передачи данных
- •13.2. Последовательный интерфейс rs-232c
- •13.3. Универсальный асинхронный приемо-передатчик 8250
- •13.4. Порты асинхронного адаптера
- •13.5. Стандартные средства программирования последовательного порта
- •13.6. Упражнения
- •Контрольные вопросы
- •Литература
- •141 Кафедра Вычислительной Техники и Программирования Московского Государственного Открытого Университета
Системное программирование
(Учебное пособие)
Юрагов Евгений Алексеевич evg_uragov@mtu-net.ru
Содержание
Основы программирования микропроцессоров 4
1. Обзор процесса создания программ на языке ассемблера 4
Контрольные вопросы 7
2. Программная модель микропроцессора 8086 7
2.1. Представление информации 7
2.2. Регистры микропроцессора 9
2.3. Формат машинной команды 12
2.4. Способы задания операндов команды 15
Контрольные вопросы 17
3. Основные понятия языка ассемблера 17
3.1. Предложения 17
3.2. Директивы определения данных 18
3.3. Выражения 22
Контрольные вопросы 23
4. Сегментированная модель памяти 23
4.1. Сегментирование адресов 23
4.2. Директивы сегментации 26
4.3. Общая структура программы 29
4.4. Модели памяти 29
Контрольные вопросы 31
5. Основные группы команд 32
5.1. Соглашению по описанию команд 32
5.2. Команды пересылки данных 33
5.3. Арифметические команды 36
5.4. Логические команды 46
5.5. Команды переходов 54
5.6. Команды организации циклов 59
5.7. Команды обработки строк 61
5.8. Стековые команды 65
5.9. Команды ввода-вывода 68
5.10. Команды прерываний 69
5.11. Команды управления микропроцессором 69
Контрольные вопросы 71
6. Подпрограммы 71
Контрольные вопросы 75
7. Разработка одномодульной программы 75
7.1. Трансляция и компоновка программы 76
7.2. Отладка программы 79
Контрольные вопросы 81
8. Разработка многомодульных программ 81
8.1. Принципы разработки модулей 82
8.2. Расширенное применение директивы сегментации 83
9. Упражнения 84
Контрольные вопросы 86
Программирование микропроцессорных устройств 87
10. Программирование системного таймера 87
10.1. Описание таймера-счетчика 8254 87
10.2. Режимы работы таймера 89
10.3. Структура регистров таймера 91
10.4. Упражнения 93
Контрольные вопросы 100
11. Программирование контроллера прерываний 100
11.1. Механизм обработки прерываний 100
11.2. Типы прерываний 102
11.3. Приоритеты прерываний 104
11.4. Контроллер прерываний 8259 104
11.5. Идентификация прерываний 105
11.6. Прерывания BIOS и MS-DOS 106
11.7. Упражнения 110
Контрольные вопросы 116
12. Программирование параллельного порта 116
12.1. Интерфейс Centronics 116
12.2. Работа с параллельным портом на низком уровне 118
12.3. Стандартные средства работы с параллельным портом 119
12.4. Упражнения 120
Контрольные вопросы 123
13. Программирование последовательного порта 123
13.1. Основы последовательной передачи данных 123
13.2. Последовательный интерфейс RS-232C 124
13.3. Универсальный асинхронный приемо-передатчик 8250 126
13.4. Порты асинхронного адаптера 128
13.5. Стандартные средства программирования последовательного порта 134
13.6. Упражнения 135
Контрольные вопросы 140
Литература 141
Основы программирования микропроцессоров
1. Обзор процесса создания программ на языке ассемблера
Аппаратные средства вычислительных машин непосредственно воспринимают только машинные языки. Машинный язык– это формальный язык для описания решения задачи, содержание и правила которого реализуются аппаратно. Программа, переведенная на машинный язык, содержит определенные команды для выполнения каждой операции. Иногда машинным языком также называютсистему командвычислительной системы.
Команды машинного языка представляют последовательности двоичных цифр, записанные в памяти, причем одна команда может занимать одну или несколько смежных ячеек памяти. Микропроцессор осуществляет последовательную выборку команд одну за другой из памяти и затем их выполняет. С помощью машинных команд реализуются элементарные операции, например, «прибавить единицу к содержимому регистру», «записать содержимое ячейки памяти с адресом А в регистр» и т.д.
Рассмотрим небольшой фрагмент программы, который организует в цикле чтение двух байт (слова данных) из порта с номером 5, затем увеличивает на единицу полученное значение и записывает результат в порт вывода 2 (табл. 1). В первом столбце в шестнадцатеричном виде указаны адреса ячеек памяти. Содержимое этих ячеек приведено во втором столбце. Они соответствуют кодам команд микропроцессора 8086 компании Intel. В последнем столбце даны комментарии к каждой команде.
Табл. 1. Фрагмент программы в машинных кодах.
Адрес памяти |
Содержимое памяти |
Комментарий |
00100h |
1110 0101 |
Читать слово в регистр AX из порта ввода 5. |
00101h |
0000 0101 | |
00102h |
0100 0000 |
Увеличить на единицу содержимое AX. |
00103h |
1110 0111 |
Передать слово из регистра AX в порт вывода 2. |
00104h |
0000 0010 | |
00105h |
1110 1011 |
Повторить действия путем перехода по адресу на семь байт назад. |
00106h |
1111 1001 |
По комментариям становится понятно, что первые две комбинации нулей и единиц, хранящихся в ячейках памяти по адресам 100h и 101h (h– символ шестнадцатеричного числа) определяет команду чтения слова данных из порта ввода под номером 5 в регистр микропроцессора AX. Команда по адресу 102h увеличивает значение регистра AX на единицу. Затем выполняется передача содержимого регистра AX в порт вывода 2. Команда, записанная по адресам 105h и 106h, выполняет переход по адресу 100h, и затем весь процесс повторяется заново.
Представленный фрагмент программы в машинных (числовых) кодах команд микропроцессора называется объектной. Разработав объектную программу, ее можно загрузить в оперативную память вычислительной машины и запустить на выполнение. Как не трудно заметить, создание напрямую объектных программ довольно утомительное занятие. Современные модели микропроцессоров имеют систему команд, включающую сотни различных инструкций. Поэтому запомнить и, тем более, безошибочно применить их чрезвычайно сложно.
Значительно проще было бы использовать близкий для человека язык символьных описаний для тех действий, которые необходимо выполнить. Разработав такой язык можно затем создать специальные инструментальные средства, выполняющие преобразование программы с символьного языка в объектный код. Программы, написанные на таких искусственных языках, называются исходными, а инструментальные средства, выполняющие преобразование, –трансляторами(рис. 1).
Существует два вида трансляторов: ассемблерыпредназначены для преобразования исходных программ, написанных на языке ассемблера, икомпиляторы– для трансляции программ с языков высокого уровня.
Рис. 1. Процесс трансляции исходной программы в объектный код.
Язык ассемблерапозволяет разрабатывать программы на уровне команд микропроцессора, но вместо числовых кодов он определяет символьные обозначения. Например, рассмотренный фрагмент программы на языке ассемблера будет выглядеть следующим образом:
L: IN AX, 5 ; читать слово данных из порта 5 в регистр AX
INC AX ; увеличить на единицу регистр AX
OUT 2, AX ; вывести в порт 2 содержимое регистра AX
JMP L ; перейти по метке L
Воспринимать эти строчки теперь стало значительно проще. На языке ассемблера машинные команды имеют вид мнемонических обозначенийилимнемоник(в нашем примере мнемониками являются IN, INC, OUT и JMP), а адреса памяти и константы могут быть представлены не последовательностью битов, а символами. Поэтому для изучения, понимания и использования языка ассемблера требуется намного меньше усилий, чем при создании программ на машинном языке.
Для преобразования аббревиатур английских слов в числовые коды команд должна быть вызвана программа ассемблера. Функцией ассемблера является преобразование исходной программы вобъектную, понятную микропроцессору (рис. 2). Отношения между программой на языке ассемблера и результатом трансляции – объектным кодом, всегда однозначные. Язык ассемблера позволяет полностью контролировать процесс получения объектного кода.
Рис. 2. Трансляция программы на языке ассемблера в объектный код.
Существует много разновидностей ассемблеров, разработанных различными фирмами. Для микропроцессоров фирмы Intel традиционно на рынке ассемблеров имеется два основных пакета: макроассемблер MASM компании Microsoft и турбо ассемблер TASM компании Borland. Оба пакета содержат трансляторы, компоновщики, отладчики и другие средства для полноценной разработки программ на ассемблере.
Приведем еще один пример того же самого алгоритма, но уже на языке высокого уровня, например, на Паскале (пакет Borland® Pascal 7.0):
1: portw[2]:=portw[5]+1; { получить из порта 5 слово данных, увеличить
его значение на единицу и вывести в порт 2 }
goto 1; { перейти на метку 1 }
Здесь для доступа к портам ввода-вывода используются предопределенный массив portw. Индексом массива является адрес порта, к которому необходимо обратиться. Как видно, теперь полностью потерян контроль над процессом получения объектного кода. Каким образом эти две строчки будут преобразованы в объектный код, зависит от выбранной версии компилятора языка Паскаль (рис. 3).
Рис. 3. Трансляция программы на языке высокого уровня в объектный код.
В общем случае отношения между исходной программой на языке высокого уровня и полученным в результате трансляции объектным кодом не очевидны. Кроме того, поскольку для каждого оператора высокого уровня может потребоваться от двух до десяти машинных команд, это приводит к снижению эффективности полученного объектного кода по сравнению с языком ассемблера. Компилятор может сгенерировать значительно более избыточный код, чем человек при написании того же алгоритма на языке ассемблера.
Поэтому на языке ассемблере целесообразно разрабатывать программы, которые должны обеспечить эффективную работу с аппаратной частью микропроцессорной системы, либо критичные по времени выполнения или расходованию памяти алгоритмы. Впоследствии они могут быть оформлены в виде подпрограмм и совмещены с основной программой на языке высокого уровня.
Из рассмотренных примеров можно видеть, что в общем случае язык программирования является механизмом абстрагирования. Он дает возможность описать вычисления абстрактно и в то же время позволяет программе (транслятору) перевести это описание в детализированную форму, необходимую для выполнения на вычислительном устройстве. Существует естественное противоречие между стремлением к краткому, ясному и надежному выражению вычисления на высокоабстрактном уровне и стремлением к гибкости подробного описания на самом низком уровне.
Начиная с этой главы, будут рассмотрены методы разработки программ на языке ассемблера для микропроцессора 8086 компании Intel, положившего начало самой распространенной в настоящее время ветви микропроцессорной архитектуры. В последующих главах будут описаны способы программирования различных микропроцессорных устройств и плат сбора данных, используемых при разработке средств измерительных техники.