Форум программистов, компьютерный форум, киберфорум
Наши страницы
Assembler для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
1

Вычисления значения функции в формате с плавающей запятой

24.04.2016, 16:36. Просмотров 544. Ответов 20
Метки нет (Все метки)

Задание такое - Написать программу для решения функции y=х^2-x^4, где х меняется от -2 до +2 с шагом 0,5. Нужно вычислить функцию на каждом шаге. В формате вычисления с плавающей комой.
Процессор х86.

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
TITLE Курсова робота
EXTERN MULFXX, MULFXY, ADDSUBFYZ, ADDSUBFYZ
 
STACK SEGMENT PARA STACKSTACK”
    DB  64 DUP (0)
STACK ENDS
 
DSEG SEGMENT PARA PUBLICDATA”
    X   DD  -2.0
        DX  DD    0.5
    Y   DD  1 DUP (0)
    Z   DD  1 DUP (0)
    R   DQ  8 DUP (0)
DSEG ENDS
 
CSEG SEGMENT PARA PUBLICCODE”
    ASSUME CS:CSEG, DS:DSEG, SS:STACK
 
MAIN PROC FAR
    mov ax,DSEG
    mov ds,ax
    mov cx,8  ; по скольку нужно сделать исчисления от -2 до +2 с шагом 0,5 заносим в счётчик(сх) 8
    push    cx  ; заносим в стек сх, по скольку в подпрограммах используется регистр сх
Start:  call    MULFXX  ; Возводим Х в квадрат и заносим результат в Y
    call    MULFYY  ; Возводим Х в 4 степень и заносим результат в Z
    call    ADDSUBFYZ  ; Y-Z
    pop cx  ; достаём сх из стека для цикла
    call    ADDSUBFXDX  ; для реализации шага выполняем эту подпрограмму, то есть x-dx, то есть 2.0-0,5, то есть, если сначала в Х было значение -2.0, то теперь там -1.5
    loop    Start  ; цикл
Такие вопросы
Как после выполнения всех подпрограмм занести результат со смещением 4 байта и в какой регистр его лучше занести ?
Будет ли уменьшатся сх после того как мы его достанем из стека и выполним цикл. То есть сначала в сх 8, после того выполнили цикл, он должен стать 7, но поскольку мы достаём из стека сх со значением 8, значит сх не уменьшается. Во общем если сх не уменьшается, то как сделать так что бы программа выполнилась 8 раз и закончилась ?
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.04.2016, 16:36
Ответы с готовыми решениями:

Вычитание чисел с плавающей запятой в формате double ассемблер
Доброго времени суток. Прошу помочь, нужно написать программу:"Вычитание чисел...

Программа для вычисления выражения в формате с плавающей точкой с использованием команд сопроцессора I 80X87
Помогите, пожалуйста, составить программу, а то сессия уже идет :cry: ...

Запись числа с плавающей запятой в регистр
Здравствуйте уважаемые эксперты! Подскажите как записать число с плавающей...

Операции над числами с плавающей запятой
Пишу при помощи masm. Изучение ассемблера только начал. Обычно с такими...

Вывести с FPU на монитор число с плавающей запятой
Доброго времени суток. Мне нужно вывести с FPU на монитор число с плавающей...

20
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
24.04.2016, 21:51 2
В стек надо заносить СХ после метки начала цикла, а не до неё, а перед командой loop извлекать из стека. Тогда после выполнения команды loop сминусованый СХ будет сохранятся в начале следующего цикла.

Только ИМХО ручной подсчет числа циклов это неправильно. Из цикла надо выходить по проверке условия выхода за диапазон. В данном случае когда Х больше или равен двум.
1
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
24.04.2016, 23:15  [ТС] 3
То есть будет так ?
Assembler
1
2
3
4
5
6
7
8
9
10
    mov ax,DSEG
    mov ds,ax
    mov cx,8  
Start:  push    cx
    call    MULFXX 
    call    MULFYY  
    call    ADDSUBFYZ
    pop cx  
    call    ADDSUBFXDX  
    loop    Start
А какая разница, ведь pop cx и так перед loop находится ?
Или я чего-то не понимаю ?

Добавлено через 2 минуты
Или вы имели ввиду, если разместить команду pop cx непосредственно перед командой loop, то тогда сх сминусуется ?
То есть будет так ?
Assembler
1
2
  pop    cx
    loop    Start
0
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
24.04.2016, 23:23 4
Цитата Сообщение от fdrv Посмотреть сообщение
А какая разница, ведь pop cx и так перед loop находится ?
Или я чего-то не понимаю ?
Между pop и loop в исходном варианте расположена call ADDSUBFXDX, а по условию
Цитата Сообщение от fdrv Посмотреть сообщение
; заносим в стек сх, по скольку в подпрограммах используется регистр сх
т.е. pop должен идти непосредственно перед самой loop, что бы подпрограмма его не изменила.

Цитата Сообщение от fdrv Посмотреть сообщение
Или вы имели ввиду, если разместить команду pop cx непосредственно перед командой loop, то тогда сх сминусуется ?
То есть будет так ?
Assembler
1
2
pop cx
loop Start
Совершенно верно. Тогда вы получите нетронутый с начала цикла СХ, loop его сминусует, а push в начале следующего цикла уже сминусованый уберёт в стек.
1
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
25.04.2016, 00:11  [ТС] 5
Дошло, спасибо большое !

Добавлено через 4 минуты
А другой вопрос не подскажите ?
Как после выполнения всех подпрограмм занести результат со смещением 4 байта и в какой регистр его лучше занести, то есть после выполнения всех 4-х call-ов нужно занести значение которое получилось, как и куда его лучше будет?
Сначала просто заносим в какой-то регистр, а уже после(остальные 7 раз) мы заносим со смещением 4 байта. Как это реализовать, подскажите пожалуйста ?
0
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
25.04.2016, 01:44 6
Цитата Сообщение от fdrv Посмотреть сообщение
Как после выполнения всех подпрограмм занести результат со смещением 4 байта и в какой регистр его лучше занести, то есть после выполнения всех 4-х call-ов нужно занести значение которое получилось, как и куда его лучше будет?
Для начала неплохо было бы знать что происходит в ваших подпрограммах. Поясню. Допустим в конце каждого вашего цикла в результате последнего вычисления результат уже находится в каком либо регистре. Тогда целесообразней было бы из этого регистра помещать ответ в ваш массив. (какая то цепочка однотипных вычислений идущих подряд фиксированной длинны обычно называют массивом). В вашем случае это
Assembler
1
massiff DD 8 DUP (0) ; массив из восьми элементов размером dword
Однако поскольку вы работаете с 16 битными регистрами, то поместить результат за "один раз" у вас не получится, так как размер данных в два раза больше чем размер регистра. Поэтому придётся передавать по частям (DW). Для этого, а так же что бы не париться со смещением вам лучше использовать команду stosw она автоматически будет индексировать адрес. Но для этого перед началом цикла Start: необходимо сделать некоторые приготовления.
Assembler
1
lea     di,massiff ; адрес начала массива под ответы поместить в регистр di
тогда в конце каждого цикла вы сможете свой ответ загружать в данный массив командой stosw за два раза.
Условно примем что ваш результат после вычислений находится в регистрах DX - старшая часть, а AX - младшая часть.
Тогда код после последней call будет иметь следующий вид
Assembler
1
2
3
4
lodsw ; младшая часть ответа уходит в massiff по адресу в регистре di? после чего регистр di автоматом увеличивается на два байта
mov ax,dx ; помещаем в ax старшую часть ответа т.к. команда lods работает только с регистром EAX,AX,AL
lodsw ; и соответственно отправляем её из AX на адрес указанный в di. После этого di опять автоматически увеличивается на два байта.
; таким образом в конце каждого цикла мы за два раза по два байта пихаем наш ответ.
1
Mikl___
Автор FAQ
11975 / 6245 / 593
Регистрация: 11.11.2010
Сообщений: 11,302
25.04.2016, 05:21 7
http://www.cyberforum.ru/cgi-bin/latex.cgi?y=x^{2}-x^{4}=x^{2}(1-x)(1+x)
0
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
25.04.2016, 13:55  [ТС] 8
Цитата Сообщение от Полный 30h Посмотреть сообщение
Допустим в конце каждого вашего цикла в результате последнего вычисления результат уже находится в каком либо регистре.
В последней подпрограмме "call ADDSUBFYZ" я заношу результат в R. Это и есть помещение в массив ?
Вот последние строчки подпрограммы после которой я заношу результат в R
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
; Форматировать результат
@subf9: add ah,ah   ; Знак во флаге переноса
rcr bh,1    ; Знак числа на месте
rcr ah,1    ; Младший бит порядка в АН7
or  ah,7fh  ; Образовать мантиссу
and bl,ah   ; Образовать второй байт числа
@subfa: ret
;
; Сохранить результат
lea di,R
mov [di],si
mov [di+2],bx
Цитата Сообщение от Полный 30h Посмотреть сообщение
massiff DD 8 DUP (0)
у меня это записано вот так
Assembler
1
R   DQ  8 DUP
Цитата Сообщение от Полный 30h Посмотреть сообщение
Однако поскольку вы работаете с 16 битными регистрами, то поместить результат за "один раз" у вас не получится, так как размер данных в два раза больше чем размер регистра.
Простите пожалуйста за скорее всего глупый вопрос. То есть ах, bx, dx, cx - это 16 битные регистры, верно ?

Цитата Сообщение от Полный 30h Посмотреть сообщение
а так же что бы не париться со смещением вам лучше использовать команду stosw она автоматически будет индексировать адрес.
То есть имеется ввиду, оно само будет смещать результат и заносить его в массив при условии, если перед циклом я пропишу строчку
Assembler
1
lea     di,massiff ; адрес начала массива под ответы поместить в регистр di
Но у меня в подпрограммах используется di, можно ли его заменить его или, например как с сх, поместить его в стек, а потом извлечь его и использовать для массива ?

Цитата Сообщение от Полный 30h Посмотреть сообщение
команда lods работает только с регистром EAX,AX,AL
Во время ознакомления с регистрами, где-то вычитал, что когда мы пишем, например регистр ах, то мы сразу указываем и на al(младшая часть) и на ah(старшая часть), или я что-то не так понял ??

Assembler
1
2
3
4
lodsw ; младшая часть ответа уходит в massiff по адресу в регистре di? после чего регистр di автоматом увеличивается на два байта
mov ax,dx ; помещаем в ax старшую часть ответа т.к. команда lods работает только с регистром EAX,AX,AL
lodsw ; и соответственно отправляем её из AX на адрес указанный в di. После этого di опять автоматически увеличивается на два байта.
; таким образом в конце каждого цикла мы за два раза по два байта пихаем наш ответ.
то есть после этих строчок, результат будет заносится в massif(или в моём случае R) и di будет автоматически увеличиваться в итоге на 4 байта(как мне и нужно) и уже при повторении следующий результат будет заносится в 4 байта, на которые di уже увеличился и снова увеличится на 4 байта, после того как я второй раз занесу результат. Верно ?
И это всё реализуется если прописать stosw... а где именно её разместить ?

Фууух.... тяжело
0
Mikl___
Автор FAQ
11975 / 6245 / 593
Регистрация: 11.11.2010
Сообщений: 11,302
25.04.2016, 14:04 9
fdrv,
по ассемблеру есть много книг, хороших и разных, но прочитай хотя бы вот эту http://www.cyberforum.ru/assembler-articles/thread1005284.html, много времени не займет, а глупые вопросы хоть наполовину отпадут
1
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
25.04.2016, 17:21 10
Цитата Сообщение от fdrv Посмотреть сообщение
у меня это записано вот так
Assembler
1
R * DQ *8 DUP
Самый натуральный массив. Собственно у меня было предположение для чего он предназначен. Однако меня смутила его размерность. Ведь речь шла о сохранении четырехбайтных результатов DD, а размер ячеек вашего массива восемь байт DQ

Цитата Сообщение от fdrv Посмотреть сообщение
Assembler
1
2
3
4
; Сохранить результат
lea di,R
mov [di],si
mov [di+2],bx
Дело в том, что если такая конструкция у вас будет выполнятся в конце каждого цикла, то независимо от того сколько циклов будет, результат всегда будет попадать в первые четыре байта массива R т.к. команда lea di,R будет каждый раз помещать в регистр di адрес начала массива. Именно поэтому я и порекомендовал вам lea di,massiff, а в вашем случае lea di,R выполнить один раз до начала цикла
а в самом цикле тогда вместо
Assembler
1
2
mov [di],si
mov [di+2],bx
использовать lodsw
Assembler
1
2
3
4
mov ax,si ; младшая часть ответа в ах
lodsw ; младшая часть ответа из ах по адресу в di, а di+2
mov ax,bx ; старшая часть ответа в ах
lodsw ; старшая часть ответа из ах по адресу в di, а di+2
Цитата Сообщение от fdrv Посмотреть сообщение
То есть имеется ввиду, оно само будет смещать результат и заносить его в массив
Да. См. пример кода чуть выше с комментариями

Цитата Сообщение от fdrv Посмотреть сообщение
Но у меня в подпрограммах используется di, можно ли его заменить его или, например как с сх, поместить его в стек, а потом извлечь его и использовать для массива ?
В случае использования команды lodsw, заменить di другим регистром нельзя. Эта команда жестко привязана к регистрам di (адрес) и регистру ах (данные)
А вот стек использовать вполне можно. Равно как и вместо di использовать другой регистр в подпрограммах. Тут уже вы как программист сами решаете что вам эффективней, привычней и т.п.

Цитата Сообщение от fdrv Посмотреть сообщение
Во время ознакомления с регистрами, где-то вычитал, что когда мы пишем, например регистр ах, то мы сразу указываем и на al(младшая часть) и на ah(старшая часть), или я что-то не так понял ??
Совершенно верно. AH и AL это две части части (по 8 бит) одного 16 битного регистра - AX. Тоже самое с BX BH:BL и т.д.
Цитата Сообщение от fdrv Посмотреть сообщение
То есть ах, bx, dx, cx - это 16 битные регистры, верно ?
Верно. Выше как бы попытался донести.

Цитата Сообщение от fdrv Посмотреть сообщение
то есть после этих строчок, результат будет заносится в massif(или в моём случае R) и di будет автоматически увеличиваться в итоге на 4 байта(как мне и нужно) и уже при повторении следующий результат будет заносится в 4 байта, на которые di уже увеличился и снова увеличится на 4 байта, после того как я второй раз занесу результат. Верно ?
И это всё реализуется если прописать stosw... а где именно её разместить ?
Выше я привёл пример какой кусок кода вашей программы нужно заменить.
1
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
25.04.2016, 19:57  [ТС] 11
Задание - Написать программу для решения функцииy=х^2-x^4, где х меняется от -2 до +2 с шагом 0,5. Нужно вычислить функцию на каждом шаге. В формате вычисления с плавающей комой.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mov ax,DSEG
    mov ds,ax
    mov cx,8
    lea     di,R
    push     di  ; прячем в стек что бы потом вытащить и занести результат всей формулы
Start:  push    cx  ; заносим в стек сх
        call    MULFXX  ; Х возносим в квадрат, результат в Y
    call    MULFYY  ; Х возносим в 4 степень, результат в Z
    pop di ; вытаскиваем di 
        call    ADDSUBFYZ ; подпрограмма в конце которой мы получаем результат выполнения всей формулы и заносим результат в массив(R)
        push    di  ; прячем, поскольку di используется в других регистрах 
    call    ADDSUBFXDX ; выполняем шаг 
        pop cx  ; вытаскиваем 8 для цикла
    loop    Start  ; цикл
; сх и di используются в других регистрах но благодаря стеку, мы их прячем и достаём в нужные моменты
Как-то так. Есть какие нибудь замечания ?

Добавлено через 4 минуты
Цитата Сообщение от Mikl___ Посмотреть сообщение
fdrv,
по ассемблеру есть много книг, хороших и разных, но прочитай хотя бы вот эту http://www.cyberforum.ru/assembler-articles/thread1005284.html, много времени не займет, а глупые вопросы хоть наполовину отпадут
Спасибо Вам за книжку
0
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
25.04.2016, 20:35 12
Цитата Сообщение от fdrv Посмотреть сообщение
Есть какие нибудь замечания ?
Есть. С работой di в стеке. Она асимметрична. К тому же на первом же проходе значение загруженное в стек из cx вы выталкиваете в di
Assembler
1
2
3
4
Start:  push    cx  ; заносим в стек сх
        call    MULFXX  ; Х возносим в квадрат, результат в Y
    call    MULFYY  ; Х возносим в 4 степень, результат в Z
    pop di ; вытаскиваем di
программа не рабочая.
0
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
25.04.2016, 21:50  [ТС] 13
А если так ?
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    mov ax,DSEG
    mov ds,ax
    mov cx,8
    lea     di,R
    push     di 
Start:  push    cx 
    call    MULFXX 
    call    MULFYY 
    pop cx
    pop di 
    call    ADDSUBFYZ ; в это подпрограмме регистр сх не используется
    push    di 
    call    ADDSUBFXDX ; в это подпрограмме регистр сх тоже не используется
    loop    Start
И ещё вопрос по поводу di, до цикла прописано lea di,R и после занесли в стек, но потом выносим из стека перед call ADDSUBFYZ(тут же, в конце,используется команда lodsw которую Вы мне посоветовали), но в этой подпрограмме используется регистр di как вначале так и походу самой подпрограммы, это не как не повлияет на то что потом в конце мы заносим туда результат ?
0
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
26.04.2016, 00:00 14
Цитата Сообщение от fdrv Посмотреть сообщение
А если так ?
В принципе ошибок я не вижу. Единственное "НО" у вас до цикла стек уменьшается на два байта push di перед Start:, но по выходу из цикла нет обратной команды выравнивающей стек.
Цитата Сообщение от fdrv Посмотреть сообщение
но в этой подпрограмме используется регистр di как вначале так и походу самой подпрограммы, это не как не повлияет на то что потом в конце мы заносим туда результат ?
Я ничего по этому поводу сказать не могу. Код данной подпрограммы видимо засекречен.
1
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
26.04.2016, 03:46  [ТС] 15
Цитата Сообщение от Полный 30h Посмотреть сообщение
но по выходу из цикла нет обратной команды выравнивающей стек
Выравнивать стек ? А можно по подробнее, то есть мы занесли di и стек соответственно стал меньше, ну это хоть я понял, что если мы ложим что-то в корзиночку, то она становится менее вместительна. А по выходу из цикла, то есть после того как 8 кругов намотает, мы должны стек выравнять, что это значит ?
Или это к тому что у меня просто после loop Start не единой команды ? Если да, то такой вопрос, если допустим что у меня всё правильно и в массиве находятся все 8 результатов, то после loop Start можно просто END написать ? или я опять что-то элементарное не знаю ?
Простите за многословность

Код подпрограммы (не мой, хотя думаю Вы это и так поняли)
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
Start:          lea si,Y
lea di,Z
mov bx,[si+2]
mov si,[si]
mov dx,[di+2]
mov di,[di]
; Переход к подпрограммам сложения, вычитания
call    ADDSUBF
ADDSUBF PROC
 
; Сравнить знаки операндов и определить операцию
@addf:  mov al,bh   ; Сравнить
xor     al,dh   ; знаки операндов
jns     @addf1  ; Знаки операндов одинаковы
xor     dh,80h  ; Знаки различны,
jmp     @subf   ; перейти к вычитанию
;
; Проверить операнды на нуль
@addf1: mov ax,dx   ; Проверить на нуль
or  ax,di   ;   второй операнд
jz  @addf8  ;   Результат в BX:SI
mov ax,bx   ;   Проверить на нуль
or  ax,si   ;   первый операнд
jnz @addf2  ;   Оба операнда не нулевые
xchg    bx,dx   ;   Первый операнд равен нулю,
xchg    si,di   ;   сумма равна
jmp @addf8  ;   второму операнду
;
; Оба операнда не нулевые можно складывать.
@addf2: mov ah,bh   ; Сравнить общий знак в АН
shl bx,1    ; Восстановить скрытый бит
stc ; мантиссы первого операнда
rcr bl,1
shl dx,1    ; Восстановить скрытый бит
stc ; мантиссы второго операнда
rcr dl,1
; Сранить порядки, образовать разность порядков
cmp bh,dh   ; Сравнить порядки
jnc @addf3  ; Порядок числа в BX:SI больше
xchg    bx,dx   ; Передать большее число
xchg    si,di   ; в BX:SI
@addf3: sub bh,dh   ; Образовать разность порядков
jz  @addf6  ; Порядки одинаковы
cmp bh,24   ; Сравнить разность порядков с 24
jc  @addf5  ; Разность порядков меньше 24
jmp @addf7  ; Результата в BX:SI
; Необходимо сдвигать вправо мантиссу меньшего числа в DL:DI 
@addf5: shr     dl,1    ; Сдвинуть мантиссу
rcr di,1
inc dh      ; Увеличить меньший порядок
dec bh      ; Декремент разности порядков
jnz @addf5  ; Повторять сдвиг
mov bh,dh   ; Передать порядок в BH
;
; Можно складывать мантиссы. В регистре DH общий порядок 
@addf6: add     si,di   ; Сложить младшие части мантисс
adc     bl,dl   ; Сложить старшие части мантисс
jnc     @addf7  ; Нарушения нормализации влево нет
inc     dh      ; Скорректировать порядок
cmp     dh,255  ; Проверить переполнение
stc
jz  @addf8  ; Возникло пререполнение
rcr bl,1    ; Сдвинуть
rcr si,1    ; мантиссу вправо
mov bh,dh   ; Передать порядок в BH
;
; Форматировать результат
@addf7: add ah,ah   ; Знак во флаге переноса
rcr bh,1    ; Знак числа на месте
rcr ah,1    ; Младший бит порядка в АН7
or  ah,7fh  ; Образовать мантиссу
and bl,ah   ; Образовать второй байт числа
@addf8: ret
;
; Сохранить результат
lea di,Z
mov [di],si
mov [di+2],bx
jmp Start   ;ret
 
@subf:
; Проверить операнды на нуль
@subf1: mov ax,dx   ; Проверить на нуль
or  ax,di   ;   второй операнд
jz  @subfa  ;   Результат в BX:SI
mov ax,bx   ;   Проверить на нуль
or  ax,si   ;   первый операнд
jnz @subf2  ;   Оба операнда не нулевые
xchg    bx,dx   ;   Первый операнд равен нулю,
xchg    si,di   ;   разность равна
xor bh,80h  ;   второму операнду
jmp @subfa  ;   с измененным знаком
;
; Оба операнда не нулевые можно вычитать.
@subf2: mov ah,bh   ; Сохранить знак уменьшаемого
shl bx,1    ; Восстановить скрытый бит
stc ; мантиссы уменьшаемого
rcr bl,1
shl dx,1    ; Восстановить скрытый бит
stc ; мантиссы вычитаемого
rcr dl,1
; Проверить отношения между числами
cmp bh,dh   ;   Сравнить порядки
jnz @subf3  ;   Порядки не равны
cmp bl,dl   ;   Сранить старшие байты мантисс
jnz @subf3  ;   Они не равны
cmp si,di   ;   Сравнить младшие слова мантисс
jnz @subf3  ;   Они не равны
mov bx,0    ;   Числа равны,
mov si,0    ;   разность равна нулю
jmp @subfa
; Операнды не равны, необходимо вычитать.
@subf3: jnc @subf4  ; Уменьшаемое больше вычитаемого
xchg    bx,dx   ; Вычитаемое больше уменьшаемого,
xchg    si,di   ; обменять числа
xor ah,80h  ; Изменить знак результата
; Образовать разность порядков.
@subf4: sub bh,dh   ; Разность порядков в BH
jz  @subf7  ; Порядки одинаковы
cmp bh,24   ; Сравнить разность порядков с 24
jc  @subf6  ; Разность порядков меньше 24
jmp @subf9  ; Результата в BX:SI
; Необходимо сдвигать вправо мантиссу менишего числа в DL:DI 
@subf6: shr     dl,1    ; Сдвинуть мантиссу
rcr di,1
inc dh      ; Увеличить меньший порядок
dec bh      ; Декремент разности порядков
jnz @subf6  ; Повторять сдвиг
mov bh,dh   ; Передать общий порядок в BH
; Вычитание мантисс и образование результата.
@subf7: sub si,di   ; Вычесть мантиссы
sbb bl,dl
@subf8: or  bl,bl   ; Проверить старший бит мантиссы
js      @subf9  ;   Результат нормализован
dec     bh  ;   Декремент порядка
cmp     bh,255  ;   Проверить переполнение
stc ;   Установить флаг переноса
jz      @subfa  ;   Возникло антипереполнение
shl     si,1    ;   Сдвинуть мантиссу влево
rcl bl,1
jmp @subf8  ; Повторять до нормализации
; Форматировать результат
@subf9: add ah,ah   ; Знак во флаге переноса
rcr bh,1    ; Знак числа на месте
rcr ah,1    ; Младший бит порядка в АН7
or  ah,7fh  ; Образовать мантиссу
and bl,ah   ; Образовать второй байт числа
@subfa: ret
;
; Сохранить результат
mov ax,si   ; младшая часть ответа в ах
lodsw       ; младшая часть ответа из ах по адресу di, а di+2
mov ax,bx   ; старшая часть ответа в ах
lodsw       ; старшая часть ответа из ах по адресу di, а di+2
 
ADDSUBF ENDP
0
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
26.04.2016, 07:44 16
Цитата Сообщение от fdrv Посмотреть сообщение
Выравнивать стек ? А можно по подробнее, то есть мы занесли di и стек соответственно стал меньше, ну это хоть я понял, что если мы ложим что-то в корзиночку, то она становится менее вместительна. А по выходу из цикла, то есть после того как 8 кругов намотает, мы должны стек выравнять, что это значит ?
Смотрите что у вас получается структурно.
Assembler
1
2
3
4
5
6
7
8
9
; начало стек равен А
СТЕК -2 ; стек с А на В
НАЧАЛО ЦИКЛА
СТЕК -2 ; стек на В на С
СТЕК +2 ; стек с С на В
СТЕК +2 ; стек с В на А
СТЕК -2 ; стек с А на В
КОНЕЦ ЦИКЛА
; конец стек равен B
Т.е. перед входом в цикл вы "просадили"стек на два байта. Внутри цикла у вас стек то "опускается" то "поднимается" но в целом в рамках цикла всё что вы в него кладёте потом забираете. Но при выходе из цикла из за того что перед ним было одно лишнее СТЕК -2 у вас стек так и остаётся -2 байта. Беда вроде небольшая, но будь этот кусок кода подпрограммой, адрес возврата из оной оказался бы не на вершине стека а завален мусором оставшимся после работы цикла.
Если вы знакомы с тегами, то это примерно как один незакрытый тег.

И поэтому правильно бы было выравнять стек по окончании его использования в локальных кусках кода
Assembler
1
2
3
4
5
6
7
8
9
10
; начало стек равен А
СТЕК -2 ; стек с А на В
НАЧАЛО ЦИКЛА
СТЕК -2 ; стек на В на С
СТЕК +2 ; стек с С на В
СТЕК +2 ; стек с В на А
СТЕК -2 ; стек с А на В 
КОНЕЦ ЦИКЛА
СТЕК +2 ; стек с В на А? эта команда только для того что
; нужно только для того что бы вернуть стек на A
Цитата Сообщение от fdrv Посмотреть сообщение
Код подпрограммы (не мой, хотя думаю Вы это и так поняли)
Тем не менее он так же крив насчет стека. При входе в подпрограмму по команде call у вас в стек уходит адрес возврата. Который потом использует команда ret.
Однако по строчке 79
Assembler
1
jmp Start   ;ret
происходит выход из подпрограммы без очищения стека.
Кстати по коментарию этой строки видно, что изначально такого косяка не было.
1
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
26.04.2016, 17:36  [ТС] 17
то есть после цикла дописать, верно ?
Assembler
1
pop di
А теперь, как я получил все нужные результаты, то в конце прописать просто END ?
То есть(финальная версия)
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
TITLE Курсова робота
EXTERN MULFXX, MULFXY, ADDSUBFYZ, ADDSUBFYZ
 
STACK SEGMENT PARA STACKSTACK”
    DB  64 DUP (0)
STACK ENDS
 
DSEG SEGMENT PARA PUBLICDATA”
    X   DD  -2.0
DX  DD  0.5
    Y   DD  1 DUP (0)
    Z   DD  1 DUP (0)
    R   DD  8 DUP (0)
DSEG ENDS
 
CSEG SEGMENT PARA PUBLICCODE”
    ASSUME CS:CSEG, DS:DSEG, SS:STACK
 
MAIN PROC FAR
mov ax,DSEG
mov ds,ax
mov cx,8
lea     di,R
push di
Start:  push    cx
call    MULFXX
call    MULFYY
pop cx
pop di
call    ADDSUBFYZ
push di
call    ADDSUBFXDX
pop cx
loop    Start
pop di
END MAIN PROC FAR
Правильно ?
0
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
26.04.2016, 19:16 18
Цитата Сообщение от fdrv Посмотреть сообщение
то есть после цикла дописать, верно ?
Assembler
1
pop di
Верно, но не обязательно. Возможно у вас сложится ситуация что этот регистр будет занят, к тому же в данном случае загруженное в стек значение вам уже не нужно. Тогда вы просто можете сделать так
Assembler
1
 add sp,2
Цитата Сообщение от fdrv Посмотреть сообщение
А теперь, как я получил все нужные результаты, то в конце прописать просто END ?
Я слабо знаю этот диалект ассемблера на котором написана ваша программа. Поэтому утверждать не берусь.
Цитата Сообщение от fdrv Посмотреть сообщение
То есть(финальная версия)
Правильно ?
Незнаю. Ваш код представлен без кода подпрограмм, возможно там имеются ошибки. Однако даже если бы этот код мне был доступен, я не буду его проверять от и до. Это же ваша программа. Поэтому предоставлю вам самому заняться этим увлекательным делом. Если возникнут какие то вопросы - обращайтесь. постараюсь помочь.
1
fdrv
1 / 1 / 0
Регистрация: 11.02.2016
Сообщений: 20
26.04.2016, 22:54  [ТС] 19
Assembler
1
add sp,2
То есть этой командой я делаю что-то наподобие вот этого
Assembler
1
СТЕК +2 ; стек с В на А?
и регистр который был в стеке автоматически пропадает?
0
Полный 30h
Эксперт быдлокодинга
1533 / 446 / 61
Регистрация: 04.11.2010
Сообщений: 1,219
26.04.2016, 23:10 20
Цитата Сообщение от fdrv Посмотреть сообщение
и регистр который был в стеке автоматически пропадает?
В стеке и не было никакого регистра, это область памяти в которой сохраняются адреса возврата из подпрограмм и ЗНАЧЕНИЯ регистров. Вообще тема стека в формате "вопрос ответ" довольно не продуктивна. Думаю вам стоит прислушаться к совету Mikl___ и почитать систематизированное чтиво. Иначе у вас в голове не знания будут, а лоскутное одеяло.
1
26.04.2016, 23:10
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.04.2016, 23:10

Протабулировать функцию с шагом 0.1 (как работать с числами с плавающей запятой?)
Всем привет. Подскажите как организовать цикл на masm32. Нужно...

Написать программу вычисления значения функции при любом X
Написать программу вычисления значения функции при любом X. Написать на языке...

Обработка чисел с плавающей точкой: вычисление значения выражения
Нужно произвести некоторые арифметический действия над числами с плавающей...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru