Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Чемпионы рейтинга экспертов в этой рассылке

Boriss
Статус: Академик
Рейтинг: 2113
∙ повысить рейтинг »
_Ayl_
Статус: Практикант
Рейтинг: 1865
∙ повысить рейтинг »
vladisslav
Статус: 6-й класс
Рейтинг: 1196
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И ПО / Программирование / Assembler (Ассемблер)

Номер выпуска:1325
Дата выхода:25.04.2010, 01:00
Администратор рассылки:Лысков Игорь Витальевич, Модератор
Подписчиков / экспертов:319 / 62
Вопросов / ответов:1 / 1
IRC-канал по теме:#assembler

Вопрос № 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)вычисления производить в сопроцессоре

Заранее спасибо дорогие эксперты!

Отправлен: 17.04.2010, 14:46
Вопрос задал: Юдин Евгений Сергеевич, 1-й класс
Всего ответов: 1
Страница вопроса »


Отвечает Лысков Игорь Витальевич, Модератор :
Здравствуйте, Юдин Евгений Сергеевич.
Программа по первому вопросу.
Можно было использовать 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 ;аналогично

lea dx, sQuot ;Quotient =
mov ah, 9
int 21h

push ds
mov ax, dsegX ;переменную x адресуем es:di< br> mov es, ax
mov ax, dsegy ;переменную y адресуем ds:si
mov ds, ax

lea bx, XdivY ;смещение результата в сегменте dseg.
; сегмент зададим внутри попрограммы !
call div_BCD_4_2 ;делим
pop ds

mov ax, dseg
mov es, ax
mov cx, 4
call PrBCD ;выводим результат: cx=4 байт BCD по адресу es:bx

lea dx, sPress ;Press any key
mov ah, 9
int 21h

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 ax, dseg
mov ds, ax ;загрузим ds сегментом dseg (для частного)

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 (Россия) | Еще номера »
  • Отправить WebMoney:

  • Оценить выпуск »
    Нам очень важно Ваше мнение об этом выпуске рассылки!

    Задать вопрос экспертам этой рассылки »

    Скажите "спасибо" эксперту, который помог Вам!

    Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА
    на короткий номер 1151 (Россия)

    Номер ответа и конкретный текст СМС указан внизу каждого ответа.

    Полный список номеров »

    * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов)
    ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
    *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.


    © 2001-2010, Портал RFpro.ru, Россия
    Авторское право: ООО "Мастер-Эксперт Про"
    Автор: Калашников О.А. | Программирование: Гладенюк А.Г.
    Хостинг: Компания "Московский хостер"
    Версия системы: 2010.6.14 от 03.03.2010

    В избранное