Умножение/деление со сдвигом - Assembler
Формулировка задачи:
Помогите исправить код. Пожалуйста.
Операции умножения и деления выполнять с помощью операций сдвига.
F= y-(96*x)/16 (8-битные со знаком)
Ввод значений переменных организовать с клавиатуры.
Вывод результата организовать на экран. Если размер результата будет более 16 бит – результат преобразовывать в 16-битный
LOCALS .model small .stack 100h .data CrLf db 0Dh, 0Ah, '$' PromptGetX db 'Input X (-32768..+32767): ', '$' PromptGetY db 'Input Y (-32768..+32767): ', '$' KeyBuf db 7, 0, 8 dup(0) ;max,len,string,CR(0dh) msgError db 'Ошибка ввода числа', 0Dh, 0Ah, '$' X db ? Y db ? F db ? .code main proc mov ax, @data mov ds, ax @@GetX: ; ввод числа с клавиатуры (строки) lea dx, PromptGetX mov ah,09h int 21h mov ah, 0Ah mov dx, offset KeyBuf int 21h ; перевод строки (на новую строку) lea dx, CrLf mov ah,09h int 21h ; преобразование строки в число lea si, KeyBuf+1 lea di, X call Str2Num ; проверка на ошибку jnc @@GetY ; если есть ошибка ввода - напечатать сообщение об ошибке lea dx, msgError mov ah,09h int 21h jmp @@GetX @@GetY: ; ввод числа с клавиатуры (строки) lea dx, PromptGetY mov ah,09h int 21h mov ah, 0Ah mov dx, offset KeyBuf int 21h ; перевод строки (на новую строку) lea dx, CrLf mov ah,09h int 21h ; преобразование строки в число lea si, KeyBuf+1 lea di, Y call Str2Num ; проверка на ошибку jnc @@Calc ; если есть ошибка ввода - напечатать сообщение об ошибке lea dx, msgError mov ah,09h int 21h jmp @@GetY @@Calc: ;F= y-(96*x)/16 ??? mov cl, X sal cl,1 sal cl,1 sal cl,1 mov bh, Y sub bh,cl mov F, bh call Show_AX mov ax, 4C00h int 21h main endp ; выводит число из регистра AX на экран ; входные данные: ; ax - число для отображения Show_AX proc push ax push bx push cx push dx push di mov cx, 10 xor di, di ; di - кол. цифр в числе ; если число в ax отрицательное, то ;1) напечатать '-' ;2) сделать ax положительным or ax, ax jns @@Conv push ax mov dx, '-' mov ah, 2 ; ah - функция вывода символа на экран int 21h pop ax neg ax @@Conv: xor dx, dx div cx ; dl = num mod 10 add dl, '0' ; перевод в символьный формат inc di push dx ; складываем в стэк or ax, ax jnz @@Conv ; выводим из стэка на экран @@Show: pop dx ; dl = очередной символ mov ah, 2 ; ah - функция вывода символа на экран int 21h dec di ; повторяем пока di<>0 jnz @@Show pop di pop dx pop cx pop bx pop ax ret Show_AX endp ; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; ds:[di] - адрес числа ; на выходе ; ds:[di] - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num proc push ax push bx push cx push dx push ds push es push si push ds pop es mov cl, ds:[si] xor ch, ch inc si mov bx, 10 xor ax, ax ;если в строке первый символ '-' ; - перейти к следующему ; - уменьшить количество рассматриваемых символов cmp byte ptr [si], '-' jne @@Loop inc si dec cx @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; игнорируем старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@Error cmp al, '9' ja @@Error sub al, '0' xor ah, ah add ax, [di] jc @@Error ; Если сумма больше 65535 cmp ax, 8000h ja @@Error inc si loop @@Loop pop si ;проверка на знак push si inc si cmp byte ptr [si], '-' jne @@Check ;если должно быть положительным neg ax ;если должно быть отрицательным jmp @@StoreRes @@Check: ;дополнительная проверка, когда при вводе положительного числа получили отрицательное or ax, ax ; js @@Error @@StoreRes: ;сохранить результат mov [di], ax clc pop si pop es pop ds pop dx pop cx pop bx pop ax ret @@Error: xor ax, ax mov [di], ax stc pop si pop es pop ds pop dx pop cx pop bx pop ax ret Str2Num endp end main
Решение задачи: «Умножение/деление со сдвигом»
textual
Листинг программы
LOCALS .model small .stack 100h .data CrLf db 0Dh, 0Ah, '$' PromptGetX db 'Input X : ', '$' PromptGetY db 'Input Y: ', '$' KeyBuf db 7, 0, 8 dup(0) ;max,len,string,CR(0dh) msgError db 'Ошибка ввода числа', 0Dh, 0Ah, '$' X db ? Y db ? F db ? .code main proc mov ax, @data mov ds, ax @@GetX: ; ввод числа с клавиатуры (строки) lea dx, PromptGetX mov ah,09h int 21h mov ah, 0Ah mov dx, offset KeyBuf int 21h ; перевод строки (на новую строку) lea dx, CrLf mov ah,09h int 21h ; преобразование строки в число lea si, KeyBuf+1 lea di, X call Str2Num ; проверка на ошибку jnc @@GetY ; если есть ошибка ввода - напечатать сообщение об ошибке lea dx, msgError mov ah,09h int 21h jmp @@GetX @@GetY: ; ввод числа с клавиатуры (строки) lea dx, PromptGetY mov ah,09h int 21h mov ah, 0Ah mov dx, offset KeyBuf int 21h ; перевод строки (на новую строку) lea dx, CrLf mov ah,09h int 21h ; преобразование строки в число lea si, KeyBuf+1 lea di, Y call Str2Num ; проверка на ошибку jnc @@Calc ; если есть ошибка ввода - напечатать сообщение об ошибке lea dx, msgError mov ah,09h int 21h jmp @@GetY @@Calc: mov ax, 0 ;bx:=96*X mov al, X mov cl, 5 sal ax, cl mov bx, ax sal ax, 1 add bx, ax mov cl, 4 ;bx:=(96*X)/16 sar bx, cl mov bx, 9 ;ax:=Y mov al, Y sub ax, bx ;ax:=Y-(96*X)/16 call Show_AX mov ax, 4C00h int 21h main endp ; выводит число из регистра AX на экран ; входные данные: ; ax - число для отображения Show_AX proc push ax push bx push cx push dx push di mov cx, 10 xor di, di ; di - кол. цифр в числе ; если число в ax отрицательное, то ;1) напечатать '-' ;2) сделать ax положительным or ax, ax jns @@Conv push ax mov dx, '-' mov ah, 2 ; ah - функция вывода символа на экран int 21h pop ax neg ax @@Conv: xor dx, dx div cx ; dl = num mod 10 add dl, '0' ; перевод в символьный формат inc di push dx ; складываем в стэк or ax, ax jnz @@Conv ; выводим из стэка на экран @@Show: pop dx ; dl = очередной символ mov ah, 2 ; ah - функция вывода символа на экран int 21h dec di ; повторяем пока di<>0 jnz @@Show pop di pop dx pop cx pop bx pop ax ret Show_AX endp ; преобразования строки в число ; на входе: ; ds:[si] - строка с числом ; ds:[di] - адрес числа ; на выходе ; ds:[di] - число ; CY - флаг переноса (при ошибке - установлен, иначе - сброшен) Str2Num proc push ax push bx push cx push dx push ds push es push si push ds pop es mov cl, ds:[si] xor ch, ch inc si mov bx, 10 xor ax, ax ;если в строке первый символ '-' ; - перейти к следующему ; - уменьшить количество рассматриваемых символов cmp byte ptr [si], '-' jne @@Loop inc si dec cx @@Loop: mul bx ; умножаем ax на 10 ( dx:ax=ax*bx ) mov [di], ax ; игнорируем старшее слово cmp dx, 0 ; проверяем, результат на переполнение jnz @@Error mov al, [si] ; Преобразуем следующий символ в число cmp al, '0' jb @@Error cmp al, '9' ja @@Error sub al, '0' xor ah, ah add ax, [di] jc @@Error ; Если сумма больше 65535 cmp ax, 8000h ja @@Error inc si loop @@Loop pop si ;проверка на знак push si inc si cmp byte ptr [si], '-' jne @@Check ;если должно быть положительным neg ax ;если должно быть отрицательным jmp @@StoreRes @@Check: ;дополнительная проверка, когда при вводе положительного числа получили отрицательное or ax, ax ; js @@Error @@StoreRes: ;сохранить результат mov [di], ax clc pop si pop es pop ds pop dx pop cx pop bx pop ax ret @@Error: xor ax, ax mov [di], ax stc pop si pop es pop ds pop dx pop cx pop bx pop ax ret Str2Num endp end main
Объяснение кода листинга программы
- Устанавливаются локальные переменные и параметры модели компоновки.
- Инициализируются переменные для вывода сообщений на экран и ввода/вывода данных.
- Определяется сообщение об ошибке.
- Инициализируются переменные для хранения вводимых значений X, Y и результата F.
- В процедуре main инициализируются стек и сегмент данных, инициализируются регистры.
- Происходит ввод значений X и Y с клавиатуры путем вызова соответствующих сообщений и обработки пользовательского ввода.
- Переводятся введенные строки в числа.
- Если произошла ошибка ввода, выводится сообщение об ошибке, и процесс ввода повторяется.
- Рассчитывается значение переменной F с использованием операций умножения, деления и арифметических операций.
- Результат выводится на экран с помощью процедуры Show_AX.
- Программа завершается системным вызовом.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д