Багатомодульне програмування.

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
Не вказано
Факультет:
КН
Кафедра:
Кафедра ЕОМ

Інформація про роботу

Рік:
2013
Тип роботи:
Звіт до лабораторної роботи
Предмет:
Засоби системного програмування

Частина тексту файла (без зображень, графіків і формул):

Міністерство освіти і науки, молоді та спорту України Національний університет “Львівська політехніка” Кафедра ЕОМ Звіт з лабораторної роботи № 7 на тему: Багатомодульне програмування. з дисципліни: " Засоби системного програмування" Варіант № 11 Мета: Оволодіти навиками створення багатомодульних програм. Засвоїти правила взаємодії різних модулів. Теоретичні відомості Багатомодульне програмування При роботі на мові Асемблер під багатомодульним програмуванням розуміють процес написання кількох процедур, підпрограм, у різних вихідних файлах з подальшим їх об’єднанням на етапі лінкування. Таке доцільно робити, коли: є необхідність компонування декількох програм написаних на різних мовах програмування (наприклад, для об’єднання потужності мов високого рівня та ефективності асемблера); програма, написана у вигляді одного модуля, може виявитись завеликою для асемблювання; окремі модулі можуть бути написані різними проектувальниками з метою подальшої інтеграції; з причини великого розміру виконавчого модуля може виникнути необхідність перекриття окремих частин програми в процесі виконання. Кожна програма асемблюється окремо і генерує власний унікальний об’єктний (OBJ) модуль. Програма  компонувальник (LINK) як правило виконання починається з основної програми, яка викликає одну або декілька підпрограм. Підпрограми, в свою чергу, можуть задіювати інші підпрограми. Виклик іншої програми зумовлює необхідність міжсегментного (довгого) виклику (CALL). Дана операція спочатку записує до стеку вміст регістру CS і заносить до цього регістру адресу іншого сегменту, потім записує до стеку значення регістру IP і заносить до цього регістру нову відносну адресу. Таким чином, в стеку запам’ятовуються і адреса кодового сегменту, і зміщення для наступного повернення з підпрограми. Наприклад, міжсегментний виклик (CALL) може складатись з такого об’єктного коду: 9A 0002 AF04 Машинний код для міжсегментного виклику CALL – 9A. При цьому команда CALL записує значення 0002 у вигляді 0200 до регістру IP, а значення 04AF – до регістру CS. Комбінація цих адрес вказує на першу виконувану команду у програмі, що викликається: Кодовий сегмент 04AF0  Зміщення в IP 0200  Дійсна адреса 04CF0   При виході з процедури, що викликалась, міжсегментна команда REТ відновлює обидві адреси в регістрах CS і IP і, таким чином, передає управління на наступну після CALL команду. Розглянемо, наприклад, основну програму MAINPROG та підпрограму, що викликається за допомогою міжсегментного виклику CALL - SUBPROG. EXTRN SUBPROG : FAR MAINPROG: . CALL SUBPROG .... PUBLIC SUBPROG SUBPROG: . .... RET Команда CALL в основній програмі повинна “знати”, що програма, яка викликається, знаходиться поза межами даного сегменту. Директива EXTRN вказує асемблеру, що посилання на SUBPROG має атрибут FAR, тобто є визначеним в іншому асемблерному модулі. Оскільки сам асемблер не має можливості точно визначити такі посилання, він генерує пустий об’єктний код для наступного його заповнення при компонуванні: 9A 0000 ---- E Підпрограма SUBPROG містить директиву PUBLIC, що вказує асемблеру і компонувальнику, що інший модуль повинен “знати” адресу SUBPROG. В результаті, після успішного асемблювання програм MAINPROG і SUBPROG в окремих об’єктних модулях, вони можуть бути скомпільовані наступним чином: D:\HOME\TASM > tasm MAINPROG /l D:\HOME\TASM > tasm SUBPROG /l D:\HOME\TASM > tlink MAINPROG + SUBPROG Компонувальник встановлює відповідності між адресами EXTRN в одному об’єктному модулі з адресами PUBLIC в іншому і заносить необхідні відносні адреси. Потім він об’єднує два об’єктних модуля в один виконавчий. В разі неможливості розв’язати посилання компонувальник видає повідомлення про помилку. Директива EXTRN має такий формат: EXTRN ім’я : тип [, … ] Можна призначити більше одного імені (до кінця рядка) або закодувати додаткові директиви EXTRN. В іншому асемблерному модулі відповідне ім’я повинно бути визначене і ідентифіковане як PUBLIC. Існують такі типи елементів: ABS, BYTE, WORD, DWORD, FAR, NEAR. Ім’я може бути визначене через EQU і повинно задовольняти реальному визначенню імені. Директива PUBLIC вказує асемблеру і компонувальнику, що адреса вказаного ідентифікатора є доступною з інших програм. Директива має такий формат: PUBLIC ідентифікатор [, … ] Можна призначити більше одного ідентифікатора (до кінця рядка) або закодувати додаткові директиви PUBLIC. Ідентифікатори можуть бути мітками (включаючи PROC-мітки), змінними або числами. Неправильними ідентифікаторами є імена регістрів та EQU-ідентифікатори, що призначають більш як двобайтні значення. Існує декілька способів компонування програм. Кожен з них характеризується одною або декількома такими рисами: директиви EXTRN і PUBLIC в якості міток; спільний кодовий сегмент - шляхом використання директиви PUBLIC в заголовку кодового сегменту кожної з програм, що компонуються; спільні дані. Передача параметрів через стек Даний спосіб взаємодії програм характеризується тим, що програма, що викликає іншу, передає їй параметри шляхом запису даних до стеку. Кожна команда PUSH при цьому повинна записувати до стеку дані розміром в одне слово з пам’яті або з регістру. Програма, приведена далі, перш ніж викликати підпрограму SUBMUL заносить у стек значення з полів PRICE і QTY. Після команди CALL стек виглядає в так: ... │ 1600 │ D213 │ 4001 │ 0025 │ 0000 │ C213 │ 6 5 4 3 2 1 Ініціалізуюча команда PUSH DS заносить адресу сегменту даних у стек. Ця адреса може відрізнятися в різних версіях DOS. Команда PUSH AX заносить у стек нуль. Команда PUSH PRICE заносить у стек слово даних (2500). Команда PUSH QTY заносить у стек друге слово даних (0140). Команда CALL заносить у стек вміст регістра CS (D213) Оскільки що команда CALL представляє тут міжсегментний виклик, то в стек заноситься також вміст регістра IP(1600). Програма, що викликається використовує регістр BP для доступу до параметрів у стеку, але вона, також, запам'ятовує вміст регістра BP, записуючи його в стек. У даному випадку, припустимо, що регістр BP містить нуль, тоді цей нуль (два байти) буде записано у вершині стеку (ліворуч). Потім програма поміщає в регістр BP вміст із регістра SP, оскільки у якості індексного регістра може використовуватися регістр BP, але не SP. Команда завантажує в регістр BP значення 0072. Спочатку регістр SP містив розмір порожнього стека, тобто комірки 80. Запис кожного слова в стек зменшує вміст SP на 2: │ BP │ IP │ CS │ QTY │ PRICE│ AX │ DS │ │ 0000 │ 1600 │ D213 │ 4001 │ 0025 │ 0000 │C213 │ │ │ │ │ │ │ │ SP: 72 74 76 78 7A 7C 7E Оскільки BP тепер також містить 0072, то параметр ціни (PRICE) буде за адресою BP+8, а параметр кількості (QTY) - за адресою BP+6. Програма пересилає ці величини зі стеку в регістри AX і BX відповідно, і виконує множення. Перед поверненням у вихідну програму в регістрі BP відновлюється початкове значення, а вміст у регістрі SP збільшується на 2, з 72 до 74. Остання команда RET являє собою міжсегментне повернення (“довгий” перехід) у вихідну програму. По цій команді виконуються наступні дії: З вершини стека відновлюється значення регістра IP (1600). Вміст регістра SP збільшується на 2, від 74 до 76. З нової вершини стеку відновлюється значення регістра CS (D213). Вміст регістра SP збільшується на 2 від 76 до 78. У такий спосіб здійснюється коректне повернення у викликаючу програму. Залишилося одне невелике пояснення. Команда RET закодована як RET 4. Параметр 4 являє собою кількість байт у стеку, використаних при передачі параметрів (два слова в даному випадку). Команда RET додасть цей параметр до вмісту регістра SP, одержавши значення 7C. Таким чином, зі стеку вилучаються непотрібні більше параметри. Будьте особливо уважні при відновленні регістра SP - помилки можуть привести до непередбачуваного результату. TITLE CALLMULL ;Головна програма EXTRN SUBMUL:FAR STACKSG SEGMENT PARA STACK 'Stack' DW 64 DUP(?) STACKSG ENDS DATASG SEGMENT PARA 'Data' QTY DW 0140H PRICE DW 2500H DATASG ENDS CODESG SEGMENT PARA PUBLIC 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX PUSH PRICE PUSH QTY CALL SUBMUL ;Викликати підпрограму RET BEGIN ENDP CODESG ENDS END BEGIN ТITLE SUBMUL ;Підпрограма множення CODESG SEGMENT PARA PUBLIC 'CODE' SUBMUL PROC FAR ASSUME CS:CODESG PUBLIC SUBMUL PUSH BP MOV BP,SP MOV AX,[BP+8] ;Вартість MOV BX,[BP+6] ;Кількість MUL BX ;Добуток в DX:AX POP BP RET SUBMUL ENDP CODESG ENDS END SUBMUL ЗАВДАННЯ: Створити *.exe програму, яка реалізовує обчислення, заданого варіантом виразу. Програма повинна складатися з чотирьох модулів: головний модуль – містить спільний сегмент стеку, необхідні дані та виклик основних процедур; модуль вводу - забезпечує ввід даних з клавіатури в десятковій формі; модуль безпосередніх обчислень – здійснює всі необхідні арифметичні дії. модуль виводу – забезпечує вивід на екран результату в десятковій формі. Всі модулі повинні бути в різних файлах і об’єднані на етапі лінкування. Передача параметрів може здійснюватися довільним чином. Переконатися у правильності роботи кожного модуля зокрема та програми загалом. Скласти звіт про виконану роботу з приведенням тексту програми та коментарів до неї. Дати відповідь на контрольні запитання. Мій варіант : 11 X=(A4-B3-K)*D1+E4/F2 311   Код програми : Файл main.asm ;******************************************************************************** ;головний модуль ;тут будуть викликатися усі інші функції ;******************************************************************************** DOSSEG ;оголошення процедур які міститимуться в окремих модулях EXTRN Input :FAR, Calculation :FAR, Output :FAR ;зовнішня змінна-прапорець : використовуватиметься для коректного завершення програми ;при виникненні помилки вона збереже наявність помилки PUBLIC erflag ;****************************************************************************************** ;***********************************ОПИС МАКРОКОМАНД*************************************** ;****************************************************************************************** ;макрокоманда для ініціалізації стеку, та сегментних регістрів INITIAL MACRO csname, dsname, ssname;макрокоманда із формальними параметрами ASSUME cs:csname, ds:dsname, ss:ssname, es:dsname push ds xor ax, ax push ax mov ax, dsname mov ds, ax mov es, ax ENDM ;******************************************************************************** ;опис сегменту стеку ;******************************************************************************** ;стек міститиме адреси поверненя з підпрограм до головної програми ;також через нього передаватимуться параметри ;він використовуватиметься усіма модулями STACKSG SEGMENT PARA STACK 'Stack' DW 127 DUP(0) STACKSG ENDS ;******************************************************************************** ;опис сегменту даних ;******************************************************************************** ;при компонуванні утвориться загальний (спільний) сегмент даних DATASG SEGMENT PARA PUBLIC 'Data' erflag DB 0 ;текстові повідомлення hello_message db '********************************************************************************', 10, 13 db '***************************BEGIN OF THE PROGRAM*********************************', 10, 13 db '********************************************************************************', 10, 13 db 'hrupa : ki-23', 10, 13 db 'student : Dasho', 10, 13 db 'lab-7_var-11', 10, 13, 10 db '--------------------------------------------------------------------------------', 10, 13 db 'X=(A4-B3-K)*D1+E4/F2', 10, 13 db '--------------------------------------------------------------------------------', 10, 13, '$' papa_message db 10, 10, 13 db '********************************************************************************', 10, 13 db '*************************THE END OF THE PROGRAM*********************************', 10, 13 db '********************************************************************************', 10, 13, '$' DATASG ENDS ;******************************************************************************** ;опис сегменту даних ;******************************************************************************** ;при компонуванні утвориться загальний (спільний) сегмент коду CODESG SEGMENT PARA PUBLIC 'Code' main PROC FAR ;мітка, що визначає початок головної процедури ;ініціалізаця стеку та регістра ds INITIAL codesg, datasg, stacksg ;виклик макрокоманди із заданням параметрів call clnscr ;очистити екран та встановити курсор на початок екрану call hello ;вивести на екран текст привітання ;виклик процедури для введення даних CALL Input ;в разі виявлення помилки cmp erflag,0 ;якщо відмінне від 0 то jne exit ;аваріне завершення програми ;виклик процедури для обчислення CALL Calculation ;в разі виявлення помилки cmp erflag,0 ;якщо відмінне від 0 то jne exit ;аваріне завершення програми ;виклик процедури для виведення результату на екран CALL Output ;в разі виявлення помилки cmp erflag,0 ;якщо відмінне від 0 то jne exit ;аваріне завершення програми ;заверешння програми exit: ;мітка, потрібна для завершення програми у разі виникнення помилки call papa ;вивести на екран повідомлення про завершення програми ret main ENDP ;------------------------------------------------------------------- ;вивести на екран привітання---------------------------------------- hello PROC mov ah, 09 lea dx, hello_message int 21h ret hello ENDP ;------------------------------------------------------------------- ;вивести на екран прощання------------------------------------------ papa PROC mov ah, 09 lea dx, papa_message int 21h ret papa ENDP ;------------------------------------------------------------------- ;очистити екран та встановити курсор на початок екрану-------------- clnscr PROC ;процедура ближньої адресації для очистки екрану mov ax, 0600h ;ah 06 - прокрутка ; al 00 - весь екран mov bh, 07 ;нормальний атрибут (чорно/білий) mov cx, 0000 ;верхня ліва позиція mov dx, 184fh ;нижня права позиція int 10h ;передача управління в BIOS ;встановлення курсору на початку екрану mov ah, 02 ;запит на встановлення курсору на екрані, не залежить чи є на ньому вже якісь символи, вони ігноруються mov bh, 00 ;номер екрану mov dx, 0200h ;встановлення курсору : 2 рядок, 10 стовбець int 10h ;переривання програми для передачі керування в BIOS ret ;завершення процедури clnscr ENDP ;завершення опису коду процедуриs CODESG ENDS ;завершення опису сегмента коду END main ;вказівка на головну процедуру Файл input.asm DOSSEG ;глобальна змінна EXTRN erFlag:BYTE ;змінні, які доступні в цьому файлі PUBLIC A, B, D, E, F ;************************************************************ ;опис спільного сегменту даних у модулі input DATASG SEGMENT PARA PUBLIC 'Data' ;список параметрів, потрібних для введення числа із клавіатури variable label byte ;імя списку параметрів max_len db 10 ;максимальна кількість цифр числа (символів ASCII) real_len db ? ;реальне число введених символів tmp_var db 10 dup(?) ;тимчасова змінна для зберігання числа в ASCII форматі ;тимчасова змінна для зберігання вже переведеного до 16 системи введеного числа tmp db 4 dup(?) ;масимальна розмірність змінної - 4 байти ;--------------------------------------------------------------------------------------- ;змінні, потрібні для обчислень : ------------------------------------------------------ A dw ?, ? B dw ?, ? D db ? E dw ?, ? F dw ? ;--------------------------------------------------------------------------------------- ;текстові повідомлення mes_vvid_A db 10, 13, 'Vvid A : ' , '$' mes_vvid_B db 10, 13, 'Vvid B : ' , '$' mes_vvid_C db 10, 13, 'Vvid C : ' , '$' mes_vvid_D db 10, 13, 'Vvid D : ' , '$' mes_vvid_E db 10, 13, 'Vvid E : ' , '$' mes_vvid_F db 10, 13, 'Vvid F : ' , '$' message_erorr_data db 10, 13, '!!!_vy vvely nekorektni dani _!!!', 10, 13, '$' DATASG ENDS ;************************************************************ ;опис спільного сегменту коду у модулі input CODESG SEGMENT PARA PUBLIC 'CODE' ASSUME DS:DATASG, CS:CODESG ;------------------------------------------------------------------- ;процедура для вводу змінних---------------------------------------- input proc FAR public Input ;збереження вмістимого регістрів push ax push dx ;****************** ;введення A (4) mov ah, 09 ;9 функція для виводу lea dx, mes_vvid_A ;адреса виводимого тексту int 21h ;переривання для виводу на екран ;----------------- mov max_len, 10 ;задання максимальної кількості вводимих цифер call input_var ;виклик для введення числа call ASCII_to_16 ;переведення до машинного вигляду числа mov ax, word ptr [tmp] mov A, ax mov ax, word ptr [tmp+2] mov A+2, ax ;****************** ;введення B (4) mov ah, 09 lea dx, mes_vvid_B int 21h ;----------------- mov max_len, 10 call input_var call ASCII_to_16 mov ax, word ptr [tmp] mov B, ax mov ax, word ptr [tmp+2] mov B+2, ax ;****************** ;введення D (1) mov ah, 09 lea dx, mes_vvid_D int 21h ;----------------- mov max_len, 2 call input_var call ASCII_to_16 mov al, byte ptr [tmp] mov D, al ;******************** ;введення E (4) mov ah, 09 lea dx, mes_vvid_E int 21h ;----------------- mov max_len, 10 call input_var call ASCII_to_16 mov ax, word ptr [tmp] mov E, ax mov ax, word ptr [tmp+2] mov E+2, ax ;********************* ;введення F (2) mov ah, 09 lea dx, mes_vvid_F int 21h ;----------------- mov max_len, 5 call input_var call ASCII_to_16 mov ax, word ptr [tmp] mov F, ax ;відновлення вмістимого регістрів pop dx pop ax ret input ENDP ;------------------------------------------------------------------- ;ввід числа із клавіатури------------------------------------------- ;в разі некоректних вхідних даних спроба вводу повториться---------- input_var PROC near ;процедура ближньої адресації для введення тексту(числа) із клавіатури ;збереження вмістимого регістрів push ax push dx push bx push cx vvid: mov ah, 0ah ;функція для вводу тексту(числа) з клавіатури lea dx, variable ;сюди буде записуватися текст(число в ASCII форматі), введений із клавіатури int 21h ;виклик 21 переривання DOS ;перевірка на коректність вхідних даних xor cx, cx mov cl, real_len mov bx, cx dec bx perevirka: mov al, tmp_var[bx] cmp al, 39h ;якщо символ поза межами ja erorr ;ASCII-кодів цифер cmp al, 30h ;то здійснюється повтор jb erorr ;вхідного числа jmp dali erorr: mov ah, 09 ;вивід на екран lea dx, message_erorr_data ;повідомлення для введення некоректних даних int 21h jmp vvid dali: dec bx ;перехід на старший розряд loop perevirka ;продовження циклу перевірки на коректність вхідних даних ;відновлення вмістимого регістрів pop cx pop bx pop dx pop ax ret ;завершення процедури input_var ENDP ;завершення опису коду процедури ;------------------------------------------------------------------- ;переведення символів з ASCII форматом до єдиного числа у 16 системі ;процедура завжди даватиме 4-байтне число--------------------------- ;але якщо буде число 2-бйтне, то старші байти будуть рівні 0-------- ASCII_to_16 PROC near ;процедура для переведення до 16 системи числення ;збереження вмістимого регістрів push ax push dx push bx push cx ;------------------------------ xor cx, cx ;обнулення cx mov cl, real_len ;кількість 10-ових цифр mov bx, cx ;потрібно для адресації dec bx ;байтів введеного числа у зворотньому порядку mov dl, 1h ;множник основи mov dh, 10d ;число на яке буде збільшуватися множник основи mov tmp, 0 ;тут запишеться число mov tmp+1, 0 mov tmp+2, 0 mov tmp+3, 0 loop10: ;цикл для переведення поточного розряду до 16 системи xor ax, ax ;обнулення регістра ax clc ;очищення прапорця CF mov al, tmp_var[bx] ;запис поточного байта and al, 0Fh ;переведення символів ASCII до цифер із діапазону від 0 до 9 mul dl ;множення на основу add tmp, al ;нарахування суми результуючого числа adc tmp+1, ah ;нарахування суми із врахуванням переносу до старшого байта adc tmp+2, 0 ;врахування переносу до старшого байта adc tmp+3, 0 ;врахування переносу до старшого байта mov al, dl ;збільшення множника -> mul dh ;основи дл наступного -> mov dl, al ;старшого розряду dec bx ;перехід на молодший байт введеного числа для доступу до старшого розряду loop loop10 ;продовжити поки не цикл не пройдеться по всіх розрядах введеного числа ;відновлення вмістимого регістрів pop cx pop bx pop dx pop ax ret ;завершення процедури ASCII_to_16 ENDP ;завершення опису коду процедури CODESG ENDS END Файл calc.asm DOSSEG ;глобальна змінна EXTRN A:dword, B:dword, D:word, E:dword, F:word, erflag:byte PUBLIC X ;************************************************************ ;опис спільного сегменту даних у модулі calc DATASG SEGMENT PARA PUBLIC 'Data' k_low equ 0311h k_high equ 0000h ;тимчасові змінні, потрібні для зберігання поточних значень обрахунків------------------ tmp1 dw ?, ? tmp2 dw ?, ? tmp3 dw ?, ? tmp4 dw ?, ? ;--------------------------------------------------------------------------------------- ;змінна для кінцевого результату обчислень---------------------------------------------- X dw ? error_data_div db 10, 13 db '!!!_INCORECTLY_DATA_!!!', 10, 13 db 'DIVIDE BY ZERO_!!!', 10, 13, '$' error_data_sub db 10, 13 db '!!!_INCORECTLY_DATA_!!!', 10, 13 db 'result must be unsigned_!!!', 10, 13, '$' error_divisor db 10, 13 db 'DIVISOR IS TO SMALL', 10, 13 db 'DIVIDE OVERFLOW_!!!', 10, 13, '$' DATASG ENDS ;************************************************************ ;опис спільного сегменту коду у модулі calc CODESG SEGMENT PARA PUBLIC 'CODE' ASSUME DS:DATASG, CS:CODESG MOV AX,DATASG MOV DS,AX ;------------------------------------------------------------------- ;процедура, яка проводитиме оючислення------------------------------ calculation PROC FAR public calculation ;збереження вмістимого регістрів push ax push dx push bx push cx ;******************************************************* ;ОБЧИСЛЕННЯ ВИРАЗУ ;X=(A4-B3-K)*D1+E4/F2 ;------------------------------------------------------- ;A4-B3(4)->tmp1(4) mov ax, word ptr A mov dx, word ptr A+2 mov bx, word ptr B mov cx, word ptr B+2 cmp ax, bx ja @@step1 mov ah, 09h lea dx, error_data_sub int 21h mov erflag, 1 jmp @@exit @@step1: sub ax, bx sbb dx, cx mov tmp1, ax mov tmp1+2, dx ;-------------------------------------------------------- ;tmp1(4)-K->tmp2(4) mov ax, tmp1 mov dx, tmp1+2 cmp ax, k_low ja @@step2 mov ah, 09h lea dx, error_data_sub int 21h mov erflag, 1 jmp @@exit @@step2: sub ax, k_low sbb dx, 0 mov tmp2, ax mov tmp2+2, dx ;----------------------------------------------------------- ;tmp2*D1->tmp3(4) mov ax, tmp2 mov dx, tmp2+2 mov bl, byte ptr D xor bh, bh mul bx mov tmp3, ax mov tmp3+2, dx ;----------------------------------------------------------- ;E4/F2->tmp4(2) mov ax, word ptr E mov dx, word ptr E+2 mov bx, F cmp bx, 0 jne @@step4_p mov ah, 09h lea dx, error_data_div int 21h mov erflag, 1 jmp @@exit @@step4_p: cmp dx, bx jb @@step4_div mov ah, 09h lea dx, error_divisor int 21h mov erflag, 1 jmp @@exit @@step4_div: div bx mov tmp4, ax ;------------------------------------------------------------ ;tmp3(4)+tmp4(2)->X(4) clc mov ax, tmp3 mov dx, tmp3+2 mov bx, tmp4 add ax, bx adc dx, 0 mov X, ax mov X+2, dx @@exit: ;вихід із процедури ;відновлення вмістимого регістрів pop cx pop bx pop dx pop ax ret calculation ENDP CODESG ENDS END Файл output.asm DOSSEG ;глобальна змінна EXTRN X:WORD ;************************************************************ ;опис спільного сегменту даних у модулі calc DATASG SEGMENT PARA PUBLIC 'Data' message_output db 10, 13 db '--------------------------------------------------------------------------------', 10, 13 db '!!!_obchyslennia vykonano_!!!', 10, 13 db '--------------------------------------------------------------------------------', 10, 13 db 'Result is : X = ', '$' mes_out_x db 10 dup (' '), '$' ;змінна для зберігання результату обчислення в ASCII форматі DATASG ENDS ;************************************************************ ;опис спільного сегменту коду у модулі calc CODESG SEGMENT PARA PUBLIC 'CODE' ASSUME DS:DATASG, CS:CODESG MOV AX,DATASG MOV DS,AX ;------------------------------------------------------------------- ;вивести на екран результат обчислень------------------------------- output PROC FAR public output ;збереження вмістимого регістрів push ax push dx push bx push cx ;виведення на екран mov ah, 09 lea dx, message_output int 21h call r16_to_ASCII mov ah, 09 lea dx, mes_out_x int 21h ;відновлення вмістимого регістрів pop cx pop bx pop dx pop ax ret output ENDP ;------------------------------------------------------------------- ;здійснити перетворення з 16 формату до ASCII----------------------- r16_to_ASCII PROC near mov ax, word ptr X mov bx, 10d xor si, si loop30: cmp ax, 10d jb dali1 xor dx, dx div bx mov mes_out_x[si], dl add mes_out_x[si], 30h inc si jmp loop30 dali1: mov mes_out_x[si], al add mes_out_x[si], 30h ;дзеркально обертаємо результат обчислень для виведення на екран mov ax, si ;кількість значущих байт для виведення xor di, di mov dl, 2 div dl ;проходити потрібно лише до середини mov cl, al xor ch, ch loop40: mov al, mes_out_x[di] ;беремо з початку повідомлення байт mov bl, mes_out_x[si] ;беремо з кінця повідомлення байт mov mes_out_x[di], bl ;заносимо з кінця в початок mov mes_out_x[si], al ;заносимо в кінець з початку dec si ;для руху з кінця до середини inc di ;для руху з початку до середини cmp cx, 0 jb loop40 ret r16_to_ASCII ENDP CODESG ENDS END Скрін програми : / / Висновок : На даній лабораторній роботі я оволодів навиками створення багатомодульних програм та засвоїв правила взаємодії різних модулів.
Антиботан аватар за замовчуванням

18.03.2015 01:03-

Коментарі

Ви не можете залишити коментар. Для цього, будь ласка, увійдіть або зареєструйтесь.

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!