Программирование контроллера приоритетных прерываний
Для организации обработки аппаратных прерываний в вычислительных системах применяется программируемый контроллер прерываний, выполненный в виде специальной микросхемы i8259А, отечественный аналог микросхема КР580ВМ59. Эта микросхема может обрабатывать запросы от восьми источников внешних прерываний. В стандартной конфигурации вычислительных систем используют две последовательно соединенные… Читать ещё >
Программирование контроллера приоритетных прерываний (реферат, курсовая, диплом, контрольная)
Министерство образования Российской Федерации Волжский университет им. Татищева Факультет «Информатика и телекоммуникации»
Кафедра «Информатика и системы управления»
УТВЕРЖДАЮ Проректор по учебной работе
_____________Е.В. Филатова
«_____"____________ 200 г.
МЕТОДИЧЕСКОЕ УКАЗАНИЕ
для проведения лабораторной работы по теме
''Программирование контроллера приоритетных прерываний''
по курсу ''Организация ЭВМ''
для студентов специальностей 220 100, 71 900
Тольятти
Создание и компиляция программ на ассемблере
Процесс разработки программы на ассемблере состоит из пяти этапов:
1. Создание файла с исходным текстом программы в любом текстовом редакторе. Расширение файла с исходным текстом может быть .asm, или .txt, или .doc.
2. Создание объектного модуля. В среде DOS или NORTON или FAR в командной строке набираете следующую команду:
tasm name. asm
или
tasm.exe name. asm name.obj
name.asm файл с исходным текстом программы. При этом файлы tasm. exe и name. asm должны находится в одном каталоге. После запуска этой команды мы получаем объектный файл с расширением .obj. Если объектный файл не появился, то в программе содержатся ошибки. Перечень ошибок можно посмотреть, отключив панели (ctrl+o или Ctrl+f1 и ctrl+f2).
3. Создание исполнительного файла. В командной строке набираем следующую команду:
tlink name. obj
или
tlink.exe name. obj name exe
При этом файлы tlink. exe и name. obj должны находится в одном каталоге. После запуска этой команды мы получаем запускной файл с расширением .exe. Если запускной файл не появился в этом каталоге, то в данном каталоге не хватает некоторых библиотек. Перечень файлов можно посмотреть, отключив панели (ctrl+o или Ctrl+f1 и ctrl+f2).
4. Тестирование программы. Запустите исполнительный файл.
5. Пошаговая отладка. В командной строке набираем следующую команду:
td name.exe
Структура программы на ассемблере
Model small ;модель программы, или же количество памяти на сегмент
.data ;сегмент данных
;описание переменных
.stack 100h ;сегмент стека
.code ;сегмент данных
;процедуры, макрокоманды
main:
mov ax,@data
mov ds,ax
;основная программа
mov ax, 4c00h
int 21h ;выход из программы
end main
Директивы резервирования памяти
Для описания простых типов данных в программе используются специальные директивы резервирования и инициализации данных, которые, по сути, являются указаниями транслятору на выделение определенного объема памяти. Если проводить аналогию с языками высокого уровня, то директивы резервирования и инициализации данных являются определениями переменных.
Машинного эквивалента этим директивам нет; просто транслятор, обрабатывая каждую такую директиву, выделяет необходимое количество байт памяти и при необходимости инициализирует эту область некоторым значением.
Директивы резервирования и инициализации данных простых типов имеют формат:
Рис. 1. Директивы описания данных простых типов
На рис. 1 использованы следующие обозначения:
· ? показывает, что содержимое поля не определено, то есть при задании директивы с таким значением выражения содержимое выделенного участка физической памяти изменяться не будет. Фактически, создается неинициализированная переменная;
· значение инициализации — значение элемента данных, которое будет занесено в память после загрузки программы. Фактически, создается инициализированная переменная, в качестве которой могут выступать константы, строки символов, константные и адресные выражения в зависимости от типа данных. Подробная информация приведена в приложении 1;
· выражение — итеративная конструкция с синтаксисом, описанным на рис. 5.17. Эта конструкция позволяет повторить последовательное занесение в физическую память выражения в скобках n раз.
· имя — некоторое символическое имя метки или ячейки памяти в сегменте данных, используемое в программе.
· db — резервирование памяти для данных размером 1 байт. Директивой db можно задавать следующие значения:
o выражение или константу, принимающую значение из диапазона:
для чисел со знаком −128…+127; для чисел без знака 0…255;
o символьную строку из одного или более символов. Строка заключается в кавычки. В этом случае определяется столько байт, сколько символов в строке.
· dw — резервирование памяти для данных размером 2 байта.
o выражение или константу, принимающую значение из диапазона:
для чисел со знаком -32 768…32 767; для чисел без знака 0…65 535;
o выражение, занимающее 16 или менее бит, в качестве которого может выступать смещение в 16-битовом сегменте или адрес сегмента;
o 1- или 2-байтовую строку, заключенная в кавычки.
· dd — резервирование памяти для данных размером 4 байта.
o выражение или константу, принимающую значение из диапазона:
для чисел со знаком -2 147 483 648…+2 147 483 647;
для чисел без знака 0…4 294 967 295;
o относительное или адресное выражение, состоящее из 16-битового адреса сегмента и 16-битового смещения;
o строку длиной до 4 символов, заключенную в кавычки.
· df — резервирование памяти для данных размером 6 байт;
· dp — резервирование памяти для данных размером 6 байт. Директивами df и dp можно задавать следующие значения:
o выражение или константу, принимающую значение из диапазона:
для чисел со знаком -2 147 483 648…+2 147 483 647;
для чисел без знака 0…4 294 967 295;
o относительное или адресное выражение, состоящее из 32 или менее бит (для i80386) или 16 или менее бит (для младших моделей микропроцессоров Intel);
o адресное выражение, состоящее из 16-битового сегмента и 32-битового смещения;
o строку длиной до 6 байт, заключенную в кавычки.
· dq — резервирование памяти для данных размером 8 байт.
относительное или адресное выражение, состоящее из 32 или менее бит
o константу со знаком из диапазона -263…263−1;
o константу без знака из диапазона 0…264−1;
o строку длиной до 8 байт, заключенную в кавычки.
· dt — резервирование памяти для данных размером 10 байт.
относительное или адресное выражение, состоящее из 32 или менее бит
o адресное выражение, состоящее из 16-битового сегмента и 32-битового смещения;
o константу со знаком из диапазона -279…279−1;
o константу без знака из диапазона 0…280−1;
o строку длиной до 10 байт, заключенную в кавычки;
o упакованную десятичную константу в диапазоне 0…99 999 999 999 999 999 999.
Очень важно уяснить себе порядок размещения данных в памяти. Он напрямую связан с логикой работы микропроцессора с данными. Микропроцессоры Intel требуют следования данных в памяти по принципу: младший байт по младшему адресу.
Для иллюстрации данного принципа рассмотрим пример 1, в котором определим сегмент данных. В этом сегменте данных приведено несколько директив описания простых типов данных.
Пример 1. Пример использования директив резервирования и инициализации данных. Результатом работы данной программы будет строка 'Привет, все работает'
model small
.stack 100h
.data
mes db 'Привет, все работает','$' ;определение строки
perem1 db 0ffh ;определение контстанты
perem2 dw 3a7fh ;определение контстанты
perem3 dd 0f54d567ah ;определение контстанты
mas db 10 dup (' ') ;определение пустого массива из 10 байт
adr dw perem3 ;переменная adr содержит адрес
;внутри сегмента переменной perem3
a_full dd perem3 ;переменная a_full содержит полный
;адрес переменной perem3
fin db 'Конец сегмента данных программы $'
.code
start:
;занесение в сегментный регистр адреса сегмента данных
mov ax,@data
mov ds,ax
mov ah, 09h
mov dx, offset mes
int 21h ;вывод на экран строки mes
mov ax, 4c00h
int 21h ;выход из программы
end start
Окончание работы программы сопровождается полной выгрузкой программы из оперативной памяти, это осуществляется функцией 4с00h прерывания int 21h.
Все что в данной программе выделено жирным шрифтом обязательно при написании любой программы.
При написании программ на ассемблере регистр букв не важен.
Организация ввода-вывода на ассемблере
Ввод-вывод данных в компьютер осуществляется посредством различных периферийных устройств. Общение процессора с различными периферийными происходит через систему прерываний. Для ввода-вывода данных служит прерывание int 21h.
Основная последовательность дей-ствий при использовании прерываний 2lh (DOS):
1. Поместить номер функции в регистр ah.
2. Поместить передаваемые функции параметры в определенные регистры (они приведены при описании каждой функции).
3. Вызвать прерывание 2lh (DOS) командой int 21h
4. Извлечь результаты работы функций из определенных регистров. Какие именно регистры и что они содержат после возврата управления из функ-ции программе пользователя, указывается при описании каждой функции.
Прерывание DOS 2lh предназначено для предоставления программисту раз-личных услуг со стороны операционной системы. Этими услугами является набор функций. Какая именно функция должна быть вызвана, указывается числом в регистре ah.
Некоторые функции DOS (int 21h)
Назначение | Номер функции | Вход | Выход | |
Ввод символа с ожиданием и эхосопровождением | ah-0lh | аlASCII-код символа | ||
Вывод символа | ah-02h | dlASCII-код символа | ||
Вывод символа на принтер | ah-05h | dlASCII-код символа | ||
Ввод символа с ожиданием и без эхосопровождения | ah-07h ah-08h | alASCII-код символа (функция 08h при вводе проверяет, не нажато ли CTRL-BREAK) | ||
Вывод строки на экран | ah-09h | ds:dx = адрес строки с символом <$> на конце | Введенная строка в буфере | |
Ввод строки с клавиатуры | ah-0ah | ds:dx-anpec буфера с форматом: 1 байт — размер буфера для ввода (формирует пользователь); 2 байт — число фактически введенных символов (заполняет система по окончанию ввода — нажатию клавиши Enter (Odh)). Символ 0dh не учитывается во втором байте буфера; 3 байт и далее — введенная строка с символом 0dh на конце | ||
Проверка состояния буфера клавиатуры | ah — 0bh | al=0 — буфер пуст al = 0ffh — в буфере есть символы | ||
Пример 2. Программа ввода символа с клавиатуры
model small
.stack 100h
.data
.code
start: ;занесение в сегментный регистр адреса сегмента данных
mov ax, @data
mov ds, ax
;помещаем в регистр ah номер функции, которая вводит символ
mov ah, 01h
int 21h ;вводим символ с клавиатуры
;символ введенный с клавиатуры находится в регистре al
mov ax, 4c00h
int 21h ;выход из программы
end start
Пример 3. Программа вывода символа на экран
model small
.stack 100h
.data
f db 'ф' ;помещаем в переменную f выводимый символ
.code
start: ;занесение в сегментный регистр адреса сегмента данных
mov ax, @data
mov ds, ax
;помещаем в регистр ah номер функции, которая выводит символ
mov ah, 02h
mov dl, f; помещаем в dl символ
int 21h ;выводим символ на экран
mov ax, 4c00h
int 21h ;выход из программы
end start
Пример 4. Вывод строки на экран
model small
.stack 100h
.data
f db 'строка вывода$'
;f — строковая переменная, которая обязательно заканчивается знаком $
.code
start: ;занесение в сегментный регистр адреса сегмента данных
mov ax, @data
mov ds, ax
;помещаем в регистр ah номер функции, которая выводит строку на экран
mov ah, 09h
mov dx, offset f; помещаем в dx адрес строки, которую выводим
int 21h ;выводим строку
mov ax, 4c00h
int 21h ;выход из программы
end start
Организация вычислений
Логические команды
Система команд микропроцессора содержит пять логических команд. Эти команды выполняют логические операции над битами операндов. Размерность операндов должна быть одинакова. В качестве операндов могут использоваться, регистры, ячейки памяти (переменные) и непосредственные операнды (числа). Любая логическая команда меняет значение следующих флагов of, sf, zf, pf, cf (переполнение, знак, нуля, паритет, перенос)
and операнд1, операнд2 — операция логического умножения (И — конъюнкция).
and ah, 0a1h; ah:=ah?0ah
and bx, cx; bx:=bx?cx
and dx, x1; dx:=dx?x1
Команда and может применяться для сброса определенных битов в 0 или для определения значения некоторых битов.
Например, необходимо 5й бит числа находящегося в bl установить в 0, остальные биты не трогать.
and bl, 1 101 1111b или and bl, 0cfh
Если необходимо определить чему равен 5й бит, то
and bl, 10 0000b или and bl, 20h
В результате если в регистре bl в 5 м бите был 0, то после выполнения этой команды мы получим нулевой результат, обнулим весь регистр. Если же в регистре bl в 5 м бите была 1, то мы получим не нулевой результат.
or операнд1, операнд2 — операция логического сложения (ИЛИ — дизъюнкцию)
or al, x1; al:=al & x1
or eax, edx; eax:=eax & edx
or dx, 0fa11h; dx:=dx & 0fa11h
Команда or может применяться для установки определенных бит в 1. Например, необходимо установить в единицу 4й и 7й биты регистра ah.
or ah, 1 001 0000b или or ah, 90h
xor операнд1, операнд2 — операция логического исключающего сложения (исключающего ИЛИ ИЛИ-НЕ). Команда может применятся для выяснения того какие биты в операндах различаются ил для инвертирования состояния заданных бит в операнде1. Например, необходимо определить совпадает ли содержимое регистров ax и dx
xor ax, dx ;если содержимое совпадает то в регистре ах мы получим
;нулевой результат, иначе не нулевой результат.
xor bh, 10b; инвертировали 1й бит в регистре bh
test операнд1, операнд2 — операция «проверить» (способом логического умножения). Команда выполняет поразрядно логическую операцию И над битами операндов операнд1 и операнд2. Состояние операндов остается прежним, изменяются только флаги zf, sf, и pf, что дает возможность анализировать состояние отдельных битов операнда без изменения их состояния.
not операнд — операция логического отрицания. Команда выполняет поразрядное инвертирование (замену значения на обратное) каждого бита операнда. Результат записывается на место операнда.
not ax ;ax:=
Пример 5. Логическое сложение двух однобайтных чисел.
model small
.stack 100h
.data
x1 db 0c2h ;первое слагаемое
x2 db 022h ;второе слагаемое
y db? ;переменная результата
.code
start:
mov ax,@data
mov ds,ax
mov al, x1 ;в al помещаем первое слагаемое
or al, x2 ;осуществляем логическое сложение, результат в al
mov y, al ;помещаем результат на место
mov ax, 4c00h
int 21h
end start
Следующие две команды позволяют осуществить поиск первого установленного в 1 бита операнда. Они появились в 486 процессоре.
bsf операнд1, операнд2 — сканирование бит операнда2 от младшего к старшему в поисках первого бита установленного в 1. Если такой обнаружится, то в операнд1 заноситься номер этого бита в целочисленном формате.
Пример:
mov al, 02h
bsf bx, al; bx:=1, т.к. 1й бит регистра al=1
bsr операнд1, операнд2 — сканирование бит операнда2 от старшего к младшему в поисках первого бита установленного в 1. Если такой обнаружится, то в операнд1 заноситься номер этого бита в целочисленном формате.
Пример:
mov al, 82h
bsr bx, al; bx:=6, т.к. 6й бит регистра al=1
Если операнд2 равен 0 то вышеописанные две команды устанавливают флаг нуля zf в 1, иначе в 0.
Арифметические операции над целыми двоичными числами
Сложение двоичных чисел
inc операнд — операция инкремента, то есть увеличения значения операнда на 1;
inc ax; ax:=ax+1
inc x1; х1:=х1+1
add оп1,оп2 — команда сложения с принципом действия: оп1 = оп1 + оп2 (addition)
add al, bl
add ax, 0fe2h
add ebx, x1+2
add x1, 0fh
add x2, ax
adc оп1,оп2 — команда сложения с учетом флага переноса cf. оп1 = оп1 + оп2 + знач_cf
Вычитание двоичных чисел
dec операнд — операция декремента, то есть уменьшения значения операнда на 1;
dec cx ;cx:=cx-1
dec x
sub операнд1, операнд2 — команда вычитания; ее принцип действия:
операнд1 = операнд1 — операнд2
sub al, bl; al:=al-bl
sub ax, x1
sub x2, dx
sub eax, 0f35h
sub x2, 22h
sbb операнд1, операнд2 — команда вычитания с учетом заема (флага cf):
операнд1 = операнд1 — операнд2 — значение_cf
Пример 6. Сложение двух однобайтных чисел.
model small
.stack 100h
.data
x1 db 0c2h ;первое слагаемое
x2 db 022h ;второе слагаемое
y db? ;результат
.code
start:
mov ax,@data
mov ds,ax
mov al, x1 ;помещаем в al первое слагаемое
add al, x2 ;складываем х1 и х2
mov y, al ;помещаем результат на место
mov ax, 4c00h
int 21h
end start
Умножение двоичных чисел
mul множитель1 — операция умножения двух целых чисел без учета знака
Алгоритм работы:
Команда выполняет умножение двух операндов без учета знаков. Алгоритм зависит от формата операнда команды и требует явного указания местоположения только одного сомножителя, который может быть расположен в памяти или в регистре. Местоположение второго сомножителя фиксировано и зависит от размера первого сомножителя. Местоположение результата также зависит от размера первого сомножителя.
mul dl; ax:=al*dl, dlмножитель1, alмножитель2
mul x1; dx: ax=ax*0ad91h, x1 wordмножитель1, axмножитель2
mul ecx; edx: eax=eax*ecx, ecxмножитель1, eaxмножитель2
в результате умножения может возникнуть ситуация когда результат по размеру превысит 16 или 32 бита, тогда старшая часть результата умножения заноситься в dx или edx соответственно.
imul множитель1 — операция умножения двух целочисленных двоичных значений со знаком
Деление двоичных чисел
div делитель — выполнение операции деления двух двоичных беззнаковых значений
Алгоритм работы:
Для команды необходимо задание двух операндов — делимого и делителя. Делимое задается неявно, и размер его зависит от размера делителя, который указывается в команде. Расположение результата зависит от размера делителя.
div dl ;ah:al=ax/dl, axделимое, dlделитель, ah-частное, alостаток
div x1 ;ax:dx=dx:ax/0ad91h, dx: axделимое, x1 wordделитель ,
;ax-частное, dxостаток
div ecx ;eax:edx=edx:eax/ecx, edx: eaxделимое, ecxделитель ,
;eax-частное, edxостаток
idiv делитель — операция деления двух двоичных значений со знаком
Пример 7. Умножение двух однобайтных чисел.
model small
.stack 100h
.data
x1 db 78 ;первый множитель
yl db? ;первый байт результата
yh db? ;второй байт результата
.code
start:
mov ax,@data
mov ds,ax
xor ax, ax ;очищаем регистр ax
mov al, 25 ;помещаем в al второй сомножитель
mul x1
jnc m1 ;если нет переполнения, переходим на метку m1
mov yh, ah ;иначе старший байт результата помещаем в yh
m1:
mov yl, al ;результат помещаем на место
mov ax, 4c00h
int 21h
end start
Пример 8. Деление двух однобайтных чисел.
model small
.stack 100h
.data
x1 db 6 ;делитель
yl db? ;остаток
yh db? ;частное
.code
start:
mov ax,@data
mov ds,ax
xor ax, ax ;очищаем регистр ax
mov ax, 25 ;помещаем в al делимое
div x1
mov yh, ah ;помещаем частное на место
mov yl, al ;помещаем остаток на место
mov ax, 4c00h
int 21h
end start
ASCII коды и их интепритация
Ввод информации с клавиатуры и вывод ее на экран осуществляется в символьном виде, т. е. любой символ предоставляется в ASCII кодах. Причем на один символ идет один ASCII код. На два символа — два ASCII кода, и т. д. Любое число, вводимое с клавиатуры и выводимое на экран, представляется последовательностью ASCII кодов.
Табл.1. ASCII коды цифр
Символ шестнадцатеричной цифры | Двоичная тетрада | ASCII код (двоичное представление) | Разница | |
30h (0011 0000) | 30h | |||
31h (0011 0001) | 30h | |||
32h (0011 0010) | 30h | |||
33h (0011 0011) | 30h | |||
34h (0011 0100) | 30h | |||
35h (0011 0101) | 30h | |||
36h (0011 0110) | 30h | |||
37h (0011 0111) | 30h | |||
38h (0011 1000) | 30h | |||
39h (0011 1001) | 30h | |||
A a | 41h (0100 0001) 61h (0110 0001) | 37h 57h | ||
B b | 42h (0100 0010) 62h (0110 0010) | 37h 57h | ||
C c | 43h (0100 0011) 63h (0110 0011) | 37h 57h | ||
D d | 44h (0100 0100) 64h (0110 0100) | 37h 57h | ||
E e | 45h (0100 0101) 65h (0110 0101) | 37h 57h | ||
F f | 46h (0100 0110) 66h (0110 0110) | 37h 57h | ||
Рассмотрим последовательность действий для преобразования чисел в их ASCII код и наоборот.
Ввод информации с клавиатуры:
1. Ввод символа с клавиатуры, один ASCII код находится в dl. Заранее не известно, что это за число от 0 до 9 или от, а до f.
Cmp dl, 040h
Jb m1; если ASCII код меньше 40h значит ввели цифру от 0 до 9,
;переходим на метку m1
Cmp dl, 047h; иначе ввели букву, заглавную или маленькую?
Jb m2 ;если ввели заглавную, переходим на m2, иначе выполняем
;дальше по программе
sub dl, 057h ;в dl получаем из символов число a. f h
jmp m3 ;переходим на m3 чтобы не выполнять лишних вычислений
m2: sub dl, 037h ;в dl получаем из символов число a. f h
jmp m3
m1: sub dl, 030h ;в dl получаем из символов число 0.9 h
m3:
Далее приведен оптимизированный код преобразования числа из ASCII кодов. Подумайте в чем разница.
Cmp dl, 040h
Jb m1
Cmp dl, 047h
Jb m2
Sub dl, 020h
m2: sub dl, 07h
m1: sub dl, 030h
2. Ввод строки, отличается только тем, что такое сравнение надо проводить с каждым элементом, т. е. надо организовать цикл и обращение к каждому элементу. Рассмотрим позднее.
Вывод информации на экран
1. Предположим что, число, которое мы хотим вывести, находится в регистре bl. Вывод символа осуществляется из регистра dl, 02 функция INT 21H. Число может быть одно или двузначное, например 7h или 5Fh. Для универсальности программы будем считать, что надо вывести двузначное число. А для этого надо получить отдельно десятки и единицы, и получить для них два ASCII кода.
;двузначное число которое хотим вывести находится в bl
mov dl, bl; помещаем число в регистр dl
;сдвигаем содержимое dl на 4 бита вправо, чтобы получить отдельно десятки
shr dl, 4
and bl, 0fh ;получаем отдельно единицы
cmp dl, 0ah ;сравниваем dl с ah
jb m1 ;если меньше переходим на m1
add dl, 07h
m1: add dl, 30h
mov ah, 02h
int 21h
mov dl, bl
cmp dl, 0ah ;сравниваем dl с ah
jb m2
add dl, 07h
m2: add dl, 30h
int 21h
Попробуйте сами разобраться в приведенном кусочке кода.
Команды передачи управления
По принципу действия, команды микропроцессора, обеспечивающие организацию переходов в программе, можно разделить на три группы:
1. Команды безусловной передачи управления:
— команда безусловного перехода; jmp
— вызова процедуры и возврата из процедуры; call, ret
— вызова программных прерываний и возврата из программных прерываний. Int, iret
2. Команды условной передачи управления:
— команды перехода по результату команды сравнения cmp;
— команды перехода по состоянию определенного флага;
— команды перехода по содержимому регистра ecx/cx.
3. Команды управления циклом:
— команда организации цикла со счетчиком ecx/cx;
— команда организации цикла со счетчиком ecx/cx с возможностью досрочного выхода из цикла по дополнительному условию.
jmp адрес_перехода — безусловный переход без сохранения информации о точке возврата. Аналог goto.
Условные переходы
Команды условного перехода имеют одинаковый синтаксис:
jcc метка_перехода
Мнемокод всех команд начинается с «j» — от слова jump (прыжок), cc — определяет конкретное условие, анализируемое командой. Что касается операнда метка_перехода, то эта метка может находится только в пределах текущего сегмента кода, межсегментная передача управления в условных переходах не допускается.
Для того чтобы принять решение о том, куда будет передано управление командой условного перехода, предварительно должно быть сформировано условие, на основании которого и будет приниматься решение о передаче управления. Источниками такого условия могут быть:
— любая команда, изменяющая состояние арифметических флагов;
— команда сравнения cmp, сравнивающая значения двух операндов;
— состояние регистра ecx/cx.
jcxz метка_перехода (Jump if cx is Zero) — переход, если cx ноль;
jecxz метка_перехода (Jump Equal ecx Zero) — переход, если ecx ноль.
Условные переходы по содержимому флагов
Название флага | Номер бита в eflags/flag | Команда условного перехода | Значение флага для осуществления перехода | |
Флаг переноса cf | 1 | jc | cf = 1 | |
Флаг четности pf | 2 | jp | pf = 1 | |
Флаг нуля zf | 6 | jz | zf = 1 | |
Флаг знака sf | 7 | js | sf = 1 | |
Флаг переполнения of | 11 | jo | of = 1 | |
Флаг переноса cf | 1 | jnc | cf = 0 | |
Флаг четности pf | 2 | jnp | pf = 0 | |
Флаг нуля zf | 6 | jnz | zf = 0 | |
Флаг знака sf | 7 | jns | sf = 0 | |
Флаг переполнения of | 11 | jno | of = 0 | |
Пример 9. Определите, равны ли два числа вводимые пользователем с клавиатуры. Определить равенство чисел можно используя вычитание, если разность исследуемых чисел равна 0, то они равны.
model small
.stack 100h
.data
s1 db 'числа равны$'
s2 db 'числа не равны$'
.code
start:
mov ax,@data
mov ds, ax
mov ah, 01h
int 21h ;ввели первое число
mov dl, al ;посылаем в dl первое число
int 21h ;ввели второе число
sub al, dl ;сравнили числа
jnz m1 ;если получили не 0 результат, то на метку m1
mov dx, offset s1 ;иначе выводим строку s1, о том что числа равны.
jmp m2
m1: mov dx, offset s2 ;числа не равны, выводим строку s2
m2: mov ah, 09h
int 21h ;вывод информационную строку
mov ax, 4c00h
int 21h
end start
Команда сравнения cmp
cmp операнд1, операнд2 — сравнивает два операнда и по результатам сравнения устанавливает флаги. Команда сравнения cmp имеет интересный принцип работы. Он абсолютно такой же, как и у команды вычитания sub. Единственное, чего она не делает — это запись результата вычитания на место первого операнда.
Алгоритм работы:
— выполнить вычитание (операнд1-операнд2);
— в зависимости от результата установить флаги, операнд1 и операнд2 не изменять (то есть результат не запоминать).
Условные переходы после команд сравнения
Типы операндов | Мнемокод команды условного перехода | Критерий условного перехода | Значения флагов для осществления перехода | |
Любые | je | операнд1 = операнд2 | zf = 1 | |
Любые | jne | операнд1<>операнд2 | zf = 0 | |
Со знаком | jl/jnge | операнд1 < операнд2 | sf <> of | |
Со знаком | jle/jng | операнд1 <= операнд2 | sf <> of or zf = 1 | |
Со знаком | jg/jnle | операнд1 > операнд2 | sf = of and zf = 0 | |
Со знаком | jge/jnl | операнд1 => операнд2 | sf = of | |
Без знака | jb/jnae | операнд1 < операнд2 | cf = 1 | |
Без знака | jbe/jna | операнд1 <= операнд2 | cf = 1 or zf=1 | |
Без знака | ja/jnbe | операнд1 > операнд2 | cf = 0 and zf = 0 | |
Без знака | jae/jnb | операнд1 => операнд2 | cf = 0 | |
Пример 10. Определите, равны ли два числа вводимые пользователем с клавиатуры.
model small
.stack 100h
.data
s1 db 'числа равны$'
s2 db 'числа не равны$'
.code
start:
mov ax,@data
mov ds, ax
mov ah, 01h
int 21h ;ввели первое число
mov dl, al
mov ah, 01h
int 21h ;ввели второе число
cmp al, dl ;сравнили числа
jne m1
mov dx, offset s1
jmp m2
m1: mov dx, offset s2
m2: mov ah, 09h
int 21h ;вывод информационную строку
mov ax, 4c00h
int 21h
end start
Пример 11. Даны три числа, найти среди них максимальное.
model small
.stack 100h
.data
s1 db 'максимальное число', 10,13,'$'
x1 db 34
x2 db 56
x3 db 45
.code
start:
mov ax,@data
mov ds, ax
mov dx, offset s1
mov ah, 09h
int 21h ;вывод информационную строку
;находим максимальное число
mov dl, x1 ;dl:=x1
cmp dl, x2 ;сравниваем х1 и х2
ja m1 ;если х1>х2, то на m1
mov dl, x2 ;иначе dl:=x2
m1: cmp dl, x3 ;сравниваем dl и х2
ja m2 ;если dl>х3 то на m2
mov dl, x3
;в dl находится самый максимальный элемент
m2: mov ah, 02h
int 21h ;выводим максимальный элемент
mov ax, 4c00h
int 21h
end start
Организация циклов
loop метка_перехода (Loop) — повторить цикл
Работа команды заключается в выполнении следующих действий:
— декремента регистра ecx/cx;
— сравнения регистра ecx/cx с нулем:
— если (ecx/cx) > 0, то управление передается на метку перехода;
— если (ecx/cx) = 0, то управление передается на следующую после loop команду Организация цикла:
mov cx, количество циклов
м1: тело цикла
loop m1
loope/loopz метка_перехода (Loop till cx <> 0 or Zero Flag = 0) — повторить цикл, пока cx <> 0 или zf = 0.
loopne/loopnz метка_перехода (Loop till cx <> 0 or Not Zero flag=0) — повторить цикл пока cx <> 0 или zf = 1
Недостаток команд организации цикла loop, loope/loopz и loopne/loopnz в том, что они реализуют только короткие переходы (от -128 до +127 байт).
Организация вложенных циклов:
mov cх,n ; в сх заносим количество итераций внешнего цикла
m1:
push cx
…
mov cx,n1; в сх заносим количество итераций внутреннего цикла
m2:
тело внутреннего цикла
loop m2
…
pop cx
loop m1
Пример 12. Напишите программу подсчета у=1+2+3+…+n, n не более 10 000.
model small
.stack 100h
.data
yb dd ?
ym dw ?
s1 db 'введите n', 10,13,'$'
.code
start:
mov ax,@data
mov ds, ax
mov dx, offset s1
mov ah, 09h
int 21h
mov cx, 3
m: shl bx, 4
mov ah, 01h
int 21h вводим n в регистр bx
sub ax, 130h
add bx, ax
loop m
mov cx, bx
xor dx, dx
xor al, al
m1: add dx, cx считаем у
jnc m2
mov al, 1
m2: loop m1
cmp al, 1
je m3
mov ym, dx
m3: mov yb, edx
mov ax, 4c00h
int 21h
end start
Команды обработки строк
Цепочка — это последовательность элементов, размер которых может быть байт, слово, двойное слово. Содержимое этих элементов может быть любое — символы, числа. В системе команд микропроцессора имеется семь операций-примитивов обработки цепочек. Каждая из них реализуется в микропроцессоре тремя командами, в свою очередь, каждая из этих команд работает с соответствующим размером элемента — байтом, словом или двойным словом.
Типовой набор действий для выполнения любой цепочечной команды:
а Установить значение флага df в зависимости от того, в каком направлении будут обрабатываться элементы цепочки — в направлении возрастания или убывания адресов.
а Загрузить указатели на адреса цепочек в памяти в пары регистров ds:(e)si и es: (e)di.
а Загрузить в регистр ecx/cx количество элементов, подлежащих обработке.
а Выдать цепочечную команду с префиксом повторений.
Пересылка цепочек
movs адрес_прием, адрес_источника (MOVe String) — переслать цепочку;
movsb MOVe String Byte) — переслать цепочку байт;
movsw (MOVe String Word) — переслать цепочку слов;
movsd (MOVe String Double word) — переслать цепочку двойных слов.
Команда копирует байт, слово или двойное слово из цепочки источника, в цепочку приемника. Размер пересылаемых элементов ассемблер определяет, исходя из атрибутов идентификаторов. К примеру, если эти идентификаторы были определены директивой db, то пересылаться будут байты, если идентификаторы были определены с помощью директивы dd, то пересылке подлежат двойные слова.
Для цепочечных команд с операндами типа movs адрес_приемника, адрес_источника, не существует машинного аналога. При трансляции в зависимости от типа операндов транслятор преобразует ее в одну из трех машинных команд: movsb, movsw или movsd.
Сама по себе команда movs пересылает только один элемент, исходя из его типа, и модифицирует значения регистров esi/si и edi/di. Если перед командой написать префикс rep, то одной командой можно переслать до 64 Кбайт данных. Число пересылаемых элементов должно быть загружено в счетчик — регистр cx (use16) или ecx (use32).
Пример 13. Пересылка строк командой movs
MODEL small
.STACK 256
.data
source db 'Тестируемая строка','$' ;строка-источник
dest db 19 DUP (' ') ;строка-приёмник
.code
main:
mov ax,@data ;загрузка сегментных регистров
mov ds, ax ;настройка регистров DS и ES на адрес сегмента данных
mov es, ax
cld ;сброс флага DF — обработка строки от начала к концу
lea si, source ;загрузка в si смещения строки-источника
lea di, dest ;загрузка в DS смещения строки-приёмника
mov cx, 20 ;для префикса rep — счетчик повторений (длина строки)
rep movs dest, source ;пересылка строки
lea dx, dest
mov ah, 09h ;вывод на экран строки-приёмника
int 21h
mov ax, 4c00h
int 21h
end main
Операция сравнения цепочек
cmps адрес_приемника, адрес_источника (CoMPare String) — сравнить строки;
cmpsb (CoMPare String Byte) — сравнить строку байт;
cmpsw (CoMPare String Word) — сравнить строку слов;
cmpsd (CoMPare String Double word) — сравнить строку двойных слов.
Алгоритм работы команды cmps заключается в последовательном выполнении вычитания (элемент цепочки-источника — элемент цепочки-получателя) над очередными элементами обеих цепочек. Принцип выполнения вычитания командой cmps аналогичен команде сравнения cmp. Она, так же, как и cmp, производит вычитание элементов, не записывая при этом результата, и устанавливает флаги zf, sf и of.
После выполнения вычитания очередных элементов цепочек командой cmps, индексные регистры esi/si и edi/di автоматически изменяются в соответствии со значением флага df на значение, равное размеру элемента сравниваемых цепочек.
Операция сканирования цепочек
scas адрес_приемника (SCAning String) — сканировать цепочку;
scasb (SCAning String Byte) — сканировать цепочку байт;
scasw (SCAning String Word) — сканировать цепочку слов;
scasd (SCAning String Double Word) — сканировать цепочку двойных слов Эти команды осуществляют поиск искомого значения, которое находится в регистре al/ax/eax. Принцип поиска тот же, что и в команде сравнения cmps, то есть последовательное выполнение вычитания
(содержимое регистра_аккумулятора — содержимое очередного_элемента_цепочки).
В зависимости от результатов вычитания производится установка флагов, при этом сами операнды не изменяются.
Загрузка элемента цепочки в аккумулятор
lods адрес_источника (LOaD String) — загрузить элемент из цепочки в регистр-аккумулятор al/ax/eax;
lodsb (LOaD String Byte) — загрузить байт из цепочки в регистр al;
lodsw (LOaD String Word) — загрузить слово из цепочки в регистр ax;
lodsd (LOaD String Double Word) — загрузить двойное слово из цепочки в регистр eax.
Эта операция-примитив позволяет извлечь элемент цепочки и поместить его в регистр-аккумулятор al, ax или eax. Эту операцию удобно использовать вместе с поиском (сканированием) с тем, чтобы, найдя нужный элемент, извлечь его (например, для изменения).
Перенос элемента из аккумулятора в цепочку
stos адрес_приемника (STOre String) — сохранить элемент из регистра-аккумулятора al/ax/eax в цепочке;
stosb (STOre String Byte) — сохранить байт из регистра al в цепочке;
stosw (STOre String Word) — сохранить слово из регистра ax в цепочке;
stosd (STOre String Double Word) — сохранить двойное слово из регистра eax в цепочке.
Эта операция-примитив позволяет произвести действие, обратное команде lods, то есть сохранить значение из регистра-аккумулятора в элементе цепочки. Эту операцию удобно использовать вместе с операцией поиска (сканирования) scans и загрузки lods, с тем, чтобы, найдя нужный элемент, извлечь его в регистр и записать на его место новое значение.
Пример 14. Подсчитайте количество несовпадающих элементов в заданной и введенной строках.
Model small
.stack 100h
.data
s0 db `Заданная строка$'
s1 db 16 ;задаем количество символов во вводимой строке + знак Enters
s2 db ?, 16 dup (?); ?- под количество введенных символов, массив под строку
s3 db 10,13, `Количество несовпадающих элементов — $' ;информац. строка
.code
mov ax, @data
mov ds, ax ;задаем адрес сегмента данных
mov es, ax ;настраиваем адрес сегмента данных, где хранится строка приемник
;вводим сравниваемую строку
mov ah, 0ah
mov dx, offset s1
int 21h
;выводим информационную строку
mov ah, 09h
mov dx, offset s3
int 21h
;сравниваем строки, один элемент из заданной строки сравниваем со всеми; элементами введенной строки
mov dl,'0' ;в dl ascii-код 0
mov cx, 16 ;в сх количество элементов в заданной строке
mov si, offset s0 ;в si адрес заданной строки-источника
z_str: push cx ;сохраняем счетчик внешних циклов в стеке
lodsb ;загружаем элемент из заданной строки в аккумулятор, al
mov di, offset s2 ;в di адрес введенной строки-приемника
mov cl, s2[di] ;в cl количество введенных элементов
xor ch, ch; обнуляем ch, т.к. в цикле счетчиком является сх
inc di ;на первый элемент строки-приемника
repe scacb
;сканируем строку-приемник до тех пор пока элемент не = содержимому al,
;или пока не кончится строка
jz m1 ;zf=1, если в строке встретился элемент = содержимому al
inc dl; считаем количество не совпадающих элементов
m1: ;внутренний цикл по введенной строке закончился
pop cx ;восстанавливаем содержимое сх
loop z_str
;после выхода из цикла в dl количество не совпадающих элементов
mov ah, 02h
int 21h ;выводим dl
mov ax, 4c00h
int 21h
end
Массивы
Организация одномерных массивов
Все элементы массива располагаются в памяти последовательно
Описание элементов массива
mas db 1,2,3,4,5
mas dw 5 dup (0)
Доступ к элементам массива
mov ax, mas[si]; в si номер элемента в массиве
mov mas[si], ax; в di номер элемента в массиве
Пример 15. Найти в строке хотя бы один нулевой элемент
model small
.stack 100h
.data
bufer dw 25 ;формирую размер буфера для ввода строки
mas db 25 dup (' ') ;формирую буфер
subj1 db `в строке найден нулевой элемент', '$'
subj2 db `в строке не найден нулевой элемент', '$'
.code
main:
mov ax,@data
mov ds, ax
; ввод строки с клавиатуры
mov ah, 0ah
mov dx, offset bufer
int 21h
;поиск нулевого элемента
xor si, si
mov cl, mas[si] ;загружаем в сх количество элементов в строке
mov al, 030h ;в ax загружаем ASCII код нуля
m1: inc si
cmp al, mas[si]
je m2
;если в строке найдем нулевой элемент, то выходим из цикла на вывод subj1
loop m1
;нормальный выход из цикла означает что в строке нет нулевых элементов
lea dx, subj2
jmp m3
m2: lea dx, subj1
m3: mov ah, 09h
int 21h
mov ax, 4c00h
int 21h
end main
Организация двумерных массивов
!Специальных средств для описания двумерных массивов в ассемблере нет!
Двумерный массив описывается также как и одномерный массив, отличие заключается в трактовке расположения элементов. Пусть последовательность элементов трактуется как двумерный массив, расположенный по строкам, тогда адрес элемента [i, j] вычисляется так База+колич_элем_строке*размер_элем*I+j
Пример 16. Найти максимальный элементы в каждой строке массива 5*7
model small
.stack 100h
.data
mas dw 5 dup (7 dup (0))
max dw 0
subj db `введите строку', 13,10,'$'
.code
main:
mov ax, @data
mov ds, ax
;заполнение массива
xor si, si
mov cx, 05h
incykl: push cx
mov ah, 09h
lea dx, subj
int 21h ;вывод информационной строки
mov cx, 07h
mov ah, 01h
outcykl: int 21h ;ввод элементов массива
mov mas[si], ax ;размещение элементов на месте
inc si
inc si
loop outcykl
pop cx
loop incykl
;поиск максимального/ минимального в строках
xor si, si
mov cx, 05h
s1t: push cx
mov cx, 06h
mov dx, mas[si]
maxi: add si, 2
cmp dx, mas[si]
ja min1 ;если меньше то переходим
mov dx, mas[si]
min1: loop maxi
;вывод максимального
mov ah, 02h
int 21h
pop cx
loop s1t
mov ax, 04c00h
int 21h
end main
Процедуры. Макрокоманды
Процедура, часто называемая подпрограммой, — это правильным образом оформленная совокупность команд, которая будучи однократно описана, при необходимости может быть вызвана в любом месте программы. Процедура представляет собой группу команд для решения конкретной подзадачи и обладает средствами получения управления из точки вызова задачи более высокого уровня и возврата управления в эту точку. В простейшем случае программа может состоять из одной процедуры.
Описание процедуры может размещается в любом месте программы, но таким образом чтобы на нее случайным образом не попало управление:
— в начале программы, до первой исполняемой команды;
— в конце, после команды возвращающей управление операционной системе;
— промежуточный вариант, тело процедуры располагается внутри другой процедуры или основной программы. В этом случае необходимо предусмотреть обход процедуры командой jmp;
— в другом модуле.
Синтаксис описания процедуры:
Имя_процедуры PROC заголовок Команды, директивы тело процедуры
[ret] возврат из процедуры
[имя_процедуры] ENDP конец процедуры Вызов процедуры осуществляется командой
CALL [модификатор] имя_процедуры
Команда call передает управление по адресу с символическим адресом имя_процедуры, с сохранением в стеке адреса возврата, команды следующей после команды call.
Возврат из процедуры осуществляется по команде
RET [число]
Команда ret считывает адрес возврата из стека и загружает его в регистры cs и ip/eip, возвращая таким образом управление команде, следующей за командой call. Число — необязательный параметр, обозначающий количество элементов, удаляемых из стека при возврате из процедуры. Размер элемента зависит от используемой модели сегментации 32 или 16 разрядной.
Передача аргументов из/в процедуру может осуществляться через регистры, переменные или стек.
Пример.
Model small .stack 100h .data w db 25 dup (?) .code vvod proc mov ah, 0ah lea dx, w int 21h ret vvod endp main: | … Call schet Call vvod … exit: mov ax, 4c00h int 21h schet proc . ret schet endp end main | |
Макрокоманда является одним из многих механизмов замены текста программы. С помощью макрокоманды в текст программы можно вставлять последовательности строк и привязывать их к месту вставки. Макрокоманда представляет собой строку, содержащую некоторое имя — имя макрокоманды, предназначенное для того, чтобы быть замещенным одной или несколькими другими строками при трансляции.
Для работы с макрокомандой вначале необходимо задать ее шаблон-описание, так называемое макроопределение.
Имя_макрокоманды MACRO [список_формальных_аргументов]
<�Тело макроопределения>
ENDM
Существует три варианта расположения макроопределений:
— в начале исходного текста программы до сегмента кода и данных с тем, чтобы не ухудшать читабельность программы. В данном случае макрокоманды будут актуальны только в пределах этой программы;
— в отдельном файле. Для того, чтобы использовать эти макроопределения в других программах, необходимо в начале исходного текста этих программ записать директиву
include имя_файла
— в макробиблиотеке. Макробиблиотека создается в том случае, когда написанные макросы используются практически во всех программах. Подключается библиотека директивой include. Недостаток этого и предыдущего методов в том, что в исходный текст программы включаются абсолютно все макроопределения. Для исправления ситуации можно использовать директиву purge, в качестве операндов которой перечисляются макрокоманды, которые не должны включаться в текст программы.
Include macrobibl. inc ;в исходный текст программы будут вставлены строки из macrobibl. inc
Purge outstr, exit ;за исключением макроопределений outstr, exit
Активизация макроса осуществляется следующим образом:
Имя_макрокоманды список_ фактических_ аргументов
Model small Vivod macro rg Mov dl, rg Mov ah, 02h Int 21h endm .data . .code . vivod al . | Model small sravnenie macro rg, met cmp rg, `a' ja met add rg, 07h met: add rg, 30h endm .data . .code . sravnenie al, m1. | |
Функционально макроопределения похожи на процедуры. Сходство их в том, что и те, и другие достаточно один раз где-то описать, а затем вызывать их специальным образом. На этом их сходство заканчивается, и начинаются различия, которые в зависимости от целевой установки можно рассматривать и как достоинства и как недостатки:
— в отличие от процедуры, текст которой неизменен, макроопределение в процессе макрогенерации может меняться в соответствии с набором фактических параметров. При этом коррекции могут подвергаться как операнды команд, так и сами команды. Процедуры в этом отношении объекты менее гибки;
— при каждом вызове макрокоманды ее текст в виде макрорасширения вставляется в программу. При вызове процедуры микропроцессор осуществляет передачу управления на начало процедуры, находящейся в некоторой области памяти в одном экземпляре. Код в этом случае получается более компактным, хотя быстродействие несколько снижается за счет необходимости осуществления переходов.
Пример 17. Найти максимальный элементы в каждой строке массива 5*7, с использованием процедур
model small
.stack 100h
.data
mas dw 5 dup (7 dup (0))
max dw 0
subj db `введите строку', 13,10,'$'
.code
;процедура ввода строки
vvod_str proc
mov ah, 09h
lea dx, subj
int 21h
mov cx, 07h
mov ah, 01h
outcykl: int 21h
mov mas[si], ax
inc si
inc si
loop outcykl
ret
vvod_str endp
;процедура поиска максимального в строке
poick-_-maxi proc
mov cx, 06h
mov dx, mas[si]
maxi: add si, 2
cmp dx, mas[si]
ja min1 ;если меньше то переходим
mov dx, mas[si]
min1: loop maxi
ret
poick-_-maxi endp
main proc
mov ax, @data
mov ds, ax
xor si, si ;заполнение массива
mov cx, 05h
incykl: push cx
call vvod_str ;вызов процедуры по вводу строки
pop cx
loop incykl
;поиск максимального/ минимального в строках
xor si, si
mov cx, 05h
s1t: push cx
call poick-_-maxi ;вызов процедуры поиска максимального элемента
mov ah, 02h ;вывод максимального
int 21h
pop cx
loop s1t
mov ax, 04c00h
int 21h
endр main
Программирование контроллера приоритетных прерываний
Для организации обработки аппаратных прерываний в вычислительных системах применяется программируемый контроллер прерываний, выполненный в виде специальной микросхемы i8259А, отечественный аналог микросхема КР580ВМ59. Эта микросхема может обрабатывать запросы от восьми источников внешних прерываний. В стандартной конфигурации вычислительных систем используют две последовательно соединенные микросхемы i8259А.
Функции микросхемы ПКП:
— фиксирование запросов на обработку прерывания от восьми источников, формирование единого запроса на прерывание и подача его на вход INTR микропроцессора;
— формирование номера вектора прерывания и выдача его на шину данных;
— организация приоритетной обработки прерываний;
— запрещение (маскирование) прерываний с определенными номерами.
На рис. 1 представлена структурная схема контроллера.
Рис. 1. Структурная схема ПКПП.
Программирование контроллера приоритетных прерываний
Цель работы:
Исследование принципа программного управления микросхемы контроллера прерываний (ПКП) i8259А с помощью ПК, исследование различных режимов работы ПКП
Микросхема i8259A имеет два состояния:
— состояние настройки параметров обслуживания прерываний, во время которого путем посылки в определенном порядке так называемых управляющих слов производится инициализация контроллера;
— состояние работы — это обычное состояние контроллера, в котором производится фиксация запросов на прерывание и формирование управляющей информации для микропроцессора в соответствии с параметрами настройки.
Возможность программирования контроллера позволяет достаточно гибко изменять алгоритмы обработки аппаратных прерываний.