Заданий вираз:
X=A2*B1+C4/(K-E1*F1) K=10974759
Згідно з завданням, в кодовому сегменті повинен бути виклик трьох процедур та їх опис. Відповідно, структура програми буде мати такий вигляд.
DOSSEG
.MODEL SMALL
; опис макросів
.STACK 100h
.DATA
; опис необхідних даних
.CODE
mov ax,@data
mov ds,ax
call INPUT
call CALCULATION
call OUTPUT
INPUT proc
;тіло процедури вводу
ret
INPUT endp
CALCULATION proc
;тіло процедури обчислень
ret
CALCULATION endp
OUTPUT proc
;тіло процедури виводу результатів
ret
OUTPUT endp
mov ah,4Ch
int 21h
END
Програма, що обраховує даний вираз була приведена в лабораторній роботі №3. Згідно з нею, вхідні дані повинні знаходитися в пам’яті за адресами від В до F, а результат – за міткою Х. Тепер, слід оформити цю програму у вигляді процедури та написати відповідні підпрограми, щоб забезпечити коректний ввід в десятковій формі, перевід в шістнадцяткову систему та зворотнє перетворення і вивід результату на екран.
Підпрограма вводу. – INPUT, обчислень – CALCULATION, виводу – OUTPUT.
Розглянемо можливості вводу даних. Це можна зробити двома способами:
1) для кожної змінної посимвольно вводити кожну цифру. В цьому випадку буде використовуватися функція 01h переривання 21h (оскільки функція 07h переривання 21h та функція 00 переривання 16h не забезпечують еховідображення, то їх використовувати в даному випадку недоцільно). В сегменті даних слід передбачити місце для зберігання введених символів. При чому, розмір відведеної пам’яті повинен дозволяти ввід змінної максимального розміру. В даному випадку змінна максимальний розмір має змінна С – 2 байт, тобто вона складається з 5 десяткових символів. Отже розмір тимчасової пам’яті для зберігання введених символів становить 5 байт. Значення в цьому місці пам’яті буде оновлюватися для кожної змінної.
2) вводити для кожної змінної рядок символів. В цьому випадку можна використати функцію 0Аh або 3Fh переривання 21h. При цьому у сегменті даних вимагається область вводу для кожної змінної, що значно збільшує об’єм коду і зрозумілість програми.
Оскільки ввід даних для кожної змінної буде відбуватися однаково, то варто написати процедуру вводу, яка буде викликатися 4 рази, вводячи кожен раз різну кількість символів і записуючи результат вводу, переведений в 10-ий формат, в іншу область пам’яті (процедура input_variable). Процес перевірки одного введеного символу на приналежність до 10-ої системи числення теж опишемо як окрему процедуру (процедура CHECK_BYTE). Крім того, слід передбачити перевірки на коректність діапазону введених чисел (наприклад процедура Err1).
При переводі в десяткову систему, використовується макрокоманда множення MY_MUL , яка дозволяє сформувати черговий множник, тобто степінь числа 10, та власне саме множення на нього.
Процедура обчислень нічим не відрізняється від програми з лабораторної роботи №4.
Тепер слід вивести результат, отриманий після обчислень, на екран в десятковому форматі. При формуванні десяткового результату слід проводити ділення на основу числення – 10 результату Х, який займає 4 байти. Для коректного ділення призначена підпрограма MY_DIV2.
Безпосередній вивід утвореного числа здійснити двома способами:
1) посимвольно виводити кожну цифру. В цьому випадку буде використовуватися функція 02h або 06h переривання 21h і жодних змін в сегмент даних вносити не треба.
2) утворити рядок символів і вивести результат повністю. В цьому випадку можна використати функцію 09h або 40h переривання 21h, які потребують у сегменті даних області виводу (тобто місця під майбутній рядок символів).
Згідно алгоритму перетворення, програма буде містити цикл, кількість повторів якого залежить від розміру результату (в байтах). В даному випадку цей розмір становить 4 байти. Зчитування даних повинно відбуватися послідовно по одному байту починаючи зі старшого. Оскільки змінна результату оголошена як слово, то щоб звернутися окремо до кожного байту слід використати директиву BYTE PTR та відносну адресацію через регістр [SI], значення в якому буде на одиницю відставати від лічильника циклу в регістрі CX.
Альтернативним варіантом виводу результату на екран є формування символьного рядка в пам’яті і вивід його за допомогою функції 09h переривання 21h. При цьому, в сегменті даних резервуємо місце під рядок символів довжиною 10 байт (4 байти результату це 10 символів), заповнюючи його пробілами , та додаємо ознаку завершення рядка – ‘$’. При записі чергового символу в пам’ять необхідно збільшувати лічильник символів, який адресує область виводу і знаходиться в регістрі [DI].
Нижче приведено текст програми, що реалізовує завдання.
X=A2*B1+C4/(K-E1*F1) K=10974759
.MODEL SMALL
MY_MUL MACRO X,Y,Z
mov z,0
mov z+2,0
MOV AX,X
MUL Y
MOV Z,AX
MOV Z+2,DX
MOV AX,X+2
MUL Y
ADD Z+2,AX
mov ax,Z
mov dx,Z+2
ENDM
.STACK 100h
.DATA
K_low EQU 7627h
K_high EQU 00A7h
A dw 2h ;=2
B db 1h ;=1
C dd B71B00h ;=12000000
E db 14h ;=20
F db 3Ch ;=60
Temp1 dw 00h,00h
Temp2 dw 0000h
Temp3 dw 00h,00h
Temp4 dw 00h,00h
X dw 00h,00h
X_Str db 10 dup (0)
TempStr db 10 dup (0)
TempBin dw 0,0
MaxLen dw 0
X_div2 dw 0,0
Y_div2 dw 0
MESSG_X DB 13,10,'X=A2*B1+C4/(K-E1*F1) K=10974759 (A77627h)','$'
MESSG_A DB 13,10,'A= ','$'
MESSG_B DB 13,10,'B= ','$'
MESSG_C DB 13,10,'C= ','$'
MESSG_E DB 13,10,'E= ','$'
MESSG_F DB 13,10,'F= ','$'
MESSG_X1 DB 13,10,'X= ','$'
erStr1 db 13,10,'Data not input_variable',13,10,'$'
erStr2 db 13,10,'Incorrectly data ',13,10,'$'
erStr2_1 db 13,10,' D =0 --> divide by zero ',13,10,'$'
erStr3 db 13,10,'Data is too long ',13,10,'$'
Mult10 dw 1,0
my_z dw 0,0
.CODE
mov ax,@data
mov ds,ax
call input
call calculation
call output
mov ah,01
int 21h
mov ah,4Ch
int 21h
input proc
LEA DX,MESSG_X
MOV AH,09
INT 21H
LEA DX,MESSG_A
MOV AH,09
INT 21H
mov di,offset A
mov MaxLen,5
mov cx,MaxLen
call input_variable
LEA DX,MESSG_B
MOV AH,09
INT 21H
mov di,offset B
mov MaxLen,3
mov cx,MaxLen
call input_variable
LEA DX,MESSG_C
MOV AH,09
INT 21H
mov di,offset C
mov MaxLen,10
mov cx,MaxLen
call input_variable
cmp C,0
jne dali
mov ah,09
mov dx, offset erStr2_1
int 21h
mov ah,4Ch
int 21h
dali: LEA DX,MESSG_E
MOV AH,09
INT 21H
mov di,offset E
mov MaxLen,3
mov cx,MaxLen
call input_variable
LEA DX,MESSG_F
MOV AH,09
INT 21H
mov di,offset F
mov MaxLen,3
mov cx,MaxLen
call input_variable
ret
input endp
calculation proc
xor ax,ax
xor bx,bx
xor cx,cx
xor dx,dx
mov ax,0
mov al,B
mul A
mov Temp1,ax;=0002
mov Temp1+2,dx;=0000
mov ax,0
mov al,E
mul F
mov Temp2,ax ;=4B0
mov dx,K_high
mov ax,K_low
mov bx,Temp2
sub ax,bx
sbb dx,0
mov Temp3,ax;=7177
mov Temp3+2,dx;=00A7
mov ax,word ptr[C]
mov dx,word ptr[C+2]
div Temp3
mov Temp4,ax
mov dx,0
mov ax,Temp4
add Temp1,ax
adc Temp1+2,0
mov X,ax
mov X+2,dx
ret
calculation endp
input_variable PROC
mov si,0
In_00: mov ah,01
int 21h
cmp al,0Dh
je In_1
In_0: mov dl,al
call CHECK_BYTE
mov TempStr[si],dl
inc si
loop In_00
In_1: push si
dec si
cmp cx,MaxLen
jne In_2
call Err1
In_2: mov bh,0
mov bl,TempStr[si]
MY_MUL Mult10,bx,my_z
add TempBin,ax
adc TempBin+2,dx
mov bh,0
mov bl,10
MY_MUL Mult10,bx,my_z
mov Mult10,ax
mov Mult10+2,dx
dec si
cmp si,0
jge In_2
mov ax, TempBin
mov dx,TempBin+2
pop si
cmp si,MaxLen
jl In_3
cmp MaxLen,10
jl In_2_1
js In_Err
cmp dx,0FFFFh
ja In_Err
jmp In_3
In_2_1: cmp MaxLen,5
jl In_2_2
cmp dx,00
ja In_Err
cmp ah,0ffh
ja In_Err
jmp In_3
In_2_2: cmp ax,00FFh
jbe In_3
In_Err: LEA DX,erSTR3
MOV AH,09
INT 21H
mov ah,4Ch
int 21h
In_3: mov [di],ax
mov [di+2],dx
mov TempBin,0
mov TempBin+2,0
mov Mult10,1
mov Mult10+2,0
RET
input_variable ENDP
Err1 PROC
LEA DX,erSTR1
MOV AH,09
INT 21H
mov ah,4Ch
int 21h
RET
Err1 ENDP
CHECK_BYTE PROC
sub dl,30h
cmp dl,00
jl ErS
cmp dl,0Ah
jl GO
ErS: LEA DX,erSTR2
MOV AH,09
INT 21H
mov ah,4Ch
int 21h
GO: RET
CHECK_BYTE ENDP
MY_DIV2 proc
sub cx,cx
sub bx,bx
mov dx,X_div2+2
mov ax,X_div2
M2_D1:
cmp dx,Y_div2
jb M2_D3
sub ax,Y_div2
sbb dx,00
add cx,01
adc bx,0
jmp M2_D1
M2_D3:
div Y_div2
add cx,ax
adc bx,00
ret
MY_DIV2 ENDP
output PROC
mov di,0
mov Y_div2,10
mov cx,X
mov bx,X+2
O_1: mov X_div2,cx
mov X_div2+2,bx
call my_div2
add dl,30h
mov X_Str[di],dl
inc di
cmp bx,0
ja O_1
cmp cx,10
jae O_1
add cl,30h
mov X_Str[di],cl
mov dx,offset MESSG_X1
mov ah,09
int 21h
O_2:
mov dl,X_Str[di]
mov ah,02h
int 21h
dec di
jge O_2
ret
output ENDP
end