Программирование контроллера приоритетных прерываний

–PAGE_BREAK–xor    ax, dx                 ; если содержимое совпадает то в регистре ах мы получим
; нулевой результат, иначе не нулевой результат.
xor    bh,10b                ; инвертировали 1й бит в регистре bh
testоперанд_1, операнд_2 — операция “проверить” (способом логического умножения). Команда выполняет поразрядно логическую операцию И над битами операндов операнд_1 и операнд_2. Состояние операндов остается прежним, изменяются только флаги zf, sf, и pf, что дает возможность анализировать состояние отдельных битов операнда без изменения их состояния.
notоперанд — операция логического отрицания. Команда выполняет поразрядное инвертирование (замену значения на обратное) каждого бита операнда. Результат записывается на место операнда.
not    ax      ;ax:=
Пример  SEQ Пример \* ARABIC 5. Логическое сложение двух однобайтных чисел.
end         start
Следующие две команды позволяют осуществить поиск первого установленного в 1 бита операнда. Они появились в 486 процессоре.
bsfоперанд_1, операнд_2– сканирование бит операнда_2 от младшего к старшему в поисках первого бита установленного в 1. Если такой обнаружится, то в операнд_1 заноситься номер этого бита в целочисленном формате.

Пример:
moval,02h
bsf    bx,al ; bx:=1, т.к. 1й бит регистра al=1
bsrоперанд_1, операнд_2– сканирование бит операнда_2 от старшего к младшему в поисках первого бита установленного в 1. Если такой обнаружится, то в операнд_1 заноситься номер этого бита в целочисленном формате.
Пример:
moval,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
Пример  SEQ Пример \* ARABIC 6. Сложение двух однобайтных чисел.
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делитель — операция деления двух двоичных значений со знаком
Пример  SEQ Пример \* ARABIC 7. Умножение двух однобайтных чисел.
end         start
Пример  SEQ Пример \* ARABIC 8. Деление двух однобайтных чисел.
end         start
ASCIIкоды и их интепритация
Ввод информации с клавиатуры и вывод ее на экран осуществляется в символьном виде, т.е. любой символ предоставляется в ASCIIкодах. Причем на один символ идет один ASCIIкод. На два символа – два ASCIIкода, и т.д. Любое число, вводимое с клавиатуры и выводимое на экран, представляется последовательностью ASCIIкодов.
Табл.1. ASCIIкоды цифр
Рассмотрим последовательность действий для преобразования чисел в их ASCIIкод и наоборот.
Ввод информации с клавиатуры:
1.                Ввод символа с клавиатуры, один ASCIIкод находится в dl. Заранее не известно, что это за число от 0 до 9 или от а до f.
Cmpdl, 040h
Jb      m1   ; если ASCIIкод меньше 40hзначит ввели цифру от 0 до 9,
; переходим на метку m1
Cmpdl, 047h     ; иначе ввели букву, заглавную или маленькую?
Jb     m2   ; если ввели заглавную, переходим на m2, иначе выполняем
; дальше по программе
sub   dl, 057h     ; в dlполучаем из символов число a..fh
jmp  m3   ; переходим на m3 чтобы не выполнять лишних вычислений
m2:   sub   dl, 037h     ; в dlполучаем из символов число a..fh
jmp   m3
m1:   sub   dl, 030h     ; в dlполучаем из символов число 0..9 h
m3:
Далее приведен оптимизированный код преобразования числа из ASCIIкодов. Подумайте в чем разница.
Cmpdl,040h
Jbm1
Cmpdl,047h
Jb m2
Sub dl, 020h
m2: sub dl, 07h
m1: sub dl, 030h
2.                Ввод строки, отличается только тем, что такое сравнение надо проводить с каждым элементом, т.е. надо организовать цикл и обращение к каждому элементу. Рассмотрим позднее.
Вывод информации на экран
  1. Предположим что, число, которое мы хотим вывести, находится в регистре bl. Вывод символа осуществляется из регистра dl, 02 функция INT21H. Число может быть одно или двузначное, например 7hили 5Fh. Для универсальности программы будем считать, что надо вывести двузначное число. А для этого надо получить отдельно десятки и единицы, и получить для них два ASCIIкода.
; двузначное число которое хотим вывести находится в bl
movdl, 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
int     21h
mov dl, bl
cmp  dl, 0ah       ; сравниваем dlс ah
jb      m2
add    dl, 07h
m2:   add    dl, 30h
int    21h
Попробуйте сами разобраться в приведенном кусочке кода.
 SHAPE  \* MERGEFORMAT

Команды передачи управления
По принципу действия, команды микропроцессора, обеспечивающие организацию переходов в программе, можно разделить на три группы:
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 ноль.
Условные переходы по содержимому флагов Пример  SEQ Пример \* ARABIC 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 не изменять (то есть результат не запоминать).
Условные переходы после команд сравнения
    продолжение
–PAGE_BREAK–Пример  SEQ Пример \* ARABIC 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 Пример  SEQ Пример \* ARABIC 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 команду
Организация цикла:
movcx, количество циклов
м1: тело цикла
 loopm1
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 байт).
Организация вложенных циклов:
movcх,n; в сх заносим количество итераций внешнего цикла
m1:
pushcx

movcx,n1; в сх заносим количество итераций внутреннего цикла
                            m2:
тело внутреннего цикла
                            loopm2
                            …
                            popcx
                            loopm1
Пример  SEQ Пример \* ARABIC 12. Напишите программу подсчета у=1+2+3+…+n, n не более 10000.
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адрес_прием, адрес_источника(MOVeString)- переслать цепочку;
movsbMOVe 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).
Пример  SEQ Пример \* ARABIC 13. Пересылка строк командой movs
MODELsmall
.STACK256
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
Операция сравнения цепочек
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(STOreStringByte) — сохранить байт из регистра al в цепочке;
stosw (STOreStringWord) — сохранить слово из регистра ax в цепочке;
stosd(STOreStringDoubleWord) — сохранить двойное слово из регистра eax в цепочке.
Эта операция-примитив позволяет произвести действие, обратное команде lods, то есть сохранить значение из регистра-аккумулятора в элементе цепочки. Эту операцию удобно использовать вместе с операцией поиска (сканирования) scans и загрузки lods, с тем, чтобы, найдя нужный элемент, извлечь его в регистр и записать на его место новое значение.

Пример  SEQ Пример \* ARABIC 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
Массивы
Организация одномерных массивов
Все элементы массива располагаются в памяти последовательно
Описание элементов массива
masdb1,2,3,4,5
masdw5 dup(0)
Доступ к элементам массива movax,mas[si]   ; в siномер элемента в массиве
movmas[si], ax  ; в diномер элемента в массиве
Пример  SEQ Пример \* ARABIC 15. Найти в строке хотя бы один нулевой элемент
model         small
.stack          100h
.data
buferdw     25              ; формирую размер буфера для ввода строки
masdb       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
movcl, mas[si]  ; загружаем в сх количество элементов в строке
moval, 030h              ; в axзагружаем ASCIIкод нуля
m1:   inc     si               
cmp   al, mas[si]
je       m2
; если в строке найдем нулевой элемент, то выходим из цикла на вывод subj1
loopm1
; нормальный выход из цикла означает что в строке нет нулевых элементов
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
Пример  SEQ Пример \* ARABIC 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: int21h  ; ввод элементов массива
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 разрядной.
Передача аргументов из/в процедуру может осуществляться через регистры, переменные или стек.
    продолжение
–PAGE_BREAK–Пример.
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, в качестве операндов которой перечисляются макрокоманды, которые не должны включаться в текст программы.
Includemacrobibl.inc   ; в исходный текст программы будут вставлены строки из macrobibl.inc
Purgeoutstr, exit ; за исключением макроопределений outstr, exit
Активизация макроса осуществляется следующим образом:
Имя_макрокоманды список_ фактических_ аргументов
Функционально макроопределения похожи на процедуры. Сходство их в том, что и те, и другие достаточно один раз где-то описать, а затем вызывать их специальным образом. На этом их сходство заканчивается, и начинаются различия, которые в зависимости от целевой установки можно рассматривать и как достоинства и как недостатки:
— в отличие от процедуры, текст которой неизменен, макроопределение в процессе макрогенерации может меняться в соответствии с набором фактических параметров. При этом коррекции могут подвергаться как операнды команд, так и сами команды. Процедуры в этом отношении объекты менее гибки;
— при каждом вызове макрокоманды ее текст в виде макрорасширения вставляется в программу. При вызове процедуры микропроцессор осуществляет передачу управления на начало процедуры, находящейся в некоторой области памяти в одном экземпляре. Код в этом случае получается более компактным, хотя быстродействие несколько снижается за счет необходимости осуществления переходов.

Пример  SEQ Пример \* ARABIC 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
mainproc
mov  ax, @data
mov  ds, ax
xor    si, si           ; заполнение массива
movcx, 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 имеет два состояния:
–                     состояние настройки параметров обслуживания прерываний, во время которого путем посылки в определенном порядке так называемых управляющих слов производится инициализация контроллера;
–                     состояние работы — это обычное состояние контроллера, в котором производится фиксация запросов на прерывание и формирование управляющей информации для микропроцессора в соответствии с параметрами настройки.
Возможность программирования контроллера позволяет достаточно гибко изменять алгоритмы обработки аппаратных прерываний.
В процессе загрузки компьютера и в дальнейшем во время работы контроллер прерываний настраивается на работу в одном из шести режимов:
1.Режимфиксированныхприоритетов(Fixed Priority, Fully Nested Mode).
В этом режиме контроллер находится сразу после инициализации. Запросы прерываний имеют жесткие приоритеты от 0 до 7 (0 — высший) и обрабатываются в соответствии с приоритетами. Прерывание с меньшим приоритетом никогда не будет обработано, если в процессе обработки прерываний с более высокими приоритетами постоянно возникают запросы на эти прерывания.
2. Автоматический сдвиг приоритетов (Automatic Rotation). Режим циклической обработки прерываний.
В этом режиме дается возможность обработать прерывания всех уровней без их дискриминации. Например, после обработки прерывания уровня 4 ему автоматически присваивается низший приоритет, при этом приоритеты для всех остальных уровней циклически сдвигаются и прерывания уровня 5 будут иметь в данной ситуации высший приоритет и, следовательно, возможность быть обработанными.
3. Программно-управляемый сдвиг приоритетов (Specific Rotation).
Программист может сам передать команду циклического сдвига приоритетов ПКП, задав соответствующее управляющее слово. В команде задается номер уровня, которому требуется присвоить максимальный приоритет. После выполнения такой команды устройство работает так же, как и в режиме фиксированных приоритетов, с учетом их сдвига. Приоритеты сдвигаются циклически, таким образом если максимальный приоритет был назначен уровню 3, то уровень 2 получит минимальный и будет обрабатываться последним.
4 Автоматическое завершение обработки прерывания (Automatic End Of Interrupt, AEOI).
В обычном режиме работы процедура обработки аппаратного прерывания должна перед своим завершением очистить свой бит в ISR специальной командой, иначе новые прерывания не будут обрабатываться ПКП. В режиме AEOI нужный бит в ISR автоматически сбрасывается в тот момент, когда начинается обработка прерывания нужной процедурой обработки и от нее не требуется издавать команду завершения обработки прерывания (EOI). Сложность работы в данном режиме обуславливается тем, что все процедуры обработки аппаратных прерываний должны быть повторно входимыми, т. к. за время их работы могут повторно возникнуть прерывания того же уровня.
5. Режим специальной маски (Special Mask Mode).
Данный режим позволяет отменить приоритетное упорядочение обработки запросов и обрабатывать их по мере поступления. После отмены режима специальной маски предшествующий порядок приоритетов уровней сохранается.
6. Режим опроса (PollingMode).
В этом режиме аппаратные прерывания не происходят автоматически. Появление запросов на прерывание должно определяться считыванием IRR. Данный режим позволяет так же получить от ПКП информацию о наличии запросов на прерывания и, если запросы имеются, номер уровня с максимальным приоритетом, по которому есть запрос
Программирование контроллера прерываний i8259A
Для вывода информации в ПКП используются 2 порта ввода-вывода. Порт с четным адресом (обычно это порт 20h) и порт с нечетным адресом (обычно 21h). Через эти порты могут быть переданы 4 слова инициализации (Initialization Control Word, ICW1 — ICW4), задающие режим работы ПКП, и 3 операционных управляющих слова (слова рабочих приказов, Operation Control Words, OCW1 — OCW3).
В порт с четным адресом выводятся ICW1, OCW2 и OCW3.
Порт с нечетным адресом используется для вывода ICW2, ICW3, ICW4 и OCW1. Неоднозначности интерпретации данных в этом случае так же не возникает, т. к. слова инициализации ICW2 — ICW4 должны непосредственно следовать за ICW1, выведенным в порт с четным адресом и выводить в промежутке между ними OCW1 не следует, оно не будет опознано контроллером.
Выводом в порт с четным адресом управляющего слова инициализации ICW1 начинается инициализация ПКП. В процессе инициализации контроллер последовательно принимает управляющие слова ICW1 — ICW4. При наличии в системе одного контроллера ICW3 не выводится. Наличие ICW4 определяется содержанием ICW1. При наличии каскада из нескольких ПКП каждый из них инициализируется отдельно.
Для инициализации и управления работой ведомого контроллера используются адреса A0h, A1h. В порт с адресом A0h выводятся ICW1, OCW2 и OCW3. Порт с адресом A1h используется для вывода ICW2, ICW3, ICW4 и OCW1.
При наличии в системе ведомого контроллера слово ICW3 для контроллеров ПКП обязательно.
Формат ICW1 следующий:
ICW2 – определение базового адреса:
Управляющее слово ICW2 задает номер вектора прерывания, процедуры обработки прерываний, для аппаратного прерывания irq0. Вектора обработки аппаратных прерываний располагаются последовательно с адреса 08h, загружаемого в начале работы процессора. Некорректное изменение номера вектора приведет к сбою всей системы.
Формат ICW3 для ведущего контроллера следующий:

Формат ICW3 для ведомого контроллера следующий:
Формат ICW4:
    продолжение
–PAGE_BREAK–В процессе работы с ПКП вы можете без переинициализации:
–                   маскировать и размаскировать аппаратные прерывания;
–                   изменять приоритеты уровней;
–                   издавать команду завершения обработки аппаратного прерывания;
–                   устанавливать/сбрасывать режим специальной маски;
–                   переводить контроллер в режим опроса и считывать состояние регистров ISR и IRR.
Для этого Вам потребуется вывести в порты ПКП одно из трех слов рабочих приказов OCW1 — OCW3.

Формат OCW1 – управление регистром масок IMR:
Формат OCW2 – управление приоритетом:
Формат OCW3 – общее управление контроллером:

Распределение и приоритеты аппаратных прерываний в архитектуре АТ
Программирование контроллера прямого доступа памяти
  Программирование контроллера ПДП Цель работы:
Исследование принципа программного управления микросхемы, контроллера прямого доступа памяти (ПДП) i8237А с помощью ПК, исследование различных режимов работы ПДП.
Прямой доступ к памяти – DMA(DirectMemoryAccess) метод обмена данными периферийного устройства с памятью без участия процессора. В режиме прямого доступа к памяти процессор инициализирует контроллер прямого доступа к памяти – задает начальный адрес, счетчик и режим обмена, после чего освобождается. Сам обмен производит контроллером ПДП, что обеспечивает высокоскоростной обмен данными между устройствами ввода-вывода и ОЗУ без использования центрального процессора, это позволяет освободить процессор для выполнения вычислений параллельно с обменом и независимо от него. Наиболее часто возможности ПДП используются при работе с дисковыми накопителями, однако реализовано использование ПДП рядом других устройств. Ощутимые преимущества дает использование ПДП в процессе обмена с устройствами, принимающими или передающими данные достаточно большими порциями с высокой скоростью.
Четырехканальный контроллер ПДП i8237А имеет 16-разрядные регистры адреса и счетчики, что обеспечивает возможность программирования передачи блока данных размером до 64 Кбайт. Для обеспечения доступности адресного пространства памяти размером в 1 Мбайт применили внешние 4-разрядные регистры страниц DMA, отдельные для каждого канала. В этих регистрах хранятся биты адреса А[19:16], а битами А[15:0] управляет контроллер.
Микросхема i8237А допускает каскадирование при довольно гибком конфигурировании.
Принципы работы контроллера ПДП В работе ПДП различаются 2 главных цикла: цикл ожидания (Idle cycle) и активный цикл (Active cycle). Каждый цикл подразделяется на ряд состояний, занимающих по времени один период времени (тик). Из цикла ожидания контроллер может быть переведен в состояние программирования (Program Condition) путем подачи на вход RESET сигнала высокого уровня, длительностью не менее 300 нc и следующей за ним подачи сигнала низкого уровня (уровня 0) на вывод CS (Chip Select). В состоянии программирования контроллер будет находится до тех пор, пока на выводе CS сохранится сигнал низкого уровня. В процессе программирования контроллеру задаются:
–    начальный адрес памяти для обмена;
–    уменьшенное на единицу число передаваемых байтов;
–    направление обмена;
–    требуемые режимы работы (разрешить или запретить циклическое изменение приоритетов, автоинициализацию, задать направление изменения адреса при обмене и т. д.).
Загрузка 16-разрядных регистров контроллера осуществляется через 8-разрядные порты ввода-вывода. Перед загрузкой первого (младшего) байта должен быть сброшен (очищен) триггер-защелка (триггер первый/последний, First/Last flip-flop), который изменяет свое состояние после вывода в порт первого байта и таким образом дает возможность следующей командой вывода в тот же порт загрузить старший байт соответствующего регистра.
Запрограммированный канал должен быть демаскирован (бит маски канала устанавливается при этом в 0), после чего он может принимать сигналы «Запрос на ПДП», генерируемые тем внешним устройством, которое обслуживается через этот канал. Сигнал «Запрос на ПДП» может быть также инициирован установкой в 1 бита запроса данного канала в регистре запросов контроллера. После появления сигнала запроса контроллер входит в активный цикл, в котором выполняется обмен данными. Обмен может осуществляется в одном из четырех режимов:
1. Режим одиночной передачи (Signle Transfer Mode).
После каждого цикла передачи контроллер освобождает шину процессору, но сразу же начинает проверку сигналов запроса и, как только обнаруживает активный сигнал запроса, инициирует следующий цикл передачи.
2. Режим блочной передачи (Block Transfer Mode).
В этом режиме наличие сигнала запроса требуется только до момента выдачи контроллером сигнала «Подтверждение запроса на ПДП» (DACK), после чего шина не освобождается вплоть до завершения передачи всего блока.
3. Режим передачи по требованию (DemandTransferMode).
Данный режим является промежуточным между двумя первыми: передача идет непрерывно до тех пор, пока активен сигнал запроса, состояние которого проверяется после каждого цикла передачи. Как только устройство не может продолжить передачу, сигнал запроса сбрасывается им и контроллер приостанавливает работу. Этот режим применяется для обмена с медленными устройствами, не позволяющими по своим временным характеристикам работать с ПДП в режиме блочной передачи.
4. Каскадный режим (Cascade Mode).
Режим позволяет включить в подсистему ПДП более одного контроллера в тех случаях, когда недостаточно четырех каналов ПДП. В этом режиме один из каналов ведущего контроллера используется для каскадирования с контроллером второго уровня. Для работы в каскаде сигнал HRQ («Запрос на захват») ведомого контроллера подается на вход DREG («Запрос на канал ПДП») ведущего, а сигнал DACK («Подтверждение запроса») ведущего подается на вход HDLA («Подтверждение захвата») ведомого.
Такая схема подключения аналогична подключению ведущего (первого) контроллера к микропроцессору, с которым он обменивается сигналами HRQ и HDLA.
Типы возможных режимов передач
1. Передача память-память (Memory-to-memoryDMA)
Используется для передачи блока данных из одного места памяти в другое. Исходный адрес определяется в регистрах нулевого канала, выходной — в регистрах первого канала. Число циклов обмена (число байт минус 1) задается в регистре числа циклов канала 1. Передача происходит с использованием рабочего регистра контроллера в качестве промежуточного звена для хранения информации. При передачe память-память может быть задан специальный режим фиксации адреса (Address hold), при котором значение текущего адреса в регистре нулевого канала не изменяется, при этом весь выходной блок памяти заполняется одним и тем же элементом данных, находящимся по заданному адресу.
2. Автоинициализация (автозагрузка, Autoinitialization)
После завершения обычной передачи использованный канал ПДП маскируется и должен быть перепрограммирован для дальнейшей работы с ним. При автоинициализации маскировка канала после окончания передачи не происходит, а регистры текущего адреса и счетчик циклов автоматически загружаются из соответствующих регистров с начальными значениями. Таким образом для продолжения (повторения) обмена достаточно выставить сигнал запроса на ПДП по данному каналу.
3. Режим фиксированных приоритетов
В этом режиме канал 0 всегда имеет максимальный приоритет, а канал 3 — минимальный. Это означает, что любая передача по каналу с более высоким приоритетом будет выполняться раньше, чем по каналу с более низким приоритетом.
4. Циклический сдвиг приоритетов
Позволяет избежать «забивания» шины одним каналом при одновременной передаче по нескольким каналам. Каждому каналу, по которому прошла передача, автоматически присваивается низший приоритет, после чего право на передачу получает канал с наивысшим приоритетом, для которого передача в данный момент возможна. Таким образом, если в начале работы распределение приоритетов было обычным (канал 0 — наивысший), и пришли сигналы запроса на ПДП по 1-му и 2-му каналам, то сначала будет выполняться передача по первому каналу, затем он получит низший приоритет (а канал 2, соответственно, высший, т. к. сдвиг приоритетов циклический) и передача выполнится по 2-му каналу, который затем получит низший приоритет, а высший приоритет получит, соответственно, канал 3, который и будет обладать преимущественным правом на передачу.
5. Сжатиевременипередачи(Comdivssed transfer timing).
В случае, если временные характеристики быстродействия обменивающихся устройств совпадают, ПДП может сократить время выполнения каждого такта передачи на 2 цикла часов за счет тактов ожидания, входящих в каждый цикл передачи.
Распределение каналов прямого доступа Прямой доступ к памяти был использован еще в PC/XT, где для этого применялась микросхема четырехканального контроллера 8237А.
Из четырех каналов DMA XT на шине ISA доступны только три (1, 2 и 3). Канал 0 используется для регенерации динамической памяти, и от него на шину ISA выводится только сигнал подтверждения DACKO#, он же REFRESH#. Этот сигнал может использоваться для регенерации динамической памяти, если таковая используется на платах адаптера. Адрес регенерируемой строки берется с линий адреса шины ISA. Каналы 1, 2 и 3 обеспечивают побайтную передачу данных и называются 8-битными каналами DMA.
В архитектуре AT подсистему DMA расширили, добавив второй контроллер 8237А. Его подключили к шине адреса со смещением на 1 бит, и его 16-битные регистры адреса способны управлять линиями адреса А[1б:1], младший бит адреса АО всегда нулевой. Таким образом, второй контроллер может обеспечивать передачу данных только пословно (по два байта), за что его каналы и названы 16-битными. За один сеанс второй контроллер способен передать массив до 64К 16-разрядных слов. Регистры страниц для всех каналов DMA у AT расширены до 8 бит, что делает доступной для любого канала область памяти размером 16 Мбайт (0-FFFFFFh). Стандартное назначение каналов приведено в табл. 1.
Кроме увеличения числа каналов в AT ввели дополнительную возможность управления шиной ISA — Bus-Mastering — со стороны адаптера. Это внешнее управление шиной опирается на контроллер DMA, выполняющий в данном случае функции арбитра шины. Для получения управления шиной внешний Bus-Master посылает запрос по линии DRQx (только для каналов 5-7) и, получив подтверждение DACKx, устанавливает сигнал MASTERS. Теперь шиной ISA управ­ляет он, но формально он не имеет права занимать шину больше чем на 15 мкс за сеанс. В противном случае нарушится регенерация памяти (позже собьется системное время, но при нарушении регенерации эти «мелочи» уже не важны). Интеллектуальный контроллер может выполнять более эффективные процедуры обмена, чем стандартный DMA, например:
Scatter Write — «разбросанная» запись в несколько блоков памяти.
Gather Read — чтение со сбором данных из нескольких блоков памяти.
Обмен нечетным количеством байт и (или) с нечетного адреса по 16-бит­ному каналу.
Управление шиной используют высокопроизводительные адаптеры SCSI и локальных сетей, а также интеллектуальные графические адаптеры. Однако архитектурой шины доступное им пространство памяти ограничено областью 16 Мбайт, что по нынешним меркам маловато. «Заботливые» операционные системы (например, Novell NetWare) для таких адаптеров позволяют под буферы резервировать область в пределах младших 16 Мбайт.
На шине EISA DMA-каналы могут работать в 8-, 16- и 32-битном режиме, они могут использовать все 32 разряда шины адреса — иметь доступ ко всей памяти компьютера. Каждый канал может программироваться на 1 из 4 типов цикла передачи:
Compatible — полностью совместим с ISA.
Type A — сокращенный на 25% цикл: время одиночного цикла 875 нс, в блочном режиме время цикла 750 нс. Работает почти со всеми ISA-адап­терами с большей скоростью.
Type В — сокращенный на 50% цикл (750/500 нс на цикл), работает с большинством EISA-адаптеров и некоторыми ISA. Этот тип цикла возмо­жен только с памятью, непосредственно доступной контроллеру шины EISA (памятью на адаптерах EISA, а также системной в случае, если EISA является основной шиной системной платы). Если декодированный адрес памяти относится к 8/16-битной памяти ISA, то контроллер DMA EISA автоматически переводится в режим Compatible.
Type С (Burst Timing) — сокращенный на 87,5% цикл, ориентированный на пакетный режим передач. Работает со скоростными EISA-адаптерами и при обмене 32-битных устройств с 32-битной памятью позволяет разви­вать скорость обмена до 33 Мбайт/с.
В PCI-системах для обмена с устройствами системной платы (Fast ATA-2 или E-IDE-порты) возможно использование DMA Type F, при котором между соседними циклами интервал может не превышать 3 тактов шины (360 нс). Для разгрузки системной шины используется дополнительный 4-байтный буфер. Режим F может работать только в режиме одиночной передачи или по запросу и только с инкрементом (увеличением) адреса. На самой шине PCI адаптеры могут использовать режим прямого управления шиной, для чего имеется специальный протокол арбитража, который к контроллерам DMA отношения уже не имеет.
    продолжение
–PAGE_BREAK–