Вопрос № 177889:Доброго времени суток дорогие Эксперты! помогите решить парочку задач на ассемблере: 1) Написать программу для выполнения сложения 2х целых чисел размера N байт (N>0) пре...
Вопрос № 177889:
Доброго времени суток дорогие Эксперты!
помогите решить парочку задач на ассемблере: 1) Написать программу для выполнения сложения 2х целых чисел размера N байт (N>0) представленных в дополнительном коде коде.
2)Написать программу для выполнения деления 2х N-значных знаковых десятичных чисел (N>1) представленных в неупакованном формате представления.
Хар-ки: 1)процессор intel core 2 solo CPU U3500 2)window
vista home premium 32х разрядная 3)Turbo Assembler Version 4.1 в папке asm находится фаил TASM поэтому думаю он предпочтителен 4)вычисления производить в сопроцессоре
Отвечает Лысков Игорь Витальевич, Модератор :
Здравствуйте, Юдин Евгений Сергеевич. Программа по первому вопросу. Можно было использовать 32-битные регистры. Но мне захотелось продемонстрировать, как можно обойтись 16-битными... При желании, можете легко переделать на 16-битные данные... Все необходимое есть.
Код:
;Складываем x + y и выводим результат ;Разрядность данных - двойное слово (4 байта) ;Используем исключительно 16-битные регистры
dsegX segment para public 'data' x dd -2147400012 dsegX ends
dsegY segment para public 'data' y dd 1234 dsegY ends
dseg segment para public 'data' sX db 'x = $' sY db 0dh,0ah,'y = $' sSum db 0dh,0ah,'Sum
= $' sPress db 0dh,0ah,'Press any key$' dseg ends
LOCALS @@ ;чтобы метки, начинающиеся на @@ были локальными cseg segment para public 'code' assume cs:cseg, ds:dseg, es:nothing start: ;точка входа mov ax, dseg mov ds, ax ;ds - сегмент данных
lea dx, sX ;x = mov ah, 9 int 21h
mov ax, dsegX ;переменную x адресуем через сегментный регистр es mov es, ax mov ax, word ptr es:x ;младшее слово mov dx, word ptr es:x+2 ;старшее
слово call WriteDWordDEC_signed ;выведем знаковое двойное слово
mov si, ax ;сохраним x mov di, dx
lea dx, sY ;y = mov ah, 9 int 21h
mov ax, dsegY ;аналогично берем значение y mov es, ax mov ax, word ptr es:y mov dx, word ptr es:y+2 call WriteDWordDEC_signed ;выведем
add si, ax ;найдем сумму adc di, dx
lea dx, sSum ;Sum = mov ah, 9 int 21h
mov ax, si ;значение сум
мы mov dx, di call WriteDWordDEC_signed ;выведем
lea dx, sPress ;Press any key mov ah, 9 int 21h
mov ah, 0 ;чтобы окно сразу не закрывалось int 16h
mov ax, 4c00h ;выход в ДОС int 21h
;Вывод знакового двойного слова из DX:AX ;если отрицательное, выводит минус, превращает в ;положительное и далее выводит как беззнаковое WriteDWordDEC_signed proc push ax dx ;сохраним число
or dx, dx ;проверим знак jns @@_no_sign push ax mov al,
'-' ;выведем '-' int 29h pop ax not ax ;изменение знака на + not dx add ax, 1 adc dx, 0 @@_no_sign: CALL writeDWordDEC ;выводим положительное беззнаковое число
pop dx ax ret WriteDWordDEC_signed endp
;Вывод беззнакового двойного слова из DX:AX ;просто делением на 10 не получится, возможно переполнение ;переполнение возможно и при делении на 10000 ;поэтому делим на 100000,
причем в два этапа: ;сначала на 50000 (что помещается в слово), затем на 2 ;затем выводим частное от деления и остаток (5-значное цисло!) ;разные ньюансы смотрим по ходу... writeDWordDEC proc push si cx dx bx ax xor cx, cx ;старшее слово остатка от деления на 100000, ; т.к. макс значение 99999 не помещается в слово! mov bx, 50000 ;делим сначала на 50000 div bx shr ax, 1 ;и на 2 jnc @@1 ;если нет переноса, то остаток < 50000 ! add dx, 50000 ;добавим
к остатку 50000 ! adc cx, 0 ;и учтем перенос ! @@1: xor si, si ;количество выводимых цифр в остатке. ;0 - выводим остаток, сколько есть значащих цифр ;5 - если есть частное от деления на 100000, ; то у остатка должно быть обязательно 5 значащих цифр! test ax, ax ;проверим частное от деления на 100000 jz @@2 ;выводим остаток как есть call writeWordDEC ;выводим частное, как слово mov si, 5 ;и 5 обязательных циф
р остатка! @@2: mov ax, dx ;остаток в dx:ax mov dx, cx call write5DigDEC ;выводим
pop ax bx dx cx si ret
writeDWordDEC endp
;вывод на экран 5 дес цифр в DX:AX, воспринимается как беззнаковое ;SI - количество обязательных цифр write5DigDEC proc mov bx, 10 ;будем делить на 10 xor cx, cx ;счетчик цифр @@1: div bx ;делим dx:ax на bx push dx ;сохраним в стеке очередную цифру xor dx, dx ;для следующего деления inc cx ;считаем цифры or ax, ax ;есть еще разряды? jnz @@1 ;пока не разложим на цифры mov al, '0' ;выведем незначащие нули! mov dx,
cx ;число полученных цифр @@2: cmp dx, si ;сравним с максимальным jae @@3 ;для 0 сразу уходим, для 5 - пока не добавим int 29h ; inc dx ; необходимое количество незначащих нулей jmp @@2 @@3: ;цикл вывода полученного числа pop ax ;извлекаем из стека очередной разряд add al, '0' ;превращаем в символ int 29h ;выводим LOOP @@3 ;по всем цифрам
ret write5DigDEC endp
; вывод на экран сло
ва в AX, воспринимается как беззнаковое writeWordDEC proc push cx dx bx ax
mov bx, 10 ;делим на 10 xor cx, cx ;счетчик цифр @@1: xor dx, dx ;подготавливаемся к делению div bx ;делим dx:ax на bx push dx ;сохраним остаток - очередную цифру inc cx ;считаем цифры or ax, ax ;есть еще разряды? jnz @@1 ;пока не разложим на цифры @@2: ;цикл вывода полученного числа pop ax ;извлекаем из стека очередной разряд add al, '0' ;превращаем
в символ int 29h ;выводим LOOP @@2 ;по всем цифрам
pop ax bx dx cx ret writeWordDEC endp
;вывод на экран слова в AX как знакового ;если отрицательное, выводит минус, превращает в ;положительное и вызывает подпрограмму writeWordDEC WriteWordDEC_signed proc push ax or ax, ax ;проверим на знак jns @@_no_sign ;если положительное, то просто выводим push ax mov al, '-' ;выводим '-'
int 29h pop ax neg ax ;изменение знака на + @@_no_sign: CALL writeWordDEC ;выводим беззнаковое pop ax ret WriteWordDEC_signed endp
cseg ends
end start
Вторая программа делит знаковые 4-х разрядное BCD-число на 2-х разрядное BCD число Остаток отбрасываем. Ограничился более сложным случаем, а именно: делением в виде BCD Полагаю, требовалось именно это...
Код:
;Делим неупакованные числа x (разрядности 4) на y (разрядности 2) и выводим результат ;числа хранятся в формате "старший первым", знак - в виде бита 7, т.е. маска 80h в старшем байте dsegX segment para public 'data' x db 83h,6,9,8 dseg
X ends
dsegY segment para public 'data' y db 81h,2 dsegY ends
dseg segment para public 'data' XdivY db 0,0,0,0 sX db 'x = $' sY db 0dh,0ah,'y = $' sQuot db 0dh,0ah,'Quotient = $' sPress db 0dh,0ah,'Press any key$' dseg ends
cseg segment para public 'code' assume cs:cseg, ds:dseg, es:nothing start: ;точка входа mov ax, dseg mov ds, ax ;ds - сегмент данных
lea dx, sX ;x = mov ah,
9 int 21h
mov ax, dsegX ;переменную x адресуем через сегментный регистр es mov es, ax lea bx, x ;смещение для вывода mov di, bx ;смещение для деления mov cx, 4 call PrBCD ;выводим cx=4 байт BCD по адресу es:bx
lea dx, sY ;y = mov ah, 9 int 21h
mov ax, dsegY ;переменную y адресуем через сегментный регистр es mov es, ax lea bx, y mov si, bx ;смещение для деления mov cx, 2 call PrBCD
;аналогично
mov ah, 0 ;чтобы окно сразу не закрывалось int 16h
mov ax, 4c00h int 21h
;Вывод
cx байт BCD по адресу es:bx PrBCD proc test byte ptr es:[bx], 80h ;проверим знак jz PrSearchNonZero mov al, '-' ;выведем минус int 29h PrSearchNonZero: ;найдем первый не 0! mov al, es:[bx] inc bx and al, not 80h ;сбрасываем старший бит, одновременно проверяем на 0 loopz PrSearchNonZero ;циклим, пока cx!=0 и al!=0 jcxz PrLast ;все 0, выводим один 0 PrLoop: ;цикл вывода значащих цифр, кроме последней (
!) or al, '0' ;в символ int 29h mov al, es:[bx] ;читаем следующую цифру inc bx loop PrLoop PrLast: ;выведем последнюю цифру or al, '0' int 29h ret PrBCD endp
;делим BCD es:di на ds:si ;результат пишем в dseg:bx div_BCD_4_2 proc push ds di ax cx dx bx ;преобразуем делитель в двоичное число mov ax, [si]
mov dh, al and dh, 80h ;сохраним знак делителя
and al, not 80h ;сбросим знак xchg ah, al ;поменяем
местами (надо для aad) aad mov dl, al ;делитель
mov al, es:[di] ;определим знак делимого and al, 80h xor dh, al ;знак частного !
mov ah, 0 ;старший разряд пока = 0 mov cx, 4 ;число проходов div_BCD_loop: mov al, 10 ;умножим старший разряд на 10 mul ah push cx ;сохраним счетчик проходов mov cl, es:[di] ;очередной младший р
азряд inc di ;смещение следующего and cx, 007fh ;сбросим знак add ax, cx ;получим ст*10+мл pop cx ;восстановим счетчик div dl ;делим на делитель mov [bx], al ;очередная цифра частного, в ah остаток, ; который будет старшим разрядом на следующем шаге inc bx ;смещение следующейцифры частного loop div_BCD_loop pop bx ;восстановим смещение начала частного or [bx], dh ;и установим знак частного! pop dx cx ax di ds ;восстановим остальные регистры
RET div_BCD_4_2 endp
cseg ends end start
----- Удачи!
Ответ отправил: Лысков Игорь Витальевич, Модератор
Ответ отправлен: 22.04.2010, 14:05
Номер ответа: 260957 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 260957
на номер 1151 (Россия) |
Еще номера »
Оценить выпуск »
Нам очень важно Ваше мнение об этом выпуске рассылки!
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.