1. _text segment para public 'code'
2. assume cs:_text,ds:_data
3. .386
4. .387
5. start:
6. mov ax,_data
7. mov ds,ax
8. mov si,offset mas1
9. mov bx,offset mas2
10. mov cx,10
11. a:
12. mov ax,ds:[si]
13. mov ds:[bx],ax
14. add si,2
15. add bx,2
16. loop a
17. b:
18. mov flg,0
19. mov si,offset mas2
20. mov cx,9
21. c:
22. mov ax,ds:[si]
23. mov dx,ds:[si+2]
24. cmp ax,dx
25. ja d
26. mov ds:[si],dx
27. mov ds:[si+2],ax
28. mov flg,1
29. d:
30. add si,2
31. loop c
32. cmp flg,1
33. je b
34. mov ax,4c00h
35. int 21h
36. _text ends
37. _data segment use16 para public 'data'
38. mas1 dw 7,4,2,8,6,3,5,9,10,1
39. mas2 dw 10 dup (0)
40. flg db 0
41. _data ends
42. end start
- Начало сегмента кода (‘code’).
Сегменту присваивается имя _text. Директива para указывает, что адрес начала сегмента будет выровнен
на величину параграфа, т.е. 16 байт. Иными словами физический адрес начала
сегмента будет кратен 16 байтам. Public – дословно
с книги: “заставляет компоновщик соединить все сегменты с одинаковым
именем.”. Короче это важно только тогда, когда у нас код, данные или стек
расписаны сразу в нескольких компилируемых файлах и из них надо слепить
один исполняемый файл. Нам от этого ни тепло – ни холодно, т.к. у нас программа
сосредоточена в одном файле и директиву public в
принципе можно не указывать.
- Связывание регистров cs и ds с именами сегментов _text и _data. Делается это для корректной работы транслятора.
Сегмент _data описан в конце программы.
- Указываем, что компилировать под режим 386 процессора.
Смысл использования именно этого режима мне не ясен, т.к. мы не используем
его наворотов: 32-битной адресаци и 32-битных регистров EAX,
EBX, EDX и т.д. Эту и
следующую строки я передрал из методы.
- Эта строка мне вообще не понятна и что самое интересное
нигде нет ее описания. Я проверял – программа прекрасно работает и без
нее.
- Объявляем первую и поэтому главную метку start.
Считается, что с первой метки начинается описание команд сегмента кода.
- Записываем в ax адрес начала
сегмента _data.
- Переносим адрес из регистра-аккумулятора ax
в сегментный регистр ds. Теперь по адресу ds:0 находится младший байт первого элемента массива mas1.
- В регистр si записываем смещение (offset) переменной mas1 - адрес
массива mas1 относительно адреса ds:0.
Так как в данном случае эти адреса совпадают, то в si
окажется 0.
- Аналогично в bx записываем адрес
массива mas2 относительно адреса ds:0.
В bx окажется число 20. Объясняю почему: mas1 – массив из 10 двухбайтовых чисел (размер 20 байт),
т.е. он в памяти займет адреса с ds:0 по ds:13h (ds:19).
Следовательно массив mas2, следующий в памяти
следом за mas1 начнется с адреса ds:14h (ds:20). Т.е. его смещение
относительно ds:0 равно 20 байтам, что и требовалось
доказать.
- Заносим в cx кол-во элементов,
которые необходимо переслать из массива mas1 в
массив mas2.
- Объявляем метку а. Можешь назвать ее как угодно, лишь бы
имена меток не совпадали и команды перехода ссылались на нужные метки.
- Записываем в ax слово (2 байта)
находящееся по адресу ds:[si].
- Записываем это слово по адресу ds:[bx] из регистра ax. Короче этими
двумя командами происходит пересылка одного элемента из массива mas1 в массив mas2.
- Увеличиваем si на 2, т.к. размер
элемента массива 2 байта.
- Увеличиваем bx на 2.
- Если cx не равно 0, то уменьшить
его на 1 и перейти на метку а. Это все смысл одной команды loop a.
- Объявляем метку b.
- Обнуляем флаг перестановки – переменную flg.
Можешь обозвать ее по-другому, но придется менять в программе и все ссылки
на нее.
- Записывам в si смещение массива mas2.
- Записываем в cx кол-во циклов сравнения
элементов.
- Объявляем метку с.
- В ax записываем элемент
находящийся по адресу ds:[si].
- В dx записываем элемент
находящийся по адресу ds:[si+2],
т.е. следующий элемент.
- Сравниваем ax и dx.
Физически, результатом работы этой команды является установка определенных
битов регистра флагов в 1, в зависимости от результата сравнения. Все это
нужно для следующей команды, которая как раз анализирует состояние этих
битов. Не путай регистр флагов с переменной – флагом перестановки, которую
мы объявили в программе. Они не имеют ничего общего. За регистром флагов
следит микропроцессор, а за нашим флагом мы следим сами – програмно.
- Если ax>dx
прыгнуть на метку d. ja –
сокращение от Jump if Above
(прыгнуть если больше).
- Если переход в строке 25 не произошел, т.е. ax<=dx, значит элементы [si] и [si+2] стоят не в порядке
убывания и их надо переставить, что мы и делаем строками 26 и 27.
-
- Записываем в флаг перемещений единицу. Т.е. в данном
проходе произошла хотя бы одна перестановка элементов массива. Это
свидетельствует, что упорядочивание массива еще не закончено.
- Объявляем метку d.
- Увеличиваем si на 2.
- Если cx не равно 0, то уменьшить
его на 1 и перейти на метку с.
- После того как сравнили по порядку все элементы (1 со 2, 2
с 3, 3 с 4 … 9 с 10), сравниваем значение нашего флага перестановки с
единицей.
- Если он равен 1, прыгнуть на метку b.
je – сокращение от Jump if Equal (прыгнуть если равно).
- Стандартное завершение работы для программы, компилируемой
в exe-файл.
- Стандартное завершение работы для программы, компилируемой
в exe-файл.
- Конец сегмента _text, т.е.
кодового сегмента – далее можно описывать прочие сегменты (данных, стека,
дополнительных данных и т.д.).
- Начало описания сегмента данных (‘data’).
Помимо уже известного имеется директива use16,
которая говорит о том, что адресация – 16-битная и следовательно размер
сегмента ограничивается 64кБ. Если не указать эту директиву, то для режима
386 компилятор выдаст ошибки, т.к. под режим 386 по умолчанию вставляется
директива use32 (адресация 32-битная, до 4Гб на
сегмент – используется для программирования под защищенный режим
микропроцессора).
- Объявляем массив mas1
- Объявляем массив mas2. Запись dw 10 dup (0) означает 10
однотипных (dup) ячеек с размером каждой 2 байта (dw) с начальным значением каждой равным 0.
- Объявляем однобайтовую (db)
переменную flg – флаг перестановки.
- Конец сегмента _data.
- Конец главной метки start. Только
для главной метки необходимо в самом конце программы писать: end <имя метки> и не спрашивай зачем – надо и все!