![](/user_photo/2706_HbeT2.jpg)
- •Тема 2. Архітектура процесора і мова асемблера: Основи програмування на мові асемблера
- •1.1. Додавання двійкових чисел без знака
- •1.2. Додавання двійкових чисел зі знаком
- •1.3. Віднімання двійкових чисел без знака
- •1.4. Віднімання двійкових чисел зі знаком
- •1.5. Віднімання і додавання операндів великої розмірності
- •1.6. Множення чисел без знака
- •1.7. Множення чисел зі знаком
- •1.8. Ділення чисел без знака
- •1.9. Ділення чисел зі знаком
1.6. Множення чисел без знака
Для множення чисел без знака призначена команда mul співмножник _1
Як бачите, в команді вказано всього лише один операнд-співмножник_1. Другий операнд - співмножник_2 задано неявно. Його місце розташування фіксоване і залежить від розміру співмножників. Оскільки в загальному випадку результат множення перебільшує будь-який з його співмножників, то його розмір і місце розташування мають бути теж визначені однозначно. Варіанти розмірів співмножників і розміщення другого операнда і результату наведено в табл. 9.1.
Таблиця 9.1 – Розташування операндів і результату при множенні
співмножник _1 |
співмножник _2 |
Результат |
|
Байт |
al |
16 біт в ax: al — молодша частина результату; ah — старша частина результату |
|
Слово |
ax |
32 біт в парі dx:ax: aх —молодша частина результату; dx — старша частина результату |
|
Подвійне слово |
eax |
64 біт в парі edx:eax: eax—молодша частина результату; edx — старша частина результату |
|
|
|
Лістинг 3. Множення <1> ;prg_9_3.asm <2> masm <3> model small <4> stack 256 <5> .data ;сегмент даних <6> rez label word <7> rez_l db 45 <8> rez_h db 0 <9> .code ;сегмент коду <10> main: ;точка входу в програму <11> ... <12> xor ax,ax <13> mov al,25 <14> mul rez_l <15> jnc m1 ;якщо нема переносу, то на m1 <16> mov rez_h,ah ;старшу частину результату ;в rez_h <17> m1: <18> mov rez_l,al <19> exit: <20> mov ax,4c00h ;стандартний вихід <21> int 21h <22> end main ;кінець програми |
• якщо старша частина результату нульова, то після операції множення прапори cf = 0 і of = 0;
• якщо ж ці прапори ненульові, то це означає, що результат вийшов за межі молодшої частини добутку і складається з двох частин, що і потрібно враховувати при подальшій роботі.
Наведемо приклад програми.
У цій програмі у рядку 14 здійснюється множення значення в rez_l на число в регістрі al. Згідно з інформацією в табл. 9.1, результат множення буде розташовуватися в регістрі al (молодша частина) і регістрі ah (частина старша). Для з'ясування розміру результату в рядку 15 командою умовного переходу jnc аналізується стан прапора cf і якщо воно не дорівнює 1, то результат залишився в межах регістра al. Якщо ж cf = 1, то виконується команда в рядку 16, яка формує в полі rez_h старше слово результату. Команда у рядку 18 формує молодшу частину результату. А тепер зверніть увагу на сегмент даних, а саме, на рядок 6. У цьому рядку міститься директива label. Ми ще не раз будемо стикатися з цією директивою. У даному випадку вона призначає ще одне символічне ім'я rez адресі, на яку вже вказує інший ідентифікатор rez_l. Відмінність полягає в типах цих ідентифікаторів - ім'я rez має тип слова, який йому призначається директивою label (ім'я типу зазначено в якості операнда label). Ввівши цю директиву в програмі, ми підготувалися до того, що, можливо, результат операції множення буде займати слово в пам'яті. Зверніть увагу, що ми не порушили принципи: молодший байт за молодшою адресою. Далі, використовуючи ім'я rez, можна звертатися до значення в цій області як до слова.