Цель: ознакомиться с командами арифметических операций, вводом данных с клавиатуры и выводом данных на экран.
Задание: написать программу ввода с клавиатуры двух чисел в 9-ричной системе счисления размером с слово, выполнения над ними деления и вывода результата в исходной системе счисления. Программа должна предусматривать контроль вводимой информации, контроль диапазона чисел и результата операции (переполнение, невозможность деления).
Программа:
;-----------ЛАБОРАТОРНАЯ РАБОТА №3
.MODEL SMALL
.STACK 100H
.186
.DATA
S1 DB 'ВВЕДИТЕ ДЕЛИМОЕ В ДЕВЯТИРИЧНОЙ СИСТЕМЕ'
DB ' СЧИСЛЕНИЯ (ОТ -48848 ДО 1О8806): ',10,13,'$'
S2 DB 'ВВЕДИТЕ ДЕЛИТЕЛЬ В ДЕВЯТИРИЧНОЙ СИСТЕМЕ'
DB ' СЧИСЛЕНИЯ (ОТ -48848 ДО 1О8806): ',10,13,'$'
S3 DB 'НЕВЕРНАЯ ЗАПИСЬ ЧИСЛА В ДЕВЯТИРИЧНОЙ'
DB ' СИСТЕМЕ СЧИСЛЕНИЯ ИЗ ЗАДАННОГО ДИАПАЗОНА.','$'
S4 DB 'ДЕЛЕНИЕ НЕВОЗМОЖНО: ДЕЛИТЕЛЬ РАВЕН НУЛЮ.','$'
S5 DB 'ДЕЛЕНИЕ НЕВОЗМОЖНО: ДЕЛИТЕЛЬ БОЛЬШЕ ДЕЛИМОГО.','$'
S6 DB 'ОСТАТОК: ',10,13,'$'
S7 DB 'ЧАСТНОЕ: ',10,13,'$'
L DB '48848' ;МИНИМАЛЬНОЕ ЧИСЛО
H DB '108806' ;МАКСИМАЛЬНОЕ ЧИСЛО
SX DB 12 DUP('x') ;ДЕЛИМОЕ
SY DB 12 DUP('y') ;ДЕЛИТЕЛЬ
SZ DB 8 DUP('0'),'$' ;ЧАСТНОЕ
.CODE
BEGIN: MOV AX, @DATA
MOV DS, AX
;-----------ОЧИСТКА БУФЕРА КЛАВИАТУРЫ
START: CLI ;ЗАПРЕТ ПРЕРЫВАНИЙ
SUB AX, AX
MOV ES, AX
MOV AL, ES:[41AH]
MOV ES:[41CH], AL
STI ;РАЗРЕШЕНИЕ ПРЕРЫВАНИЙ
;-----------ОЧИСТКА ЭКРАНА
CLD
MOV AX, 0B800H
MOV ES, AX
MOV DI, 0
MOV AL, 32
MOV AH, 7
MOV CX, 2000
REP STOSW
;-----------УСТАНОВКА КУРСОРА В ЛЕВЫЙ ВЕРХНИЙ УГОЛ ЭКРАНА
MOV AH, 2 ;НОМЕР ФУНКЦИИ
MOV BH, 0 ;НОМЕР СТРАНИЦЫ
MOV DH, 0 ;СТРОКА
MOV DL, 0 ;СТОЛБЕЦ
INT 10H ;ПОЗИЦИОНИРОВАНИЕ КУРСОРА
;-----------ВЫВОД ПРИГЛАШЕНИЯ ВВОДА ДЕЛИМОГО
LEA DX, S1
MOV AH, 9
INT 21H
;-----------ВВОД ДЕЛИМОГО
LEA DX, SX
MOV BX, DX
MOV [BX], BYTE PTR 9 ;ПРЕДПОЛАГАЕМАЯ ДЛИНА СТРОКИ
MOV AH, 0AH
INT 21H
;-----------УСТАНОВКА КУРСОРА
MOV AH, 2 ;НОМЕР ФУНКЦИИ
MOV BH, 0 ;НОМЕР СТРАНИЦЫ
MOV DH, 2 ;СТРОКА
MOV DL, 0 ;СТОЛБЕЦ
INT 10H ;ПОЗИЦИОНИРОВАНИЕ КУРСОРА
;-----------ПРОВЕРКА ПРАВИЛЬНОСТИ ВВОДА ДЕЛИМОГО
LEA DX, SX
MOV BX, DX
CALL CONTROL ;ПРОВЕРКА ПРАВИЛЬНОСТИ ВВОДА
MOV AL, [BX]
CMP AL, '0'
JE ZERO1 ;ЧИСЛО ВВЕДЕНО НЕВЕРНО
JMP NEAR PTR DELITEL
ZERO1: LEA DX, S3
MOV AH, 9
INT 21H
;===========ОЖИДАНИЕ НАЖАТИЯ КЛАВИШИ
MOV AH, 7
INT 21H
JMP NEAR PTR START
;-----------ВЫВОД ПРИГЛАШЕНИЯ ВВОДА ДЕЛИТЕЛЯ
DELITEL: LEA DX, S2
MOV AH, 9
INT 21H
;-----------ВВОД ДЕЛИТЕЛЯ
INPUT: LEA DX, SY
MOV BX, DX
MOV [BX], BYTE PTR 9 ;ПРЕДПОЛАГАЕМАЯ ДЛИНА СТРОКИ
MOV AH, 0AH
INT 21H
;-----------УСТАНОВКА КУРСОРА
MOV AH, 2 ;НОМЕР ФУНКЦИИ
MOV BH, 0 ;НОМЕР СТРАНИЦЫ
MOV DH, 4 ;СТРОКА
MOV DL, 0 ;СТОЛБЕЦ
INT 10H ;ПОЗИЦИОНИРОВАНИЕ КУРСОРА
;-----------ПРОВЕРКА ПРАВИЛЬНОСТИ ВВОДА ДЕЛИТЕЛЯ
LEA DX, SY
MOV BX, DX
CALL CONTROL ;ПРОВЕРКА ПРАВИЛЬНОСТИ ВВОДА
CMP [BX], BYTE PTR '0'
JE ZERO2 ;ЧИСЛО ВВЕДЕНО НЕВЕРНО
JMP NEAR PTR OK
ZERO2: LEA DX, S3
MOV AH, 9
INT 21H
;===========ОЖИДАНИЕ НАЖАТИЯ КЛАВИШИ
MOV AH, 7
INT 21H
;-----------ОЧИСТКА БУФЕРА КЛАВИАТУРЫ
CLI
SUB AX, AX
MOV ES, AX
MOV AL, ES:[41AH]
MOV ES:[41CH], AL
STI
;-----------ОЧИСТКА ЭКРАНА
CLD
MOV AX, 0B800H
MOV ES, AX
MOV DI, 480
MOV AL, 32
MOV AH, 7
MOV CX, 480
REP STOSW
;-----------УСТАНОВКА КУРСОРА
MOV AH, 2 ;НОМЕР ФУНКЦИИ
MOV BH, 0 ;НОМЕР СТРАНИЦЫ
MOV DH, 3 ;СТРОКА
MOV DL, 0 ;СТОЛБЕЦ
INT 10H ;ПОЗИЦИОНИРОВАНИЕ КУРСОРА
JMP NEAR PTR INPUT
;-----------УСТАНОВКА КУРСОРА
OK: MOV AH, 2 ;НОМЕР ФУНКЦИИ
MOV BH, 0 ;НОМЕР СТРАНИЦЫ
MOV DH, 4 ;СТРОКА
MOV DL, 0 ;СТОЛБЕЦ
INT 10H ;ПОЗИЦИОНИРОВАНИЕ КУРСОРА
;-----------ПРОВЕРКА ВОЗМОЖНОСТИ ДЕЛЕНИЯ
LEA BX, SX
CALL CTRL0
MOV AH, [BX]
LEA BX, SY
CALL CTRL0
MOV AL, [BX]
CMP AL, '0'
JE NULL
JMP N_NULL
;-----------ДЕЛИТЕЛЬ РАВЕН НУЛЮ
NULL: LEA DX, S4
MOV AH, 9
INT 21H
JMP NEAR PTR ENDPROG
;-----------ДЕЛИТЕЛЬ НЕ РАВЕН НУЛЮ
N_NULL: CMP AH, '0'
JNE DELENIE
;-----------ДЕЛИМОЕ РАВНО НУЛЮ
LEA DX, S7
MOV AH, 9
INT 21H
LEA BX, SZ
MOV [BX], BYTE PTR '0'
INC BX
MOV [BX], BYTE PTR 10
INC BX
MOV [BX], BYTE PTR 13
INC BX
MOV [BX], BYTE PTR '$'
LEA DX, SZ
MOV AH, 9
INT 21H
LEA DX, S6
MOV AH, 9
INT 21H
LEA DX, SZ
MOV AH, 9
INT 21H
JMP NEAR PTR ENDPROG
;-----------ДЕЛИМОЕ И ДЕЛИТЕЛЬ НЕ РАВНЫ НУЛЮ
DELENIE: LEA SI, SX
LEA DI, SY
CALL COMPARE
CMP [SI], BYTE PTR 1
JE POSSIBLE
;-----------ДЕЛИТЕЛЬ БОЛЬШЕ ДЕЛИМОГО
LEA DX, S5
MOV AH, 9
INT 21H
JMP NEAR PTR ENDPROG
;-----------НАЧИНАЕТСЯ ДЕЛЕНИЕ
POSSIBLE: MOV BX, 7 ;BX - ИНДЕКС ДЛЯ ЧАСТНОГО
;-----------В СХ - ЧИСЛО РАЗРЯДОВ ДЕЛИТЕЛЯ
AGAIN: MOV CL, SY[1] ;CX - ЧИСЛО РАЗРАДОВ ДЕЛИТЕЛЯ
MOV CH, 0
;-----------DI - НА МЛАДШИЙ РАЗРЯД ДЕЛИТЕЛЯ
MOV DI, CX ;DI - ИНДЕКС ДЛЯ ДЕЛИТЕЛЯ
INC DI
;-----------УДАЛЕНИЕ ВЕДУЩИХ НУЛЕЙ ДЕЛИТЕЛЯ
MOV SI, 2 ;SI - ИНДЕКС ДЛЯ ДЕЛИМОГО
MOV AL, SY[SI]
CMP AL, '-'
JNE BEFORE_C1
INC SI
DEC CX
BEFORE_C1: MOV AL, SY[SI]
CMP AL, '0'
JE SS1
JMP LBLL
SS1: INC SI
DEC CX
JMP BEFORE_C1
;-----------SI - НА МЛАДШИЙ РАЗРЯД ДЕЛИМОГО
LBLL: MOV AL, SX[1]
CBW ;АН - ДЛЯ ЗАПИСИ ПЕРЕНОСА
MOV SI, AX
INC SI
;-----------НАЧАЛО ЦИКЛА ДЕЛЕНИЯ
;===========СРАВНЕНИЕ ЦИФР РАЗРЯДА ДЕЛИМОГО И ДЕЛИТЕЛЯ
C1: MOV AL, SX[SI]
CMP AL, SY[DI]
JAE NEXT
;===========ЦИФРА ДЕЛИМОГО МЕНЬШЕ ЦИФРЫ ДЕЛИТЕЛЯ
ADD AL, 9 ;ЗАЁМ ЕДИНИЦЫ
SUB AL, SY[DI] ;ВЫЧИТАНИЕ
ADD AL, '0' ;ПЕРЕВОД ЦИФРЫ В ЕЕ КОД
SUB AL, AH ;ВЫЧИТАНИЕ ПЕРЕНОСА
MOV SX[SI], AL ;РЕЗУЛЬТАТ - НА МЕСТО РАЗРЯДА ДЕЛИМОГО
MOV AH, 1 ;ЗАПИСЬ ЗАЁМА
JMP NEAR PTR DECREM ;НА КОНЕЦ ЦИКЛА
;===========ЦИФРА ДЕЛИМОГО БОЛЬШЕ ЦИФРЫ ДЕЛИТЕЛЯ
NEXT: SUB AL, SY[DI] ;ВЫЧИТАНИЕ
SUB AL, AH ;ВЫЧИТАНИЕ ПЕРЕНОСА
MOV AH, 0 ;ЗАЁМА НЕТ
ADD AL, '0' ;ПЕРЕВОД ЦИФРЫ В ЕЕ КОД
MOV SX[SI], AL ;РЕЗУЛЬТАТ - НА МЕСТО РАЗРЯДА ДЕЛИМОГО
;-----------SI, DI - НА БОЛЕЕ СТАРШИЙ РАЗРЯД
DECREM: DEC SI
DEC DI
LOOP C1 ;НА НАЧАЛО ЦИКЛА ДЕЛЕНИЯ
;-----------БЫЛ ЛИ ЗАЁМ ИЛИ НЕТ
CMP AH, 1
JNE SRAVN
;-----------ЗАЁМ БЫЛ
AGAIN1: CMP SX[SI], '0' ;СРАВНЕНИЕ ЦИФРЫ РАЗРЯДА С НУЛЁМ
JE C2
DEC SX[SI]
JMP SRAVN
;-----------ЦИФРА РАЗРЯДА ДЕЛИТЕЛЯ РАВНА НУЛЮ
C2: MOV SX[SI], '8'
DEC SI ;НА БОЛЕЕ СТАРШИЙ РАЗРЯД
JMP AGAIN1 ;НА СРАВНЕНИЕ ЦИФРЫ РАЗРЯДА С НУЛЁМ
;===========ФОРМИРОВАНИЕ ЧАСТНОГО
;-----------ЕСТЬ ЛИ ПЕРЕНОС ПРИ УВЕЛИЧЕНИИ ЧАСТНОГО НА ЕДИНИЦУ
SRAVN: CMP SZ[BX], '8'
JE PERENOS
;-----------ПЕРЕНОСА НЕТ
ADD SZ[BX], 1 ;УВЕЛИЧЕНИЕ ЧАСТНОГО НА ЕДИНИЦУ
MOV BX, 7 ;ВХ - НА МЛАДШИЙ РАЗРЯД
JMP DEL ;НА СРАВНЕНИЕ ДЕЛИМОГО И ДЕЛИТЕЛЯ
;-----------ПЕРЕНОС ЕСТЬ
PERENOS: MOV SZ[BX], '0' ;В ДАННЫЙ РАЗРЯД - НУЛЬ
DEC BX ;УВЕЛИЧЕНИЕ РАЗРЯДА
JMP SRAVN ;НА СРАВНЕНИЕ РАЗРЯДА С "8"
;===========СРАВНЕНИЕ ДЕЛИМОГО И ДЕЛИТЕЛЯ
DEL: LEA SI, SX
LEA DI, SY
CALL COMPARE
MOV AL, [SI]
CMP AL, 1
JNE QUIT ;ДЕЛЕНИЕ ЗАВЕРШЕНО
JMP NEAR PTR AGAIN ;ДЕЛЕНИЕ ПРОДОЛЖАЕТСЯ
;-----------ОПРЕДЕЛЕНИЕ ЗНАКА ЧАСТНОГО
QUIT: MOV AH, SX[2]
MOV AL, SY[2]
;-----------ВЫЯСНЕНИЕ ЗНАКА ДЕЛИМОГО
CMP AH, '-'
JE SX_
JMP N_SX_
;-----------ДЕЛИМОЕ - ОТРИЦАТЕЛЬНОЕ
SX_: CMP AH, AL ;СРАВНЕНИЕ ЗНАКА ДЕЛИМОГО И ДЕЛИТЕЯ
JE OUTP ;НА ВЫВОД ОСТАТКА
;-----------ДЕЛИТЕЛЬ - ПОЛОЖИТЕЛЬНЫЙ
;===========УДАЛЕНИЕ ВЕДУЩИХ НУЛЕЙ В ЧАСТНОМ
SY_: MOV BX, 0
SRCH: CMP SZ[BX], '0'
JE DALEE
JMP STOP
DALEE: INC BX
JMP SRCH
;-----------ЗАПИСЬ МИНУСА ПЕРЕД СТАРШИМ РАЗРЯДОМ ЧАСТНОГО
STOP: DEC BX
MOV SZ[BX], '-'
JMP OUTP ;НА ВЫВОД ОСТАТКА
;-----------ДЕЛИМОЕ ПОЛОЖИТЕЛЬНОЕ
N_SX_: CMP AL, '-' ;ДЕЛИТЕЛЬ ОТРИЦАТЕЛЬНЫЙ?
JE SY_ ;ЧАСТНОЕ ОТРИЦАТЕЛЬНОЕ
;-----------ВЫВОД ЧАСТНОГО
;===========ВЫВОД ОСТАТКА
;-----------ВЫВОД СТРОКИ "ОСТАТОК:"
OUTP: LEA DX, S6
MOV AH, 9
INT 21H
;ЗАПИСЬ В КОНЕЦ ОСТАТКА СИМВОЛОВ 10, 13 И "$"
MOV BH, 0
MOV BL, SX[1]
ADD BX, 2 ;ВХ - ЗА МЛАДШИЙ РАЗРЯД
MOV SX[BX], 10
INC BX
MOV SX[BX], 13
INC BX
MOV SX[BX], '$'
;-----------УДАЛЕНИЕ ВЕДУЩИХ НУЛЕЙ ОСТАТКА
MOV AH, '0'
LEA BX, SX ;ВХ - УКАЗЫВАЕТ НА ОСТАТОК
INC BX
INC BX
MOV AL, [BX]
CMP AL, '-'
JE MN
JMP N_MN
MN: MOV AH, '-'
INC BX
N_MN: MOV AL, [BX]
CMP AL, '0'
JE EQ1
JMP NEQ1
EQ1: INC BX
JMP N_MN
NEQ1: MOV AL, [BX]
DEC BX
CMP AL, 10
JE N_NUL
MOV [BX], AH
CMP AH, '-'
JE EQQ
JMP NEQQ
EQQ: MOV DX, BX
JMP LBL
NEQQ: INC BX
MOV AL, [BX]
CMP AL, 10
JE NUL
JMP N_NUL
NUL: DEC BX
N_NUL: MOV DX, BX
LBL: MOV AH, 9
INT 21H
;===========ВЫВОД ЧАСТНОГО
LEA DX, S7
MOV AH, 9
INT 21H
LEA BX, SZ
Q: MOV AL, [BX]
CMP AL, '0'
JE SM3
JMP OUTPUT
SM3: INC BX
JMP Q
OUTPUT: MOV DX, BX
MOV AH, 9
INT 21H
;-----------ВЫХОД ИЗ ПРОГРАММЫ
ENDPROG: MOV AH, 4CH
INT 21H
;===========ПРОЦЕДУРА CONTROL - ЧИСЛО ДЕВЯТИРИЧНОЕ?
CONTROL PROC
PUSHA ;СОХРАНЕНИЕ РЕГИСТРОВ В СТЕКЕ
MOV BX, DX
INC BX
MOV AL, [BX]
MOV AH, 0
MOV CX, AX
;-----------ЯВЛЯЕТСЯ ЛИ СТРОКА ПУСТОЙ?
CMP AL, 0
JE ERR1 ;ЯВЛЯЕТСЯ
;-----------ПРОВЕРКА ДЛИНЫ СТРОКИ
CMP AL, 6
JA ERR1 ;ЧИСЛО ВВЕДЕНО НЕВЕРНО
INC BX
MOV AH, [BX]
CMP AH, '-'
JE MINUS
JMP NEAR PTR FOR1
MINUS: INC BX ;ЧИСЛО ОТРИЦАТЕЛЬНОЕ
DEC CX
;-----------ВВЕДЕННОЕ ЧИСЛО ДЕВЯТИРИЧНОЕ?
FOR1: MOV AH, [BX]
CMP AH, '9'
JB N1
ERR1: JMP NEAR PTR ERROR ;ЧИСЛО ВВЕДЕНО НЕВЕРНО
N1: CMP AH, '0'
JB ERR1 ;ЧИСЛО ВВЕДЕНО НЕВЕРНО
INC BX
LOOP FOR1
MOV [BX], BYTE PTR '$' ;ДЛЯ ВЫВОДА СТРОКИ
CMP AL, 6
JNE RETURN ;ЕСЛИ ДЛИНА ЧИСЛА МЕНЬШЕ 6
MOV BX, DX
INC BX
MOV AH, 0
MOV CX, AX
INC BX
MOV AH, [BX]
CMP AH, '-'
JE M1 ;ЧИСЛО ОТРИЦАТЕЛЬНОЕ
LEA DI, H ;ЧИСЛО ПОЛОЖИТЕЛЬНОЕ
JMP FOR2
M1: INC BX
DEC CX
LEA DI, L
;ВХОДИТ ЛИ ЧИСЛО В ЗАДАННЫЙ ДИАПАЗОН?
FOR2: MOV AH, [BX]
CMP AH, [DI]
JA ERROR ;ЧИСЛО ВВЕДЕНО НЕВЕРНО
JB RETURN ;ЧИСЛО ВВЕДЕНО ПРАВИЛЬНО
INC BX
INC DI
LOOP FOR2
JMP RETURN
ERROR: MOV BX, DX
MOV [BX], BYTE PTR '0'
RETURN: POPA ;ВОССТАНОВЛЕНИЕ РЕГИСТРОВ
RET
CONTROL ENDP
;===========ПРОЦЕДУРА CTRL0 - ЭТО НУЛЬ?
CTRL0 PROC
PUSHA
MOV SI, 1
MOV CL, [BX+SI]
MOV CH, 0
INC SI
MOV AL, [BX+SI]
CMP AL, '-'
JE MIN
JMP CYCLE
MIN: INC SI
DEC CX
CYCLE: MOV AL, [BX+SI]
CMP AL, '0'
JNE FINISH
INC SI
LOOP CYCLE
MOV SI, 0
MOV AL, '0'
MOV [BX+SI], AL
FINISH: POPA
RET
CTRL0 ENDP
;===========ПРОЦЕДУРА COMPARE - СРАВНЕНИЕ ДВУХ ЧИСЕЛ
COMPARE PROC
PUSHA
INC SI
INC DI
MOV AH, [SI]
MOV AL, [DI]
INC SI
INC DI
CMP BYTE PTR [SI], '-'
JE NEGAT1
JMP POZIT1
NEGAT1: DEC AH
INC SI
POZIT1: CMP BYTE PTR [DI], '-'
JE NEGAT2
JMP POZIT2
NEGAT2: DEC AL
INC DI
POZIT2: MOV BL, [SI]
CMP BL, '0'
JE SM
JMP DI0
SM: INC SI
DEC AH
JMP POZIT2
DI0: MOV BL, [DI]
CMP BL, '0'
JE SM1
JMP SRAV1
SM1: INC DI
DEC AL
JMP DI0
SRAV1: CMP AH, AL
JA ABOVE
JB BELOW
JMP EQUAL
ABOVE: LEA SI, SX
MOV [SI], BYTE PTR 1
JMP NEAR PTR END1
BELOW: LEA SI, SX
MOV [SI], BYTE PTR -1
JMP NEAR PTR END1
EQUAL: MOV CL, AL
MOV CH, 0
FOR3: MOV AH, [SI]
CMP AH, [DI]
JA ABOVE
JB BELOW
INC SI
INC DI
LOOP FOR3
JMP ABOVE
END1: POPA
RET
COMPARE ENDP
END BEGIN